@semiont/jobs 0.5.35 → 0.5.37
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +169 -4
- package/dist/index.js +510 -10
- package/dist/index.js.map +1 -1
- package/dist/worker-main.js +9 -7
- package/dist/worker-main.js.map +1 -1
- package/package.json +9 -8
package/dist/index.d.ts
CHANGED
|
@@ -290,7 +290,22 @@ interface JobQueue {
|
|
|
290
290
|
destroy(): void;
|
|
291
291
|
createJob(job: AnyJob): Promise<void>;
|
|
292
292
|
getJob(jobId: JobId): Promise<AnyJob | null>;
|
|
293
|
-
|
|
293
|
+
/**
|
|
294
|
+
* Atomically claim the NEXT pending job matching one of `types` — the ONE
|
|
295
|
+
* transition that makes this a queue rather than a state store
|
|
296
|
+
* (JOB-QUEUE-DRIVER P0; reshaped claim-by-TYPE in P2, while every worker
|
|
297
|
+
* is still ours). pending → running, `startedAt` stamped, progress empty.
|
|
298
|
+
* An announcement is a WAKE-UP, not a reservation: the claimed job may
|
|
299
|
+
* differ from any announced one, no ordering among matching pending jobs
|
|
300
|
+
* is promised, and an empty `types` accepts any type. Simultaneous claims
|
|
301
|
+
* admit one winner PER pending job; a claim that finds nothing is
|
|
302
|
+
* DECLINED (`none-available`), never an error.
|
|
303
|
+
*/
|
|
304
|
+
claimNextJob(types: string[]): Promise<{
|
|
305
|
+
job: AnyJob;
|
|
306
|
+
} | {
|
|
307
|
+
declined: 'none-available';
|
|
308
|
+
}>;
|
|
294
309
|
/** Move a running job to `complete`. Returns false if the job isn't running. */
|
|
295
310
|
completeJob(jobId: JobId, result: Record<string, unknown>): Promise<boolean>;
|
|
296
311
|
/**
|
|
@@ -398,10 +413,30 @@ declare class FsJobQueue implements JobQueue {
|
|
|
398
413
|
* Get a job by ID (searches all status directories)
|
|
399
414
|
*/
|
|
400
415
|
getJob(jobId: JobId): Promise<AnyJob | null>;
|
|
416
|
+
/**
|
|
417
|
+
* Serializes claims. This driver's atomicity is single-process by design,
|
|
418
|
+
* but `claimJob`'s contract must hold even against interleaved awaits in
|
|
419
|
+
* that one process — a read-check-write with await points in it can admit
|
|
420
|
+
* two winners without this chain (the TOCTOU the operation exists to kill).
|
|
421
|
+
*/
|
|
422
|
+
private claimChain;
|
|
423
|
+
claimNextJob(types: string[]): Promise<{
|
|
424
|
+
job: AnyJob;
|
|
425
|
+
} | {
|
|
426
|
+
declined: 'none-available';
|
|
427
|
+
}>;
|
|
428
|
+
private doClaimNext;
|
|
401
429
|
/**
|
|
402
430
|
* Update a job (atomic: delete old, write new)
|
|
403
431
|
*/
|
|
404
|
-
|
|
432
|
+
/**
|
|
433
|
+
* Cross-status move (or in-place rewrite): delete old slot, write new.
|
|
434
|
+
* Private — the interface exposes named transitions only (JOB-QUEUE-DRIVER
|
|
435
|
+
* P0); a generic public patch is trivial on files and impossible on an
|
|
436
|
+
* in-flight message, so no driver may offer one. Re-entering `pending`
|
|
437
|
+
* announces, which is how failJob's retry reaches a listening worker.
|
|
438
|
+
*/
|
|
439
|
+
private transition;
|
|
405
440
|
/**
|
|
406
441
|
* Move a running job to `complete`. Returns false (and changes
|
|
407
442
|
* nothing) if the job is missing or not running — which also makes
|
|
@@ -478,6 +513,136 @@ declare class FsJobQueue implements JobQueue {
|
|
|
478
513
|
}>;
|
|
479
514
|
}
|
|
480
515
|
|
|
516
|
+
/**
|
|
517
|
+
* JetStreamJobQueue — the JetStream driver behind the `JobQueue` interface
|
|
518
|
+
* (JOB-QUEUE-DRIVER P1, topology ruling M: gateway-mediated).
|
|
519
|
+
*
|
|
520
|
+
* Two primitives, one authority each:
|
|
521
|
+
*
|
|
522
|
+
* - **KV bucket `jobs`** is the AUTHORITATIVE operational state: one entry
|
|
523
|
+
* per job (`{ job, lastProgressAt }`), every transition a revision-CAS —
|
|
524
|
+
* which is what makes `claimJob` atomic: simultaneous claims race on one
|
|
525
|
+
* revision and exactly one update wins.
|
|
526
|
+
* - **Stream `JOBS`** (subjects `jobs.<category>.<type>`, work-queue
|
|
527
|
+
* retention) is the DELIVERY vehicle and redelivery timer. A delivered
|
|
528
|
+
* message is the lease this process holds for a job; `working()`
|
|
529
|
+
* heartbeats extend it, and a gateway that dies stops heartbeating, so
|
|
530
|
+
* `AckWait` redelivers the job to a live instance — gateway-death
|
|
531
|
+
* recovery, protocol-native.
|
|
532
|
+
*
|
|
533
|
+
* Worker-death recovery is NOT AckWait's job under the mediated topology
|
|
534
|
+
* (the gateway holding the lease is alive; the worker vanished): it is the
|
|
535
|
+
* `lastProgressAt` sweep (`recoverStaleRunningJobs`), the same contract the
|
|
536
|
+
* fs driver's mtime janitor implemented. The redelivery handler checks KV
|
|
537
|
+
* state, so the two recovery paths can never double-apply.
|
|
538
|
+
*
|
|
539
|
+
* Battery ownership (JOB-QUEUE-DRIVER P0): the retry decision belongs to
|
|
540
|
+
* `will-retry.ts` — `max_deliver` is unlimited and a deterministic failure
|
|
541
|
+
* is `term()`ed, so the backend's retry engine never becomes a second
|
|
542
|
+
* authority. The cursor merge belongs to `checkpoint-merge.ts`, shared with
|
|
543
|
+
* every driver.
|
|
544
|
+
*
|
|
545
|
+
* The boundary is the point: no NATS type, subject string, or delivery
|
|
546
|
+
* handle escapes this file.
|
|
547
|
+
*/
|
|
548
|
+
|
|
549
|
+
interface JetStreamJobQueueOptions {
|
|
550
|
+
/** NATS server address(es), e.g. "192.168.64.42:4222". */
|
|
551
|
+
servers: string | string[];
|
|
552
|
+
/** Worker presumed dead after this long without progress (default 30 min). */
|
|
553
|
+
staleRunningMs?: number;
|
|
554
|
+
/** Lease redelivery window when THIS process stops heartbeating (default 30 s). */
|
|
555
|
+
ackWaitMs?: number;
|
|
556
|
+
/** Re-announce + worker-death-sweep cadence (default 30 s; tests shrink it). */
|
|
557
|
+
tickMs?: number;
|
|
558
|
+
/** Reconnect on connection loss (default true; tests turn it off). */
|
|
559
|
+
reconnect?: boolean;
|
|
560
|
+
}
|
|
561
|
+
declare class JetStreamJobQueue implements JobQueue {
|
|
562
|
+
private readonly options;
|
|
563
|
+
private readonly logger;
|
|
564
|
+
private readonly eventBus?;
|
|
565
|
+
private nc;
|
|
566
|
+
private js;
|
|
567
|
+
private jsm;
|
|
568
|
+
private kv;
|
|
569
|
+
private iter;
|
|
570
|
+
/** Delivered messages this process holds — the lease, keyed by jobId,
|
|
571
|
+
* with the job's type so a by-type claim can walk them without a read. */
|
|
572
|
+
private readonly held;
|
|
573
|
+
private heartbeat;
|
|
574
|
+
private reconciling;
|
|
575
|
+
private tick;
|
|
576
|
+
private ticking;
|
|
577
|
+
private readonly lastProgressWrite;
|
|
578
|
+
private readonly staleRunningMs;
|
|
579
|
+
private readonly ackWaitMs;
|
|
580
|
+
private readonly tickMs;
|
|
581
|
+
constructor(options: JetStreamJobQueueOptions, logger: Logger, eventBus?: EventBus | undefined);
|
|
582
|
+
initialize(): Promise<void>;
|
|
583
|
+
destroy(): void;
|
|
584
|
+
/**
|
|
585
|
+
* A delivery is a job arriving at this gateway. What it means depends on
|
|
586
|
+
* the job's authoritative (KV) state:
|
|
587
|
+
* - pending → hold the lease, announce for a worker to claim;
|
|
588
|
+
* - running → hold silently (a claim raced ahead of the delivery, or a
|
|
589
|
+
* redelivery reached a fresh instance after a gateway death);
|
|
590
|
+
* - terminal → the work already concluded elsewhere; consume the message;
|
|
591
|
+
* - unknown → not ours to run; terminate it.
|
|
592
|
+
*/
|
|
593
|
+
private onDelivery;
|
|
594
|
+
/** Same wire shape as the fs driver: only jobs with a resourceId announce. */
|
|
595
|
+
private announce;
|
|
596
|
+
private read;
|
|
597
|
+
private write;
|
|
598
|
+
/**
|
|
599
|
+
* Read-transform-CAS with bounded retries: the transform sees the current
|
|
600
|
+
* job and returns the replacement (or null to stop). Every state
|
|
601
|
+
* transition goes through here, which is what makes each one atomic.
|
|
602
|
+
*/
|
|
603
|
+
private cas;
|
|
604
|
+
createJob(job: AnyJob): Promise<void>;
|
|
605
|
+
getJob(jobIdArg: JobId): Promise<AnyJob | null>;
|
|
606
|
+
claimNextJob(types: string[]): Promise<{
|
|
607
|
+
job: AnyJob;
|
|
608
|
+
} | {
|
|
609
|
+
declined: 'none-available';
|
|
610
|
+
}>;
|
|
611
|
+
/** CAS one pending job to running; null when someone else won it. */
|
|
612
|
+
private tryClaim;
|
|
613
|
+
completeJob(jobIdArg: JobId, result: Record<string, unknown>): Promise<boolean>;
|
|
614
|
+
failJob(jobIdArg: JobId, error: string, completedUnits?: string[], failureClass?: 'transient' | 'deterministic', unitCursors?: Record<string, UnitCursor>): Promise<'retried' | 'failed' | null>;
|
|
615
|
+
checkpointUnits(jobIdArg: JobId, completedUnits: string[], unitCursors?: Record<string, UnitCursor>): Promise<void>;
|
|
616
|
+
recordProgress(jobIdArg: JobId, progress: Record<string, unknown>): Promise<void>;
|
|
617
|
+
cancelPendingJobs(category: 'annotation' | 'generation'): Promise<number>;
|
|
618
|
+
cancelJob(jobIdArg: JobId): Promise<boolean>;
|
|
619
|
+
getStats(): Promise<{
|
|
620
|
+
pending: number;
|
|
621
|
+
running: number;
|
|
622
|
+
complete: number;
|
|
623
|
+
failed: number;
|
|
624
|
+
cancelled: number;
|
|
625
|
+
}>;
|
|
626
|
+
/**
|
|
627
|
+
* Worker-death recovery: the same contract the fs driver's mtime janitor
|
|
628
|
+
* implemented — a running job with no progress inside the stale window is
|
|
629
|
+
* retried or failed, checkpoint intact. Gateway-death recovery never comes
|
|
630
|
+
* through here; that is AckWait redelivery.
|
|
631
|
+
*/
|
|
632
|
+
recoverStaleRunningJobs(): Promise<number>;
|
|
633
|
+
/** The heartbeat body — extend live leases, settle concluded ones. */
|
|
634
|
+
private reconcileHeld;
|
|
635
|
+
/**
|
|
636
|
+
* Materialize the KV key list BEFORE touching any entry: interleaving
|
|
637
|
+
* `get`/`update` with an open `keys()` iterator on the same connection
|
|
638
|
+
* makes the iterator drop entries (measured: the second pending job
|
|
639
|
+
* vanished from every sweep until this was split into two passes).
|
|
640
|
+
*/
|
|
641
|
+
private allKeys;
|
|
642
|
+
/** Conclude this process's lease on a job, if it holds one. */
|
|
643
|
+
private settleLease;
|
|
644
|
+
}
|
|
645
|
+
|
|
481
646
|
/**
|
|
482
647
|
* Citation-token resolver (INLINE-CITATIONS P1).
|
|
483
648
|
*
|
|
@@ -865,5 +1030,5 @@ declare function generateResourceFromTopic(topic: string, entityTypes: string[],
|
|
|
865
1030
|
*/
|
|
866
1031
|
declare const STALL_THRESHOLD_MS: number;
|
|
867
1032
|
|
|
868
|
-
export { AnnotationDetection, FsJobQueue, STALL_THRESHOLD_MS, generateResourceFromTopic, isCancelledJob, isCompleteJob, isFailedJob, isPendingJob, isRunningJob, processAssessmentJob, processCommentJob, processGenerationJob, processHighlightJob, processReferenceJob, processTagJob };
|
|
869
|
-
export type { AnyJob, AssessmentDetectionJob, AssessmentDetectionParams, AssessmentDetectionProgress, CancelledJob, CommentDetectionJob, CommentDetectionParams, CommentDetectionProgress, CompleteJob, DetectionJob, DetectionParams, DetectionProgress, FailedJob, GenerationJob, GenerationResult, HighlightDetectionJob, HighlightDetectionParams, HighlightDetectionProgress, JobMetadata, JobQueryFilters, JobQueue, JobStatus, JobType, OnProgress, PendingJob, ProcessorResult, RunningJob, TagDetectionJob, TagDetectionParams, TagDetectionProgress, YieldProgress };
|
|
1033
|
+
export { AnnotationDetection, FsJobQueue, JetStreamJobQueue, STALL_THRESHOLD_MS, generateResourceFromTopic, isCancelledJob, isCompleteJob, isFailedJob, isPendingJob, isRunningJob, processAssessmentJob, processCommentJob, processGenerationJob, processHighlightJob, processReferenceJob, processTagJob };
|
|
1034
|
+
export type { AnyJob, AssessmentDetectionJob, AssessmentDetectionParams, AssessmentDetectionProgress, CancelledJob, CommentDetectionJob, CommentDetectionParams, CommentDetectionProgress, CompleteJob, DetectionJob, DetectionParams, DetectionProgress, FailedJob, GenerationJob, GenerationResult, HighlightDetectionJob, HighlightDetectionParams, HighlightDetectionProgress, JetStreamJobQueueOptions, JobMetadata, JobQueryFilters, JobQueue, JobStatus, JobType, OnProgress, PendingJob, ProcessorResult, RunningJob, TagDetectionJob, TagDetectionParams, TagDetectionProgress, YieldProgress };
|