RenderJobEntity.java
package org.fresnel.backend.persistence;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.EnumType;
import jakarta.persistence.Enumerated;
import jakarta.persistence.Id;
import jakarta.persistence.Index;
import jakarta.persistence.Lob;
import jakarta.persistence.PrePersist;
import jakarta.persistence.Table;
import java.time.Instant;
/**
* Persisted snapshot of a {@link org.fresnel.backend.jobs.RenderJob}.
*
* <p>Live progress for in-flight jobs is tracked in memory by
* {@link org.fresnel.backend.jobs.RenderJobService}; this entity is written when a
* job transitions to a terminal state ({@code COMPLETED} / {@code FAILED}) so the
* result survives JVM restarts and is visible to other instances.
*/
@Entity
@Table(name = "render_jobs", indexes = {
@Index(name = "idx_render_jobs_owner", columnList = "owner_id"),
@Index(name = "idx_render_jobs_created_at", columnList = "created_at")
})
public class RenderJobEntity {
public enum State { QUEUED, RUNNING, COMPLETED, FAILED }
@Id
@Column(name = "id", nullable = false, updatable = false, length = 64)
private String id;
@Column(name = "label", nullable = false, length = 64)
private String label;
@Enumerated(EnumType.STRING)
@Column(name = "state", nullable = false, length = 16)
private State state;
@Column(name = "progress", nullable = false)
private double progress;
@Column(name = "message", length = 1024)
private String message;
@Column(name = "error_message", length = 2048)
private String errorMessage;
@Column(name = "owner_id", length = 128)
private String ownerId;
@Lob
@Column(name = "result_png")
private byte[] resultPng;
@Column(name = "result_pixel_size_mm")
private Double resultPixelSizeMm;
@Column(name = "result_width_px")
private Integer resultWidthPx;
@Column(name = "result_height_px")
private Integer resultHeightPx;
@Column(name = "created_at", nullable = false, updatable = false)
private Instant createdAt;
@Column(name = "finished_at")
private Instant finishedAt;
public RenderJobEntity() {}
public RenderJobEntity(String id, String label, String ownerId) {
this.id = id;
this.label = label;
this.ownerId = ownerId;
this.state = State.QUEUED;
this.progress = 0.0;
this.message = "queued";
}
@PrePersist
void onCreate() { if (createdAt == null) createdAt = Instant.now(); }
public String getId() { return id; }
public String getLabel() { return label; }
public State getState() { return state; }
public void setState(State state) { this.state = state; }
public double getProgress() { return progress; }
public void setProgress(double progress) { this.progress = progress; }
public String getMessage() { return message; }
public void setMessage(String message) { this.message = message; }
public String getErrorMessage() { return errorMessage; }
public void setErrorMessage(String e) { this.errorMessage = e; }
public String getOwnerId() { return ownerId; }
public void setOwnerId(String ownerId) { this.ownerId = ownerId; }
public byte[] getResultPng() { return resultPng; }
public void setResultPng(byte[] resultPng) { this.resultPng = resultPng; }
public Double getResultPixelSizeMm() { return resultPixelSizeMm; }
public void setResultPixelSizeMm(Double v) { this.resultPixelSizeMm = v; }
public Integer getResultWidthPx() { return resultWidthPx; }
public void setResultWidthPx(Integer v) { this.resultWidthPx = v; }
public Integer getResultHeightPx() { return resultHeightPx; }
public void setResultHeightPx(Integer v) { this.resultHeightPx = v; }
public Instant getCreatedAt() { return createdAt; }
public Instant getFinishedAt() { return finishedAt; }
public void setFinishedAt(Instant finishedAt) { this.finishedAt = finishedAt; }
}