namespace OpenNest.Data; /// Where a server nest job is. Succeeded, Failed and Cancelled are final. public enum NestJobState { Queued, Running, Succeeded, Failed, Cancelled, } /// A whole-job nest the server's worker solves; see docs/server-nesting.md. public sealed class NestJobRecord { public Guid Id { get; set; } /// What the job is for, for people: usually the nest's name. public string Title { get; set; } = ""; public string EngineName { get; set; } = ""; public string SubmittedBy { get; set; } = ""; public NestJobState State { get; set; } /// Someone asked to stop the job while it ran; the worker stops at its next heartbeat. public bool CancelRequested { get; set; } public DateTime SubmittedAt { get; set; } public DateTime? StartedAt { get; set; } public DateTime? FinishedAt { get; set; } /// How many times a worker has taken the job; a worker that stops responding gives it back. public int Attempts { get; set; } /// Why the job failed; empty otherwise. public string Error { get; set; } = ""; /// Queued jobs ahead of this one (zero for a job that is not queued). public int QueuePosition { get; set; } public long PackageSize { get; set; } /// /// Bumped by every change a watcher shows (state, cancel request, progress, plan); the /// event stream's ids. Heartbeats leave it alone. /// public long Revision { get; set; } /// The the best plan so far was stored at; zero when there is none. public long PlanRevision { get; set; } /// /// The worker's latest progress report while the job runs (RemoteNestProgress JSON, /// opaque to the server); empty when there is none. /// public string Progress { get; set; } = ""; /// The server nest the job was sent from, when it had been saved there; null otherwise. public Guid? NestId { get; set; } /// Whether a succeeded job's result was kept or discarded; each happens at most once. public NestJobReview Review { get; set; } /// Who kept or discarded the result; empty while it is unreviewed. public string ReviewedBy { get; set; } = ""; public DateTime? ReviewedAt { get; set; } /// What a succeeded job's result holds, as its worker reported it; null for other jobs and older workers. public NestJobSummary? Summary { get; set; } public bool IsFinished => State is NestJobState.Succeeded or NestJobState.Failed or NestJobState.Cancelled; /// A succeeded job nobody has kept or discarded yet: its result can still be opened. public bool IsUnreviewed => State == NestJobState.Succeeded && Review == NestJobReview.None; } /// What became of a succeeded job's result. Kept and Discarded are final. public enum NestJobReview { None, Kept, Discarded, } /// A finished job's result in numbers, for job lists (the server never opens the result). public sealed class NestJobSummary { /// Parts placed, counting every copy of a repeated sheet. public int PartsPlaced { get; set; } public int PartsUnplaced { get; set; } /// Physical sheets, counting repeats. public int Sheets { get; set; } /// Part area over sheet area across every sheet, 0 to 1. public double Utilization { get; set; } } /// Which jobs GET /api/nest-jobs lists. public enum NestJobListFilter { All, /// Queued or running. Active, /// Succeeded, failed or cancelled. Finished, /// Succeeded and neither kept nor discarded. Unreviewed, } /// The description sent with a job's package. public sealed class NestJobSubmission { public string Title { get; set; } = ""; public string EngineName { get; set; } = ""; public string SubmittedBy { get; set; } = ""; /// The server nest the job is for, when it is saved there (helps a later review find it). public Guid? NestId { get; set; } } /// A desktop's Keep or Discard of a succeeded job's result. public sealed class NestJobReviewRequest { public string ReviewedBy { get; set; } = ""; } /// A worker's message about the job it holds. public sealed class NestJobWorkerMessage { public string WorkerId { get; set; } = ""; /// Why the job failed, for fail; ignored otherwise. public string Error { get; set; } = ""; } /// The server's answer to a worker's heartbeat. public sealed class NestJobHeartbeat { public bool CancelRequested { get; set; } } /// What a job's event stream (GET /api/nest-jobs/{id}/events) sent. public enum NestJobEventKind { /// The stream is open; nothing has necessarily changed. Open, /// The job itself: . The last one of a stream is final. Job, /// A new best plan so far: , sent before the job event that names it. Plan, /// The server no longer holds the job. Gone, } public sealed class NestJobEvent { public NestJobEventKind Kind { get; init; } /// The event id: the job's , or the plan's for a plan. public long Id { get; init; } public NestJobRecord? Job { get; init; } /// The worker's plan (RemoteNestPlan JSON, opaque to the server). public string Plan { get; init; } = ""; } /// Limits and timings both sides of server nesting share. public static class NestJobRules { /// Largest job package (drawings and job) the server accepts. public const long MaxPackageBytes = 256L * 1024 * 1024; /// Largest result the server accepts from a worker. public const long MaxResultBytes = 64L * 1024 * 1024; public const int MaxTextLength = 500; /// How long a running job stays with its worker without a heartbeat. public static readonly TimeSpan Lease = TimeSpan.FromMinutes(2); /// How often a worker reports; well inside . public static readonly TimeSpan HeartbeatInterval = TimeSpan.FromSeconds(20); /// Largest progress report a worker may store. public const long MaxProgressBytes = 64L * 1024; /// Largest best-plan-so-far a worker may store. public const long MaxPlanBytes = 16L * 1024 * 1024; /// /// How often a worker at most stores progress and plans (only the latest of each is sent), /// and checks for a cancel request between reports. /// public static readonly TimeSpan ProgressInterval = TimeSpan.FromSeconds(2); /// How often an idle event stream sends a comment, so a dropped connection shows. public static readonly TimeSpan StreamKeepAlive = TimeSpan.FromSeconds(15); /// A stream silent this long (several missed keep-alives) is treated as dropped. public static readonly TimeSpan StreamIdleTimeout = TimeSpan.FromSeconds(45); /// Workers that stop responding this many times fail the job instead of retrying it. public const int MaxAttempts = 3; /// /// Finished jobs, their packages and results are removed this long after they finish, /// unless the server is configured otherwise (OPENNEST_JOB_RETENTION_DAYS). /// public static readonly TimeSpan Retention = TimeSpan.FromDays(7); /// Most jobs one list request returns. public const int MaxListLimit = 500; }