@happyvertical/smrt-jobs 0.55.4 → 0.55.7
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/AGENTS.md +20 -0
- package/README.md +32 -0
- package/dist/chunks/{runner-uZZwhrat.js → runner-C6_0QXo2.js} +919 -680
- package/dist/chunks/runner-C6_0QXo2.js.map +1 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/manifest.json +20 -1
- package/dist/mcp-task.d.ts.map +1 -1
- package/dist/runner.d.ts +2 -0
- package/dist/runner.d.ts.map +1 -1
- package/dist/runner.js +1 -1
- package/dist/smrt-job-event.d.ts +41 -0
- package/dist/smrt-job-event.d.ts.map +1 -1
- package/dist/smrt-job.d.ts.map +1 -1
- package/dist/smrt-knowledge.json +39 -6
- package/dist/terminal-outcome.d.ts +33 -0
- package/dist/terminal-outcome.d.ts.map +1 -0
- package/package.json +11 -11
- package/dist/chunks/runner-uZZwhrat.js.map +0 -1
package/dist/manifest.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"version": "1.0.0",
|
|
3
3
|
"timestamp": 0,
|
|
4
4
|
"packageName": "@happyvertical/smrt-jobs",
|
|
5
|
-
"packageVersion": "0.55.
|
|
5
|
+
"packageVersion": "0.55.7",
|
|
6
6
|
"objects": {
|
|
7
7
|
"@happyvertical/smrt-jobs:ForgeDelivery": {
|
|
8
8
|
"name": "forgedelivery",
|
|
@@ -612,6 +612,7 @@
|
|
|
612
612
|
"className": "ForgeDeliveryCollection",
|
|
613
613
|
"qualifiedName": "@happyvertical/smrt-jobs:ForgeDeliveryCollection",
|
|
614
614
|
"collection": "forgedeliveries",
|
|
615
|
+
"description": "Durable provider delivery inbox.",
|
|
615
616
|
"filePath": "/home/runner/work/smrt/smrt/packages/jobs/src/forge-projection.ts",
|
|
616
617
|
"packageName": "@happyvertical/smrt-jobs",
|
|
617
618
|
"fields": {},
|
|
@@ -1199,6 +1200,20 @@
|
|
|
1199
1200
|
"isStatic": false,
|
|
1200
1201
|
"isPublic": true
|
|
1201
1202
|
},
|
|
1203
|
+
"listTerminalOutcomes": {
|
|
1204
|
+
"name": "listTerminalOutcomes",
|
|
1205
|
+
"async": true,
|
|
1206
|
+
"parameters": [
|
|
1207
|
+
{
|
|
1208
|
+
"name": "options",
|
|
1209
|
+
"type": "ListTerminalOutcomesOptions",
|
|
1210
|
+
"optional": false
|
|
1211
|
+
}
|
|
1212
|
+
],
|
|
1213
|
+
"returnType": "Promise<SmrtJobTerminalOutcomePage>",
|
|
1214
|
+
"isStatic": false,
|
|
1215
|
+
"isPublic": true
|
|
1216
|
+
},
|
|
1202
1217
|
"cleanup": {
|
|
1203
1218
|
"name": "cleanup",
|
|
1204
1219
|
"async": true,
|
|
@@ -1336,6 +1351,7 @@
|
|
|
1336
1351
|
"className": "SmrtJob",
|
|
1337
1352
|
"qualifiedName": "@happyvertical/smrt-jobs:SmrtJob",
|
|
1338
1353
|
"collection": "smrtjobs",
|
|
1354
|
+
"description": "Persistent job record stored in the _smrt_jobs system table.",
|
|
1339
1355
|
"filePath": "/home/runner/work/smrt/smrt/packages/jobs/src/smrt-job.ts",
|
|
1340
1356
|
"packageName": "@happyvertical/smrt-jobs",
|
|
1341
1357
|
"fields": {
|
|
@@ -1899,6 +1915,7 @@
|
|
|
1899
1915
|
"className": "SmrtJobCollection",
|
|
1900
1916
|
"qualifiedName": "@happyvertical/smrt-jobs:SmrtJobCollection",
|
|
1901
1917
|
"collection": "smrtjobs",
|
|
1918
|
+
"description": "Collection for managing SmrtJob objects",
|
|
1902
1919
|
"filePath": "/home/runner/work/smrt/smrt/packages/jobs/src/smrt-job.ts",
|
|
1903
1920
|
"packageName": "@happyvertical/smrt-jobs",
|
|
1904
1921
|
"fields": {},
|
|
@@ -2276,6 +2293,7 @@
|
|
|
2276
2293
|
"className": "SmrtWorker",
|
|
2277
2294
|
"qualifiedName": "@happyvertical/smrt-jobs:SmrtWorker",
|
|
2278
2295
|
"collection": "smrtworkers",
|
|
2296
|
+
"description": "Liveness record for a single TaskRunner / ScheduleRunner incarnation, stored in the _smrt_workers system table.",
|
|
2279
2297
|
"filePath": "/home/runner/work/smrt/smrt/packages/jobs/src/smrt-worker.ts",
|
|
2280
2298
|
"packageName": "@happyvertical/smrt-jobs",
|
|
2281
2299
|
"fields": {
|
|
@@ -2453,6 +2471,7 @@
|
|
|
2453
2471
|
"className": "SmrtWorkerCollection",
|
|
2454
2472
|
"qualifiedName": "@happyvertical/smrt-jobs:SmrtWorkerCollection",
|
|
2455
2473
|
"collection": "smrtworkers",
|
|
2474
|
+
"description": "Collection for managing _smrt_workers liveness rows.",
|
|
2456
2475
|
"filePath": "/home/runner/work/smrt/smrt/packages/jobs/src/smrt-worker.ts",
|
|
2457
2476
|
"packageName": "@happyvertical/smrt-jobs",
|
|
2458
2477
|
"fields": {},
|
package/dist/mcp-task.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mcp-task.d.ts","sourceRoot":"","sources":["../src/mcp-task.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AAE5D,OAAO,EAAE,KAAK,OAAO,EAAqB,MAAM,eAAe,CAAC;
|
|
1
|
+
{"version":3,"file":"mcp-task.d.ts","sourceRoot":"","sources":["../src/mcp-task.ts"],"names":[],"mappings":"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"}
|
package/dist/runner.d.ts
CHANGED
|
@@ -225,6 +225,8 @@ export declare class TaskRunner extends EventEmitter {
|
|
|
225
225
|
private assertMcpTaskAuthority;
|
|
226
226
|
private createExecutionContext;
|
|
227
227
|
private appendJobEvent;
|
|
228
|
+
private emitPersistedJobEvent;
|
|
229
|
+
private emitTelemetryError;
|
|
228
230
|
/**
|
|
229
231
|
* Whether the `_smrt_workers` table exists. Cached once positive — the table
|
|
230
232
|
* never disappears mid-run, so this avoids a probe query on every poll.
|
package/dist/runner.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"runner.d.ts","sourceRoot":"","sources":["../src/runner.ts"],"names":[],"mappings":"AAEA,OAAO,wBAAwB,CAAC;AAGhC,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAY3C,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AAI5D,OAAO,EAGL,KAAK,mBAAmB,EAEzB,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EAGL,KAAK,gBAAgB,EAItB,MAAM,eAAe,CAAC;AACvB,OAAO,EAEL,KAAK,uBAAuB,EAE7B,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAEL,KAAK,OAAO,EAEb,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,KAAK,YAAY,EAA0B,MAAM,qBAAqB,CAAC;
|
|
1
|
+
{"version":3,"file":"runner.d.ts","sourceRoot":"","sources":["../src/runner.ts"],"names":[],"mappings":"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"}
|
package/dist/runner.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { a as isRunnerExecutionContext, i as getActiveJobExecutionContext, n as TaskRunner, r as createTaskRunner, t as JobTimeoutError } from "./chunks/runner-
|
|
1
|
+
import { a as isRunnerExecutionContext, i as getActiveJobExecutionContext, n as TaskRunner, r as createTaskRunner, t as JobTimeoutError } from "./chunks/runner-C6_0QXo2.js";
|
|
2
2
|
export { JobTimeoutError, TaskRunner, TaskRunner as default, createTaskRunner, getActiveJobExecutionContext, isRunnerExecutionContext };
|
package/dist/smrt-job-event.d.ts
CHANGED
|
@@ -24,6 +24,38 @@ export interface ListJobEventsOptions {
|
|
|
24
24
|
afterId?: string;
|
|
25
25
|
cursor?: string | JobEventCursor;
|
|
26
26
|
}
|
|
27
|
+
export type SmrtJobTerminalStatus = 'completed' | 'failed' | 'cancelled';
|
|
28
|
+
export interface SmrtJobTerminalOutcome {
|
|
29
|
+
eventId: string;
|
|
30
|
+
jobId: string;
|
|
31
|
+
tenantId: string | null;
|
|
32
|
+
status: SmrtJobTerminalStatus;
|
|
33
|
+
queue: string;
|
|
34
|
+
objectType: string;
|
|
35
|
+
method: string;
|
|
36
|
+
attempts: number;
|
|
37
|
+
failureKind?: 'execution' | 'timeout' | 'stale-recovery';
|
|
38
|
+
completedAt: string;
|
|
39
|
+
cursor: string;
|
|
40
|
+
}
|
|
41
|
+
export interface ListTerminalOutcomesOptions {
|
|
42
|
+
/** Explicit tenant boundary. Pass null only for global jobs. */
|
|
43
|
+
tenantId: string | null;
|
|
44
|
+
limit?: number;
|
|
45
|
+
since?: string | Date;
|
|
46
|
+
before?: string | JobEventCursor;
|
|
47
|
+
statuses?: SmrtJobTerminalStatus[];
|
|
48
|
+
queues?: string[];
|
|
49
|
+
objectTypes?: string[];
|
|
50
|
+
methods?: string[];
|
|
51
|
+
}
|
|
52
|
+
export interface SmrtJobTerminalOutcomePage {
|
|
53
|
+
outcomes: SmrtJobTerminalOutcome[];
|
|
54
|
+
limit: number;
|
|
55
|
+
candidateLimit: 1000;
|
|
56
|
+
truncated: boolean;
|
|
57
|
+
nextCursor: string | null;
|
|
58
|
+
}
|
|
27
59
|
export declare class SmrtJobEvent extends SmrtObject {
|
|
28
60
|
tenantId: string | null | undefined;
|
|
29
61
|
jobId: string;
|
|
@@ -47,6 +79,15 @@ export declare class SmrtJobEventCollection extends SmrtCollection<SmrtJobEvent>
|
|
|
47
79
|
latestProgressByJobIds(jobIds: string[], options?: {
|
|
48
80
|
tenantId?: string | null;
|
|
49
81
|
}): Promise<Map<string, SmrtJobEvent>>;
|
|
82
|
+
/**
|
|
83
|
+
* Read the newest safe, authoritative terminal outcomes for one tenant.
|
|
84
|
+
*
|
|
85
|
+
* The projection is built only from versioned terminal events written in the
|
|
86
|
+
* same transaction as their job status. It never returns job arguments,
|
|
87
|
+
* object ids, results, raw errors, or stack traces. Events follow the package
|
|
88
|
+
* retention policy (30 days by default), independently of job-row cleanup.
|
|
89
|
+
*/
|
|
90
|
+
listTerminalOutcomes(options: ListTerminalOutcomesOptions): Promise<SmrtJobTerminalOutcomePage>;
|
|
50
91
|
private addTenantPredicate;
|
|
51
92
|
/**
|
|
52
93
|
* Delete job events recorded before a cutoff (#2375).
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"smrt-job-event.d.ts","sourceRoot":"","sources":["../src/smrt-job-event.ts"],"names":[],"mappings":"AAEA,OAAO,wBAAwB,CAAC;AAEhC,OAAO,
|
|
1
|
+
{"version":3,"file":"smrt-job-event.d.ts","sourceRoot":"","sources":["../src/smrt-job-event.ts"],"names":[],"mappings":"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"}
|
package/dist/smrt-job.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"smrt-job.d.ts","sourceRoot":"","sources":["../src/smrt-job.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAC;AAC/D,OAAO,EAIL,cAAc,EACd,UAAU,EAEX,MAAM,0BAA0B,CAAC;
|
|
1
|
+
{"version":3,"file":"smrt-job.d.ts","sourceRoot":"","sources":["../src/smrt-job.ts"],"names":[],"mappings":"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"}
|
package/dist/smrt-knowledge.json
CHANGED
|
@@ -3,13 +3,13 @@
|
|
|
3
3
|
"sensitiveFieldsExcluded": true,
|
|
4
4
|
"generatedAt": "1970-01-01T00:00:00.000Z",
|
|
5
5
|
"packageName": "@happyvertical/smrt-jobs",
|
|
6
|
-
"packageVersion": "0.55.
|
|
6
|
+
"packageVersion": "0.55.7",
|
|
7
7
|
"sourceManifestPath": "dist/manifest.json",
|
|
8
8
|
"agentDocPath": "AGENTS.md",
|
|
9
9
|
"sourceHashes": {
|
|
10
|
-
"manifest": "
|
|
11
|
-
"packageJson": "
|
|
12
|
-
"agents": "
|
|
10
|
+
"manifest": "90675030e564677710baa6e1ec0dbabda34ba1764c00232462f029fd23c85365",
|
|
11
|
+
"packageJson": "42beeaeb16693e27cefa227359c6b7c08e2719046676502d34a101a832b970de",
|
|
12
|
+
"agents": "2421cfb461cef4c890027678493aba1def8e21fced0daa598bc48ec60d2535fb"
|
|
13
13
|
},
|
|
14
14
|
"exports": [
|
|
15
15
|
".",
|
|
@@ -270,6 +270,7 @@
|
|
|
270
270
|
"name": "ForgeDeliveryCollection",
|
|
271
271
|
"qualifiedName": "@happyvertical/smrt-jobs:ForgeDeliveryCollection",
|
|
272
272
|
"collection": "forgedeliveries",
|
|
273
|
+
"description": "Durable provider delivery inbox.",
|
|
273
274
|
"tableName": "_smrt_forge_deliveries",
|
|
274
275
|
"packageName": "@happyvertical/smrt-jobs",
|
|
275
276
|
"extends": "SmrtCollection",
|
|
@@ -479,7 +480,8 @@
|
|
|
479
480
|
"initialize",
|
|
480
481
|
"latestProgressByJobIds",
|
|
481
482
|
"listByJob",
|
|
482
|
-
"listSinceCursor"
|
|
483
|
+
"listSinceCursor",
|
|
484
|
+
"listTerminalOutcomes"
|
|
483
485
|
],
|
|
484
486
|
"methodSignatures": [
|
|
485
487
|
{
|
|
@@ -528,6 +530,14 @@
|
|
|
528
530
|
"options?: any"
|
|
529
531
|
],
|
|
530
532
|
"returns": "Promise<SmrtJobEvent[]>"
|
|
533
|
+
},
|
|
534
|
+
{
|
|
535
|
+
"name": "listTerminalOutcomes",
|
|
536
|
+
"async": true,
|
|
537
|
+
"params": [
|
|
538
|
+
"options: ListTerminalOutcomesOptions"
|
|
539
|
+
],
|
|
540
|
+
"returns": "Promise<SmrtJobTerminalOutcomePage>"
|
|
531
541
|
}
|
|
532
542
|
],
|
|
533
543
|
"surfaces": [
|
|
@@ -555,6 +565,12 @@
|
|
|
555
565
|
"operation": "latestProgressByJobIds",
|
|
556
566
|
"objectName": "@happyvertical/smrt-jobs:SmrtJobEventCollection"
|
|
557
567
|
},
|
|
568
|
+
{
|
|
569
|
+
"kind": "cli",
|
|
570
|
+
"name": "smrtjobeventcollection_listTerminalOutcomes",
|
|
571
|
+
"operation": "listTerminalOutcomes",
|
|
572
|
+
"objectName": "@happyvertical/smrt-jobs:SmrtJobEventCollection"
|
|
573
|
+
},
|
|
558
574
|
{
|
|
559
575
|
"kind": "cli",
|
|
560
576
|
"name": "smrtjobeventcollection_cleanup",
|
|
@@ -604,6 +620,13 @@
|
|
|
604
620
|
"code": "api-disabled",
|
|
605
621
|
"reason": "api is disabled",
|
|
606
622
|
"objectName": "@happyvertical/smrt-jobs:SmrtJobEventCollection"
|
|
623
|
+
},
|
|
624
|
+
{
|
|
625
|
+
"kind": "api",
|
|
626
|
+
"operation": "listTerminalOutcomes",
|
|
627
|
+
"code": "api-disabled",
|
|
628
|
+
"reason": "api is disabled",
|
|
629
|
+
"objectName": "@happyvertical/smrt-jobs:SmrtJobEventCollection"
|
|
607
630
|
}
|
|
608
631
|
],
|
|
609
632
|
"relationshipFeatures": [
|
|
@@ -616,6 +639,7 @@
|
|
|
616
639
|
"name": "SmrtJob",
|
|
617
640
|
"qualifiedName": "@happyvertical/smrt-jobs:SmrtJob",
|
|
618
641
|
"collection": "smrtjobs",
|
|
642
|
+
"description": "Persistent job record stored in the _smrt_jobs system table.",
|
|
619
643
|
"tableName": "_smrt_jobs",
|
|
620
644
|
"packageName": "@happyvertical/smrt-jobs",
|
|
621
645
|
"extends": "SmrtObject",
|
|
@@ -882,6 +906,7 @@
|
|
|
882
906
|
"name": "SmrtJobCollection",
|
|
883
907
|
"qualifiedName": "@happyvertical/smrt-jobs:SmrtJobCollection",
|
|
884
908
|
"collection": "smrtjobs",
|
|
909
|
+
"description": "Collection for managing SmrtJob objects",
|
|
885
910
|
"tableName": "_smrt_jobs",
|
|
886
911
|
"packageName": "@happyvertical/smrt-jobs",
|
|
887
912
|
"extends": "SmrtCollection",
|
|
@@ -1074,6 +1099,7 @@
|
|
|
1074
1099
|
"name": "SmrtWorker",
|
|
1075
1100
|
"qualifiedName": "@happyvertical/smrt-jobs:SmrtWorker",
|
|
1076
1101
|
"collection": "smrtworkers",
|
|
1102
|
+
"description": "Liveness record for a single TaskRunner / ScheduleRunner incarnation, stored in the _smrt_workers system table.",
|
|
1077
1103
|
"tableName": "_smrt_workers",
|
|
1078
1104
|
"packageName": "@happyvertical/smrt-jobs",
|
|
1079
1105
|
"extends": "SmrtObject",
|
|
@@ -1138,6 +1164,7 @@
|
|
|
1138
1164
|
"name": "SmrtWorkerCollection",
|
|
1139
1165
|
"qualifiedName": "@happyvertical/smrt-jobs:SmrtWorkerCollection",
|
|
1140
1166
|
"collection": "smrtworkers",
|
|
1167
|
+
"description": "Collection for managing _smrt_workers liveness rows.",
|
|
1141
1168
|
"tableName": "_smrt_workers",
|
|
1142
1169
|
"packageName": "@happyvertical/smrt-jobs",
|
|
1143
1170
|
"extends": "SmrtCollection",
|
|
@@ -1298,6 +1325,12 @@
|
|
|
1298
1325
|
"operation": "latestProgressByJobIds",
|
|
1299
1326
|
"objectName": "@happyvertical/smrt-jobs:SmrtJobEventCollection"
|
|
1300
1327
|
},
|
|
1328
|
+
{
|
|
1329
|
+
"kind": "cli",
|
|
1330
|
+
"name": "smrtjobeventcollection_listTerminalOutcomes",
|
|
1331
|
+
"operation": "listTerminalOutcomes",
|
|
1332
|
+
"objectName": "@happyvertical/smrt-jobs:SmrtJobEventCollection"
|
|
1333
|
+
},
|
|
1301
1334
|
{
|
|
1302
1335
|
"kind": "cli",
|
|
1303
1336
|
"name": "smrtjobeventcollection_cleanup",
|
|
@@ -1380,5 +1413,5 @@
|
|
|
1380
1413
|
"polymorphicAssociations": 0,
|
|
1381
1414
|
"uuidColumns": 18
|
|
1382
1415
|
},
|
|
1383
|
-
"agentDoc": "# @happyvertical/smrt-jobs\n\nBackground job execution with persistent queue, scheduling, and fluent builder API.\n\n## Architecture\n\n```\nSmrtObject.bg('method') → SmrtJob (in _smrt_jobs) → TaskRunner picks up → executes via ObjectRegistry\nAgentSchedule (cron) → ScheduleRunner creates SmrtJob → TaskRunner executes → ScheduleRunner updates\nTaskRunner.start() → SmrtWorker lease (in _smrt_workers) → recovery keys on worker liveness, not heartbeat\n```\n\n## SmrtJob\n\nPersistent in `_smrt_jobs`. Fields: `queue` (default), `objectType`, `objectId`, `method`, `args`, `runAt`, `priority` (higher=sooner), `status`, `attempts`/`maxAttempts`, `timeout` (default 5min), `retryStrategy`, `workerId` (the owning runner's incarnation key), `workerHeartbeat` (telemetry only — no longer gates recovery).\n\nStatus: `pending → running → completed/failed/cancelled`.\n\n## TaskRunner\n\nPolling-based execution engine. Config: `concurrency` (5), `pollInterval` (1s), `idlePollInterval` (defaults to 20× `pollInterval`), `heartbeatInterval` (30s, telemetry only), `leaseTtlMs` (30s), `leaseTickMs` (10s), `shutdownTimeout` (30s). Empty claims back off exponentially to `idlePollInterval`; any claimed work, capacity pressure, or poll error resets to `pollInterval`. Every delay is capped at the effective worker lease TTL, including an oversized base interval; recovery sweep spacing stays TTL-bounded (plus query/event-loop time). Polling intervals must be finite positive milliseconds within the Node timer range.\n\n1. `start()` calls `assertReady()` (fail fast if `_smrt_workers` unmigrated), registers a seeded `SmrtWorker` lease, and adds its worker key to the process-global live set — all **before** polling\n2. Polls `claimReady()` to atomically claim at most the free slots (`concurrency - active`) of pending jobs (`runAt <= NOW`, ordered by `priority DESC, runAt ASC, created_at ASC, id ASC`). On PostgreSQL the candidates come from a `MATERIALIZED` CTE joined to the UPDATE; never claim with `WHERE id IN (SELECT … LIMIT n FOR UPDATE SKIP LOCKED)` — a nested-loop semi join rescans it per outer row and takes the whole backlog (#3145). The runner also never starts more than the free slots and returns any surplus claim to `pending` with its attempt restored\n3. Claim sets `status='running'`, `workerId=<incarnation key>`, heartbeat/start timestamps, and increments `attempts`\n4. Resolves class via `ObjectRegistry.getClass(objectType)`. Object-bound jobs\n pass `objectId` to the constructor and let `initialize()` perform the single\n canonical hydration. Runner-owned `db`, `id`, and hydration options cannot be\n overridden by agent config; missing persisted targets fail before method\n dispatch. Jobs without `objectId` construct a static-like instance\n5. **Internal args**: `_agentConfig` and `_scheduleId` stripped from args before calling method\n6. Calls the requested method on the initialized instance\n7. Terminal/retry writes are **conditional** (`WHERE worker_id=? AND status='running'`) so a recovered row is never stomped\n8. Retry: uses strategy from `@happyvertical/jobs`, schedules future `runAt` on failure\n9. Events: `job:started`, `job:completed`, `job:failed`, `job:retrying`, `runner:started/stopped`\n\nA rejection from `processJob` can never escape the poll loop: the caller attaches `.catch(e => emit('runner:error', e))` and the error path (`handleJobError`) is itself try/caught, so a failure-path write that rejects is surfaced as a `runner:error` event instead of crashing the worker with an unhandled rejection.\n\n## Timeouts & at-least-once\n\n**Execution is at-least-once, never exactly-once. Make job handlers idempotent.**\n\nA job `timeout` only races the handler's promise — JavaScript cannot preempt an already-running function. When a handler exceeds its timeout:\n\n- The job is **failed terminally and NOT auto-retried** (a timed-out handler is still running; re-queueing it would let a second worker run a concurrent duplicate). This narrows, but does not eliminate, the overlap window — the orphaned handler keeps running until it returns on its own.\n- The orphaned handler's eventual terminal write is dropped by the ownership guard (`WHERE worker_id=? AND status='running'`), so it cannot resurrect the failed row — but any **side effects** it performs (external API calls, writes to other tables) still happen.\n- Key any non-idempotent work by `context.job.jobId` or a caller-supplied idempotency key.\n\n`timeoutBehavior` (persisted + shown in the UI) is now honored:\n\n- **`'fail'`** (default): on timeout the job fails (and, per above, is not retried).\n- **`'warn'`**: the handler is **not** raced against the timeout — it runs to completion, and at the deadline the runner logs a warning and emits a `timeout-warning` job event. A slow-but-successful handler still completes successfully.\n- **`'kill'`**: treated identically to `'fail'`. In-process JavaScript has no thread interruption, so a true \"kill\" of a running handler is impossible without worker isolation; this value is honest that it only fails the job row, it does not stop the handler. Prefer `'fail'` unless you specifically want the label.\n\n## Worker liveness & recovery (#1474)\n\nRecovery keys on **worker-process liveness**, never per-job heartbeat freshness (a CPU-bound synchronous handler used to starve the heartbeat and false-recover its own running jobs).\n\n- **`SmrtWorker` / `_smrt_workers`**: one lease row per runner *incarnation* (`workerId` is per-incarnation unique via `createWorkerKey`, so a restart never looks like it still owns the previous crash's jobs). `leaseExpiresAt` is a `datetime` (an integer epoch-ms column overflows `int4`/`INT32` on Postgres/DuckDB). Stage 1 writes/compares it against the host clock — the same approach the old heartbeat recovery used, so it's no more skew-sensitive than the code it replaced.\n- **Process-global live set** (`worker-liveness.ts`, `globalThis.__smrtLiveWorkers`): checked synchronously, so it can't be starved by a blocked loop. Covers all same-process topologies.\n- **Off-loop ticker** (`worker-liveness-ticker.ts` + `worker-liveness-thread.ts`): for engines a second connection can reach (Postgres, file-backed SQLite — `offLoopEligible()`), `start()` spawns a `node:worker_threads` ticker that renews the lease on its own thread, so a CPU-bound synchronous handler on the main loop can't starve it. In-memory SQLite / DuckDB, a thread-spawn failure, a start-handshake timeout, or the thread dying mid-run all fall back to main-loop renewal; the in-process live set keeps same-process correct regardless. The worker entry is a separate build entry resolved via `import.meta.resolve('@happyvertical/smrt-jobs/worker-liveness-thread')`.\n- **Recovery rule** (both runners): a `running` job is orphaned iff its worker is *not alive* = not in the live set **and** no fresh `_smrt_workers` lease. The live set takes precedence over a stale lease. TaskRunner also never recovers a job in its own `activeJobs`. If `_smrt_workers` is absent, recovery skips lease checks (never mass-recovers). Recovery is swept at most once per lease tick, and terminal/recovery writes use `RETURNING id` (not `rowCount`, which DuckDB/JSON adapters always report as ≥1).\n- **Lease clock**: the lease is compared against the host clock (same as the old heartbeat; fine with NTP + a 30s TTL). A dead process stops renewing and the lease expires within its TTL — that is how recovery detects death. (Instant cross-process detection via Postgres session advisory locks was prototyped on `@happyvertical/sql`'s `acquireSession()` but deferred — treating a free lock as proof-of-death false-recovers any worker legitimately in main-loop fallback mode.)\n\n## ScheduleRunner\n\nPolls `_smrt_agent_schedules` every 60s for due entries. Creates SmrtJob with `queue='agents'`, `priority=75`. Wires to TaskRunner events for completion/failure tracking. Slot reconciliation keys on worker liveness (it has no in-process active-job set, so the lease/live-set is its whole mechanism).\n\nThe job is enqueued **before** `next_run` is advanced and `running_count` is incremented: a transient enqueue failure (tenant-cap hit, DB blip) therefore leaves `next_run` and `status='active'` untouched so the same due slot is retried on the next poll, rather than losing the slot and disabling the schedule.\n\n`next_run` is always recomputed from *now*, never from the previous `next_run` — this is **fire-once-forward**: runs that came due while the runner was down are not caught up, only the next future occurrence fires. There is no missed-run backfill.\n\nCustom cron parser: 5-field (minute hour dom month dow). `*`, ranges, lists, steps supported. **Not timezone-aware**: cron fields are matched against the **server's local time** (the parser uses `getHours`/`getDate`/`getDay`/… local accessors), so `0 0 * * *` fires at local midnight on the host, not at 00:00 UTC. Deploy runners in a known timezone (e.g. `TZ=UTC`) for UTC semantics. A per-schedule timezone option is a possible future enhancement.\n\n## JobBuilder — Fluent API\n\n```typescript\nconst handle = await doc.background('analyze', { detailed: true })\n .delay('5m').priority('high').retries(5).queue('analysis').timeout(600000).enqueue();\n\nawait handle.wait({ timeout: 60000, pollInterval: 100 }); // polling-based\n```\n\n## Durable forge projections\n\n`ForgeDeliveryCollection` owns the provider-neutral delivery inbox in\n`_smrt_forge_deliveries`; `ForgeProjectionRuntime` owns lease/retry/dead-letter\ntransitions and monotonic checkpoints in\n`_smrt_forge_projection_checkpoints`.\n\n- Inbox identity is `(tenant_id, provider, delivery_id)`.\n- Runtimes sharing the inbox pass `providers` (to `ForgeProjectionRuntime` or\n `claimReady`) so each claims and dead-letters only its own deliveries;\n unfiltered claims take every provider (smrt-commerce billing uses\n `<name>-billing:<sellerTenantId>`, #3060).\n- `claimReady` leases exactly one delivery; PostgreSQL uses the same\n `MATERIALIZED` CTE claim as jobs (#3105).\n- Tenant-facing accept/replay requires ambient tenant context. Worker claim is\n cross-tenant, then runtime restores the captured context before observation.\n Reads in the accept path go through the tenant-scoped collection (`list()`),\n so intake works under the interceptor's `rawQueryPolicy: 'throw'` production\n default without a bypass (#3100); keep new tenant-facing reads that way.\n- Projection callbacks must write through `ForgeProjectionContext.db`; the\n application projection, checkpoint, and inbox completion share one\n transaction.\n- Observation identity is tracker-independent\n `(projection, subjectKey, version)`. Equal or older versions are acknowledged\n without reapplying.\n- Lease-token conditions guard every terminal/failure write. Expired final\n attempts become replayable `dead_letter` rows, and persisted errors are\n redacted.\n- Generated API, CLI, and MCP surfaces stay disabled; replay is an explicit\n tenant-scoped operator action.\n\n`bg()` is shorthand: `await doc.bg('analyze', args)` → enqueues immediately, returns JobHandle.\n\n## withBackgroundJobs(Class)\n\nMixin that adds `bg()` and `background()` to any SmrtObject. Uses WeakMap for collection caching per DB instance.\n\n## Background policy (`background-policy.ts`, S5 audit #1402)\n\nThree opt-in guards, all owned **and enforced here**. Other packages apply the\neligibility marker (`reports`, `support`, `fields`, the MCP conformance\nfixture), but nothing outside this package acts on it — `TaskRunner` is the only\nreader. In particular `@happyvertical/smrt-agents` has no reference to any of\nthese guards and does not depend on this package, so marking a method does not\nchange what the agents runtime will dispatch.\n\n- `clampRetries()` / `MAX_JOB_RETRIES` (25): a requested retry count above the\n ceiling is clamped, not rejected.\n- `assertWithinTenantCreationCap(tenantId, current, cap)` /\n `DEFAULT_TENANT_JOB_CAP` (10 000): throws `TenantJobCapExceededError` when the\n tenant's count of non-terminal jobs is already at or above the cap. Applied in\n `SmrtJobCollection.enqueueJob()` (`smrt-job.ts`), which is the single choke\n point for the builder and `ScheduleRunner`; a `null` tenant and a `cap <= 0`\n both skip the check. Deliberately not serialized — concurrent enqueues can\n overshoot by the number of in-flight creators (see the method's own comment).\n- `@backgroundEligible()` / `markBackgroundEligible()` /\n `isBackgroundEligibleMethod()`: an allowlist of methods `TaskRunner` may\n dispatch, enforced at exactly one call site (`runner.ts`, after the method\n lookup). **Restrictive, not enabling** — a class with no marked methods allows\n any of its methods, and the first mark makes the set exhaustive, excluding\n every sibling method. Adding the decorator to one method of an existing class\n is therefore a behaviour change for the rest of it.\n\n## Retention (#2375)\n\n`_smrt_jobs` and `_smrt_job_events` are append-only in practice — `cleanup()`\nexisted but nothing ever called it, and job events (one row per log line and\nprogress tick) had no prune path at all. `src/retention.ts` contributes both to\nthe framework retention sweep in `@happyvertical/smrt-core`.\n\n- `TaskRunner` starts a sweeper by default. `retention: false` opts out;\n `retention: { intervalMs, policy, jobs }` tunes it. The **first sweep is one\n interval after `start()`, never at start** — a crash-looping worker must not\n become a delete loop, and a short-lived runner must exit having deleted\n nothing. `stop()` only clears the timer — it does **not** unregister the job\n tasks. The package entry point (`index.ts`) registers them unconditionally\n on import, so \"this process loaded `@happyvertical/smrt-jobs`\" is the\n contract that contributes them, not \"a sweeper happens to be running\";\n `unregisterJobRetentionTasks()` is the explicit opt-out for callers that\n want a clean registry (tests, teardown).\n- Windows (`DEFAULT_JOB_RETENTION`): completed/cancelled 7 days, failed 30\n days, events 30 days, 10 000 job rows per sweep. Events deliberately outlive\n the jobs they describe, so a job row removed at 7 days still has a readable\n log for another three weeks. `SmrtJobEvent.jobId` is therefore the explicit\n same-package archival exception: `@foreignKey('SmrtJob', { constraint:\n false })` retains runtime relationship metadata and its index without a\n physical database constraint that would block parent pruning.\n- `cleanup()` counts before deleting (`rowCount` is unreliable across engines)\n and honours `dryRun`, which is what makes `smrt db:prune --dry-run` an exact\n preview. Its `(status, completed_at)` predicate is indexed by\n `ensureJobsSystemTableCompatibility()`, which this collection runs on every\n `initialize()` — bootstrap cannot do it, because `_smrt_jobs` does not exist\n yet when bootstrap runs.\n- `cleanup({})` with no cutoff returns 0. It must never be read as \"delete\n everything\".\n\n## Gotchas\n\n- **Cron not timezone-aware**: cron fields match the server's **local** time, not UTC (set `TZ` for UTC); no missed-run catch-up (fire-once-forward)\n- **At-least-once execution**: a timeout cannot preempt a running handler; timed-out jobs fail without retry but the handler keeps running — make handlers idempotent (see \"Timeouts & at-least-once\")\n- **No dead letter queue**: failed jobs stay in DB with `status='failed'` — manual intervention\n- **Forge deliveries are not SmrtJobs**: they use their own replayable\n dead-letter inbox and projection checkpoint contract. Do not enqueue provider\n deliveries as generic background jobs.\n- **Result storage**: `resultPointer` is just a string — app must implement result backend\n- **Lazy builder**: `background()` returns builder — nothing happens until `enqueue()`\n- **wait() is polling**: JobHandle.wait() polls DB every 100ms (configurable)\n- **Migrate before start()**: `TaskRunner.start()` throws if `_smrt_workers` is missing — run `smrt db:migrate` after upgrading. Tables are never created at runtime.\n- **Recovery is liveness-based**: don't reintroduce heartbeat-threshold recovery; a blocked event loop must not look dead (see Worker liveness section, #1474)\n"
|
|
1416
|
+
"agentDoc": "# @happyvertical/smrt-jobs\n\nBackground job execution with persistent queue, scheduling, and fluent builder API.\n\n## Architecture\n\n```\nSmrtObject.bg('method') → SmrtJob (in _smrt_jobs) → TaskRunner picks up → executes via ObjectRegistry\nAgentSchedule (cron) → ScheduleRunner creates SmrtJob → TaskRunner executes → ScheduleRunner updates\nTaskRunner.start() → SmrtWorker lease (in _smrt_workers) → recovery keys on worker liveness, not heartbeat\n```\n\n## SmrtJob\n\nPersistent in `_smrt_jobs`. Fields: `queue` (default), `objectType`, `objectId`, `method`, `args`, `runAt`, `priority` (higher=sooner), `status`, `attempts`/`maxAttempts`, `timeout` (default 5min), `retryStrategy`, `workerId` (the owning runner's incarnation key), `workerHeartbeat` (telemetry only — no longer gates recovery).\n\nStatus: `pending → running → completed/failed/cancelled`.\n\n## TaskRunner\n\nPolling-based execution engine. Config: `concurrency` (5), `pollInterval` (1s), `idlePollInterval` (defaults to 20× `pollInterval`), `heartbeatInterval` (30s, telemetry only), `leaseTtlMs` (30s), `leaseTickMs` (10s), `shutdownTimeout` (30s). Empty claims back off exponentially to `idlePollInterval`; any claimed work, capacity pressure, or poll error resets to `pollInterval`. Every delay is capped at the effective worker lease TTL, including an oversized base interval; recovery sweep spacing stays TTL-bounded (plus query/event-loop time). Polling intervals must be finite positive milliseconds within the Node timer range.\n\n1. `start()` calls `assertReady()` (fail fast if `_smrt_workers` unmigrated), registers a seeded `SmrtWorker` lease, and adds its worker key to the process-global live set — all **before** polling\n2. Polls `claimReady()` to atomically claim at most the free slots (`concurrency - active`) of pending jobs (`runAt <= NOW`, ordered by `priority DESC, runAt ASC, created_at ASC, id ASC`). On PostgreSQL the candidates come from a `MATERIALIZED` CTE joined to the UPDATE; never claim with `WHERE id IN (SELECT … LIMIT n FOR UPDATE SKIP LOCKED)` — a nested-loop semi join rescans it per outer row and takes the whole backlog (#3145). The runner also never starts more than the free slots and returns any surplus claim to `pending` with its attempt restored\n3. Claim sets `status='running'`, `workerId=<incarnation key>`, heartbeat/start timestamps, and increments `attempts`\n4. Resolves class via `ObjectRegistry.getClass(objectType)`. Object-bound jobs\n pass `objectId` to the constructor and let `initialize()` perform the single\n canonical hydration. Runner-owned `db`, `id`, and hydration options cannot be\n overridden by agent config; missing persisted targets fail before method\n dispatch. Jobs without `objectId` construct a static-like instance\n5. **Internal args**: `_agentConfig` and `_scheduleId` stripped from args before calling method\n6. Calls the requested method on the initialized instance\n7. Terminal/retry writes are **conditional** (`WHERE worker_id=? AND status='running'`) so a recovered row is never stomped\n8. Retry: uses strategy from `@happyvertical/jobs`, schedules future `runAt` on failure\n9. Events: `job:started`, `job:completed`, `job:failed`, `job:retrying`, `runner:started/stopped`\n\nA rejection from `processJob` can never escape the poll loop: the caller attaches `.catch(e => emit('runner:error', e))` and the error path (`handleJobError`) is itself try/caught, so a failure-path write that rejects is surfaced as a `runner:error` event instead of crashing the worker with an unhandled rejection.\n\n## Timeouts & at-least-once\n\n**Execution is at-least-once, never exactly-once. Make job handlers idempotent.**\n\nA job `timeout` only races the handler's promise — JavaScript cannot preempt an already-running function. When a handler exceeds its timeout:\n\n- The job is **failed terminally and NOT auto-retried** (a timed-out handler is still running; re-queueing it would let a second worker run a concurrent duplicate). This narrows, but does not eliminate, the overlap window — the orphaned handler keeps running until it returns on its own.\n- The orphaned handler's eventual terminal write is dropped by the ownership guard (`WHERE worker_id=? AND status='running'`), so it cannot resurrect the failed row — but any **side effects** it performs (external API calls, writes to other tables) still happen.\n- Key any non-idempotent work by `context.job.jobId` or a caller-supplied idempotency key.\n\n`timeoutBehavior` (persisted + shown in the UI) is now honored:\n\n- **`'fail'`** (default): on timeout the job fails (and, per above, is not retried).\n- **`'warn'`**: the handler is **not** raced against the timeout — it runs to completion, and at the deadline the runner logs a warning and emits a `timeout-warning` job event. A slow-but-successful handler still completes successfully.\n- **`'kill'`**: treated identically to `'fail'`. In-process JavaScript has no thread interruption, so a true \"kill\" of a running handler is impossible without worker isolation; this value is honest that it only fails the job row, it does not stop the handler. Prefer `'fail'` unless you specifically want the label.\n\n## Worker liveness & recovery (#1474)\n\nRecovery keys on **worker-process liveness**, never per-job heartbeat freshness (a CPU-bound synchronous handler used to starve the heartbeat and false-recover its own running jobs).\n\n- **`SmrtWorker` / `_smrt_workers`**: one lease row per runner *incarnation* (`workerId` is per-incarnation unique via `createWorkerKey`, so a restart never looks like it still owns the previous crash's jobs). `leaseExpiresAt` is a `datetime` (an integer epoch-ms column overflows `int4`/`INT32` on Postgres/DuckDB). Stage 1 writes/compares it against the host clock — the same approach the old heartbeat recovery used, so it's no more skew-sensitive than the code it replaced.\n- **Process-global live set** (`worker-liveness.ts`, `globalThis.__smrtLiveWorkers`): checked synchronously, so it can't be starved by a blocked loop. Covers all same-process topologies.\n- **Off-loop ticker** (`worker-liveness-ticker.ts` + `worker-liveness-thread.ts`): for engines a second connection can reach (Postgres, file-backed SQLite — `offLoopEligible()`), `start()` spawns a `node:worker_threads` ticker that renews the lease on its own thread, so a CPU-bound synchronous handler on the main loop can't starve it. In-memory SQLite / DuckDB, a thread-spawn failure, a start-handshake timeout, or the thread dying mid-run all fall back to main-loop renewal; the in-process live set keeps same-process correct regardless. The worker entry is a separate build entry resolved via `import.meta.resolve('@happyvertical/smrt-jobs/worker-liveness-thread')`.\n- **Recovery rule** (both runners): a `running` job is orphaned iff its worker is *not alive* = not in the live set **and** no fresh `_smrt_workers` lease. The live set takes precedence over a stale lease. TaskRunner also never recovers a job in its own `activeJobs`. If `_smrt_workers` is absent, recovery skips lease checks (never mass-recovers). Recovery is swept at most once per lease tick, and terminal/recovery writes use `RETURNING id` (not `rowCount`, which DuckDB/JSON adapters always report as ≥1).\n- **Lease clock**: the lease is compared against the host clock (same as the old heartbeat; fine with NTP + a 30s TTL). A dead process stops renewing and the lease expires within its TTL — that is how recovery detects death. (Instant cross-process detection via Postgres session advisory locks was prototyped on `@happyvertical/sql`'s `acquireSession()` but deferred — treating a free lock as proof-of-death false-recovers any worker legitimately in main-loop fallback mode.)\n\n## ScheduleRunner\n\nPolls `_smrt_agent_schedules` every 60s for due entries. Creates SmrtJob with `queue='agents'`, `priority=75`. Wires to TaskRunner events for completion/failure tracking. Slot reconciliation keys on worker liveness (it has no in-process active-job set, so the lease/live-set is its whole mechanism).\n\nThe job is enqueued **before** `next_run` is advanced and `running_count` is incremented: a transient enqueue failure (tenant-cap hit, DB blip) therefore leaves `next_run` and `status='active'` untouched so the same due slot is retried on the next poll, rather than losing the slot and disabling the schedule.\n\n`next_run` is always recomputed from *now*, never from the previous `next_run` — this is **fire-once-forward**: runs that came due while the runner was down are not caught up, only the next future occurrence fires. There is no missed-run backfill.\n\nCustom cron parser: 5-field (minute hour dom month dow). `*`, ranges, lists, steps supported. **Not timezone-aware**: cron fields are matched against the **server's local time** (the parser uses `getHours`/`getDate`/`getDay`/… local accessors), so `0 0 * * *` fires at local midnight on the host, not at 00:00 UTC. Deploy runners in a known timezone (e.g. `TZ=UTC`) for UTC semantics. A per-schedule timezone option is a possible future enhancement.\n\n## JobBuilder — Fluent API\n\n```typescript\nconst handle = await doc.background('analyze', { detailed: true })\n .delay('5m').priority('high').retries(5).queue('analysis').timeout(600000).enqueue();\n\nawait handle.wait({ timeout: 60000, pollInterval: 100 }); // polling-based\n```\n\n## Durable forge projections\n\n`ForgeDeliveryCollection` owns the provider-neutral delivery inbox in\n`_smrt_forge_deliveries`; `ForgeProjectionRuntime` owns lease/retry/dead-letter\ntransitions and monotonic checkpoints in\n`_smrt_forge_projection_checkpoints`.\n\n- Inbox identity is `(tenant_id, provider, delivery_id)`.\n- Runtimes sharing the inbox pass `providers` (to `ForgeProjectionRuntime` or\n `claimReady`) so each claims and dead-letters only its own deliveries;\n unfiltered claims take every provider (smrt-commerce billing uses\n `<name>-billing:<sellerTenantId>`, #3060).\n- `claimReady` leases exactly one delivery; PostgreSQL uses the same\n `MATERIALIZED` CTE claim as jobs (#3105).\n- Tenant-facing accept/replay requires ambient tenant context. Worker claim is\n cross-tenant, then runtime restores the captured context before observation.\n Reads in the accept path go through the tenant-scoped collection (`list()`),\n so intake works under the interceptor's `rawQueryPolicy: 'throw'` production\n default without a bypass (#3100); keep new tenant-facing reads that way.\n- Projection callbacks must write through `ForgeProjectionContext.db`; the\n application projection, checkpoint, and inbox completion share one\n transaction.\n- Observation identity is tracker-independent\n `(projection, subjectKey, version)`. Equal or older versions are acknowledged\n without reapplying.\n- Lease-token conditions guard every terminal/failure write. Expired final\n attempts become replayable `dead_letter` rows, and persisted errors are\n redacted.\n- Generated API, CLI, and MCP surfaces stay disabled; replay is an explicit\n tenant-scoped operator action.\n\n`bg()` is shorthand: `await doc.bg('analyze', args)` → enqueues immediately, returns JobHandle.\n\n## withBackgroundJobs(Class)\n\nMixin that adds `bg()` and `background()` to any SmrtObject. Uses WeakMap for collection caching per DB instance.\n\n## Background policy (`background-policy.ts`, S5 audit #1402)\n\nThree opt-in guards, all owned **and enforced here**. Other packages apply the\neligibility marker (`reports`, `support`, `fields`, the MCP conformance\nfixture), but nothing outside this package acts on it — `TaskRunner` is the only\nreader. In particular `@happyvertical/smrt-agents` has no reference to any of\nthese guards and does not depend on this package, so marking a method does not\nchange what the agents runtime will dispatch.\n\n- `clampRetries()` / `MAX_JOB_RETRIES` (25): a requested retry count above the\n ceiling is clamped, not rejected.\n- `assertWithinTenantCreationCap(tenantId, current, cap)` /\n `DEFAULT_TENANT_JOB_CAP` (10 000): throws `TenantJobCapExceededError` when the\n tenant's count of non-terminal jobs is already at or above the cap. Applied in\n `SmrtJobCollection.enqueueJob()` (`smrt-job.ts`), which is the single choke\n point for the builder and `ScheduleRunner`; a `null` tenant and a `cap <= 0`\n both skip the check. Deliberately not serialized — concurrent enqueues can\n overshoot by the number of in-flight creators (see the method's own comment).\n- `@backgroundEligible()` / `markBackgroundEligible()` /\n `isBackgroundEligibleMethod()`: an allowlist of methods `TaskRunner` may\n dispatch, enforced at exactly one call site (`runner.ts`, after the method\n lookup). **Restrictive, not enabling** — a class with no marked methods allows\n any of its methods, and the first mark makes the set exhaustive, excluding\n every sibling method. Adding the decorator to one method of an existing class\n is therefore a behaviour change for the rest of it.\n\n## Terminal outcomes (#3696)\n\nTerminal state is authoritative together with its versioned event. Completion,\npermanent failure, timeout, stale-worker recovery, and cancellation update the\nowned `_smrt_jobs` row and append the safe `_smrt_job_events` projection in one\ndatabase transaction. If either write fails, neither commits. Conditional\nownership/status predicates prevent a lost race from appending an event.\nBuild the event from the conditional update's returned row, not a caller\nsnapshot, and bind that update to the row's tenant. Public cancellation must\nretain ambient-tenant isolation; only explicit bypass contexts may cross it.\nRetries are deliberately excluded until a later terminal transition. Ordinary\nprogress, logs, start, and retry telemetry remain best-effort.\n\n`SmrtJobEventCollection.listTerminalOutcomes()` requires an explicit tenant\n(`null` means global), reads newest-first, scans at most 1,000 candidates, and\nreturns only the safe versioned terminal shape. Never add job arguments,\nobject IDs, results, raw errors, or stacks to that shape. Applications must\nintersect job IDs with their own authorized ownership records; queue/object\ntype/method filters narrow the projection but do not authorize it.\n\n## Retention (#2375)\n\n`_smrt_jobs` and `_smrt_job_events` are append-only in practice — `cleanup()`\nexisted but nothing ever called it, and job events (one row per log line and\nprogress tick) had no prune path at all. `src/retention.ts` contributes both to\nthe framework retention sweep in `@happyvertical/smrt-core`.\n\n- `TaskRunner` starts a sweeper by default. `retention: false` opts out;\n `retention: { intervalMs, policy, jobs }` tunes it. The **first sweep is one\n interval after `start()`, never at start** — a crash-looping worker must not\n become a delete loop, and a short-lived runner must exit having deleted\n nothing. `stop()` only clears the timer — it does **not** unregister the job\n tasks. The package entry point (`index.ts`) registers them unconditionally\n on import, so \"this process loaded `@happyvertical/smrt-jobs`\" is the\n contract that contributes them, not \"a sweeper happens to be running\";\n `unregisterJobRetentionTasks()` is the explicit opt-out for callers that\n want a clean registry (tests, teardown).\n- Windows (`DEFAULT_JOB_RETENTION`): completed/cancelled 7 days, failed 30\n days, events 30 days, 10 000 job rows per sweep. Events deliberately outlive\n the jobs they describe, so a job row removed at 7 days still has a readable\n log for another three weeks. `SmrtJobEvent.jobId` is therefore the explicit\n same-package archival exception: `@foreignKey('SmrtJob', { constraint:\n false })` retains runtime relationship metadata and its index without a\n physical database constraint that would block parent pruning.\n- `cleanup()` counts before deleting (`rowCount` is unreliable across engines)\n and honours `dryRun`, which is what makes `smrt db:prune --dry-run` an exact\n preview. Its `(status, completed_at)` predicate is indexed by\n `ensureJobsSystemTableCompatibility()`, which this collection runs on every\n `initialize()` — bootstrap cannot do it, because `_smrt_jobs` does not exist\n yet when bootstrap runs.\n- `cleanup({})` with no cutoff returns 0. It must never be read as \"delete\n everything\".\n\n## Gotchas\n\n- **Cron not timezone-aware**: cron fields match the server's **local** time, not UTC (set `TZ` for UTC); no missed-run catch-up (fire-once-forward)\n- **At-least-once execution**: a timeout cannot preempt a running handler; timed-out jobs fail without retry but the handler keeps running — make handlers idempotent (see \"Timeouts & at-least-once\")\n- **No dead letter queue**: failed jobs stay in DB with `status='failed'` — manual intervention\n- **Forge deliveries are not SmrtJobs**: they use their own replayable\n dead-letter inbox and projection checkpoint contract. Do not enqueue provider\n deliveries as generic background jobs.\n- **Result storage**: `resultPointer` is just a string — app must implement result backend\n- **Lazy builder**: `background()` returns builder — nothing happens until `enqueue()`\n- **wait() is polling**: JobHandle.wait() polls DB every 100ms (configurable)\n- **Migrate before start()**: `TaskRunner.start()` throws if `_smrt_workers` is missing — run `smrt db:migrate` after upgrading. Tables are never created at runtime.\n- **Recovery is liveness-based**: don't reintroduce heartbeat-threshold recovery; a blocked event loop must not look dead (see Worker liveness section, #1474)\n"
|
|
1384
1417
|
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import type { DatabaseInterface } from '@happyvertical/sql';
|
|
2
|
+
import type { JobStatus, SmrtJob } from './smrt-job.js';
|
|
3
|
+
import { SmrtJobEvent, type SmrtJobTerminalStatus } from './smrt-job-event.js';
|
|
4
|
+
export interface SmrtJobTerminalSnapshot {
|
|
5
|
+
id: string;
|
|
6
|
+
tenantId: string | null;
|
|
7
|
+
queue: string;
|
|
8
|
+
objectType: string;
|
|
9
|
+
method: string;
|
|
10
|
+
attempts: number;
|
|
11
|
+
}
|
|
12
|
+
export interface TransitionTerminalJobOptions {
|
|
13
|
+
job: SmrtJobTerminalSnapshot;
|
|
14
|
+
status: SmrtJobTerminalStatus;
|
|
15
|
+
completedAt: Date;
|
|
16
|
+
expectedStatuses: JobStatus[];
|
|
17
|
+
expectedWorkerId?: string | null;
|
|
18
|
+
expectedTaskId?: string;
|
|
19
|
+
clearWorker?: boolean;
|
|
20
|
+
lastError?: string | null;
|
|
21
|
+
failureKind?: 'execution' | 'timeout' | 'stale-recovery';
|
|
22
|
+
resultPointer?: string | null;
|
|
23
|
+
taskResult?: Record<string, unknown> | null;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Atomically persist an owned terminal job transition and its durable outcome.
|
|
27
|
+
*
|
|
28
|
+
* A null result means the conditional transition lost a race. Neither the job
|
|
29
|
+
* row nor an event is written in that case.
|
|
30
|
+
*/
|
|
31
|
+
export declare function transitionTerminalJob(db: DatabaseInterface, options: TransitionTerminalJobOptions): Promise<SmrtJobEvent | null>;
|
|
32
|
+
export declare function terminalSnapshot(job: Pick<SmrtJob, 'id' | 'tenantId' | 'queue' | 'objectType' | 'method' | 'attempts'>): SmrtJobTerminalSnapshot | null;
|
|
33
|
+
//# sourceMappingURL=terminal-outcome.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"terminal-outcome.d.ts","sourceRoot":"","sources":["../src/terminal-outcome.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AAC5D,OAAO,KAAK,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AACxD,OAAO,EAAE,YAAY,EAAE,KAAK,qBAAqB,EAAE,MAAM,qBAAqB,CAAC;AA4B/E,MAAM,WAAW,uBAAuB;IACtC,EAAE,EAAE,MAAM,CAAC;IACX,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,4BAA4B;IAC3C,GAAG,EAAE,uBAAuB,CAAC;IAC7B,MAAM,EAAE,qBAAqB,CAAC;IAC9B,WAAW,EAAE,IAAI,CAAC;IAClB,gBAAgB,EAAE,SAAS,EAAE,CAAC;IAC9B,gBAAgB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACjC,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,WAAW,CAAC,EAAE,WAAW,GAAG,SAAS,GAAG,gBAAgB,CAAC;IACzD,aAAa,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC;CAC7C;AAED;;;;;GAKG;AACH,wBAAsB,qBAAqB,CACzC,EAAE,EAAE,iBAAiB,EACrB,OAAO,EAAE,4BAA4B,GACpC,OAAO,CAAC,YAAY,GAAG,IAAI,CAAC,CAkJ9B;AAED,wBAAgB,gBAAgB,CAC9B,GAAG,EAAE,IAAI,CACP,OAAO,EACP,IAAI,GAAG,UAAU,GAAG,OAAO,GAAG,YAAY,GAAG,QAAQ,GAAG,UAAU,CACnE,GACA,uBAAuB,GAAG,IAAI,CAUhC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@happyvertical/smrt-jobs",
|
|
3
|
-
"version": "0.55.
|
|
3
|
+
"version": "0.55.7",
|
|
4
4
|
"smrtJsdoc": "strict",
|
|
5
5
|
"description": "Background job processing for SMRT objects with persistence and scheduling",
|
|
6
6
|
"author": "HappyVertical",
|
|
@@ -51,18 +51,18 @@
|
|
|
51
51
|
}
|
|
52
52
|
},
|
|
53
53
|
"dependencies": {
|
|
54
|
-
"@happyvertical/jobs": "^0.102.
|
|
55
|
-
"@happyvertical/logger": "^0.102.
|
|
56
|
-
"@happyvertical/smrt-config": "0.55.
|
|
57
|
-
"@happyvertical/smrt-core": "0.55.
|
|
58
|
-
"@happyvertical/smrt-tenancy": "0.55.
|
|
59
|
-
"@happyvertical/smrt-types": "0.55.
|
|
60
|
-
"@happyvertical/smrt-ui": "0.55.
|
|
61
|
-
"@happyvertical/sql": "^0.102.
|
|
62
|
-
"@happyvertical/utils": "^0.102.
|
|
54
|
+
"@happyvertical/jobs": "^0.102.5",
|
|
55
|
+
"@happyvertical/logger": "^0.102.5",
|
|
56
|
+
"@happyvertical/smrt-config": "0.55.7",
|
|
57
|
+
"@happyvertical/smrt-core": "0.55.7",
|
|
58
|
+
"@happyvertical/smrt-tenancy": "0.55.7",
|
|
59
|
+
"@happyvertical/smrt-types": "0.55.7",
|
|
60
|
+
"@happyvertical/smrt-ui": "0.55.7",
|
|
61
|
+
"@happyvertical/sql": "^0.102.5",
|
|
62
|
+
"@happyvertical/utils": "^0.102.5"
|
|
63
63
|
},
|
|
64
64
|
"devDependencies": {
|
|
65
|
-
"@happyvertical/smrt-vitest": "0.55.
|
|
65
|
+
"@happyvertical/smrt-vitest": "0.55.7",
|
|
66
66
|
"@sveltejs/package": "^2.5.8",
|
|
67
67
|
"@sveltejs/vite-plugin-svelte": "^7.3.0",
|
|
68
68
|
"@types/node": "24.13.6",
|