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;
}