@sixthsummit/ship-testing 0.0.0-stage → 1.2.0

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.
@@ -0,0 +1,232 @@
1
+ const passthrough = {
2
+ "conf.ok": { attempts: 3, initialMs: 10 },
3
+ "conf.flaky": { attempts: 3, initialMs: 10 },
4
+ "conf.final": { attempts: 3, initialMs: 10 },
5
+ "conf.slow": { attempts: 1, initialMs: 10 },
6
+ };
7
+ /** Job declarations every conformance run attaches; retention is short so cleanup is observable. */
8
+ export function conformanceJobs() {
9
+ const schema = {
10
+ "~standard": {
11
+ version: 1,
12
+ vendor: "conformance",
13
+ validate: (value) => ({ value }),
14
+ },
15
+ };
16
+ return Object.freeze(Object.entries(passthrough).map(([id, retry]) => Object.freeze({
17
+ id,
18
+ input: schema,
19
+ trigger: Object.freeze({ kind: "enqueue" }),
20
+ concurrency: Object.freeze({
21
+ mode: "parallel",
22
+ max: 2,
23
+ keyed: false,
24
+ leaseMs: 1_000,
25
+ }),
26
+ retry: Object.freeze({
27
+ attempts: retry.attempts,
28
+ backoff: Object.freeze({ initialMs: retry.initialMs }),
29
+ }),
30
+ retention: Object.freeze({ completedMs: 50, deadLetteredMs: 50 }),
31
+ transaction: "none",
32
+ })));
33
+ }
34
+ /**
35
+ * Shared behavioral contract for `JobBackend` adapters. The in-memory backend
36
+ * and `@sixthsummit/ship-jobs-bullmq` both run it. `createBackend` receives the
37
+ * budget the suite expects and must return a fresh, unattached backend.
38
+ */
39
+ export function jobBackendConformance(name, createBackend, test, options = {}) {
40
+ const timeoutMs = options.timeoutMs ?? 10_000;
41
+ const testTimeoutMs = options.testTimeoutMs ?? timeoutMs + 5_000;
42
+ test.describe(`${name} job backend conformance`, () => {
43
+ let backend;
44
+ let calls;
45
+ let flakyFailures;
46
+ const execute = async (jobId, input, run) => {
47
+ calls.push({ jobId, input, run });
48
+ if (jobId === "conf.ok")
49
+ return { ok: true, data: { echoed: input } };
50
+ if (jobId === "conf.final") {
51
+ return { ok: false, retryable: false, error: "VALIDATION_ERROR: rejected" };
52
+ }
53
+ if (jobId === "conf.slow") {
54
+ await new Promise((resolve) => setTimeout(resolve, 150));
55
+ return { ok: true, data: undefined };
56
+ }
57
+ if (flakyFailures > 0) {
58
+ flakyFailures -= 1;
59
+ return { ok: false, retryable: true, error: `Error: flaky ${run.attempt}` };
60
+ }
61
+ return { ok: true, data: { attempt: run.attempt } };
62
+ };
63
+ const waitFor = async (predicate, label) => {
64
+ const started = Date.now();
65
+ while (Date.now() - started < timeoutMs) {
66
+ if (await predicate())
67
+ return;
68
+ await new Promise((resolve) => setTimeout(resolve, 25));
69
+ }
70
+ throw new Error(`${name} conformance timed out waiting for ${label}`);
71
+ };
72
+ test.beforeEach(async () => {
73
+ calls = [];
74
+ flakyFailures = 0;
75
+ backend = await createBackend({ maxQueueDepth: 3, maxInFlight: 2 });
76
+ await backend.attach({ jobs: conformanceJobs(), execute });
77
+ }, testTimeoutMs);
78
+ test.afterEach(async () => {
79
+ await backend.quit();
80
+ }, testTimeoutMs);
81
+ test.it("accepts runs, executes them once workers start and reports health", async () => {
82
+ const accepted = await backend.enqueue("conf.ok", { value: 1 });
83
+ test.expect(accepted).toMatchObject({ accepted: true, deduplicated: false });
84
+ const before = await backend.health(new Date());
85
+ test
86
+ .expect(before.jobs.find((job) => job.jobId === "conf.ok"))
87
+ .toMatchObject({ waiting: 1 });
88
+ test.expect(await backend.startWorkers("worker")).toBeGreaterThanOrEqual(1);
89
+ await waitFor(() => calls.length === 1, "one execution");
90
+ test.expect(calls[0]).toMatchObject({
91
+ jobId: "conf.ok",
92
+ input: { value: 1 },
93
+ run: { attempt: 1 },
94
+ });
95
+ if (!accepted.accepted)
96
+ throw new Error("unreachable");
97
+ test.expect(calls[0]?.run.runId).toBe(accepted.runId);
98
+ // The handler returning is not the completion signal: a backend records the
99
+ // outcome after the handler resolves, so wait for health to report the run
100
+ // neither waiting nor active before asserting on the settled counts.
101
+ await waitFor(async () => {
102
+ const entry = (await backend.health(new Date())).jobs.find((job) => job.jobId === "conf.ok");
103
+ return entry?.waiting === 0 && entry.active === 0;
104
+ }, "health to drain");
105
+ const after = await backend.health(new Date());
106
+ const entry = after.jobs.find((job) => job.jobId === "conf.ok");
107
+ test.expect(entry).toMatchObject({ waiting: 0, active: 0, failed: 0 });
108
+ test.expect(entry?.lastSuccessAt === undefined).toBe(false);
109
+ }, testTimeoutMs);
110
+ test.it("deduplicates a repeated dedupeKey while the first run is not terminal", async () => {
111
+ const first = await backend.enqueue("conf.ok", { value: 1 }, { dedupeKey: "same" });
112
+ const second = await backend.enqueue("conf.ok", { value: 2 }, { dedupeKey: "same" });
113
+ if (!first.accepted || !second.accepted)
114
+ throw new Error("runs were rejected");
115
+ test.expect(second.deduplicated).toBe(true);
116
+ test.expect(second.runId).toBe(first.runId);
117
+ test
118
+ .expect((await backend.health(new Date())).jobs.find((job) => job.jobId === "conf.ok")?.waiting)
119
+ .toBe(1);
120
+ }, testTimeoutMs);
121
+ test.it("returns queue-full past the configured depth instead of buffering", async () => {
122
+ for (let index = 0; index < 3; index += 1) {
123
+ test
124
+ .expect(await backend.enqueue("conf.ok", { index }))
125
+ .toMatchObject({ accepted: true });
126
+ }
127
+ test.expect(await backend.enqueue("conf.ok", { index: 3 })).toEqual({
128
+ accepted: false,
129
+ rejected: "queue-full",
130
+ });
131
+ // Other jobs keep their own depth.
132
+ test.expect(await backend.enqueue("conf.final", {})).toMatchObject({ accepted: true });
133
+ }, testTimeoutMs);
134
+ test.it("never exceeds the per-job max under a burst", async () => {
135
+ let concurrent = 0;
136
+ let peak = 0;
137
+ await backend.quit();
138
+ backend = await createBackend({ maxQueueDepth: 50, maxInFlight: 10 });
139
+ await backend.attach({
140
+ jobs: conformanceJobs(),
141
+ execute: async () => {
142
+ concurrent += 1;
143
+ peak = Math.max(peak, concurrent);
144
+ await new Promise((resolve) => setTimeout(resolve, 40));
145
+ concurrent -= 1;
146
+ return { ok: true, data: undefined };
147
+ },
148
+ });
149
+ for (let index = 0; index < 10; index += 1)
150
+ await backend.enqueue("conf.slow", { index });
151
+ await backend.startWorkers("worker");
152
+ await waitFor(async () => {
153
+ const entry = (await backend.health(new Date())).jobs.find((job) => job.jobId === "conf.slow");
154
+ return entry?.waiting === 0 && entry.active === 0 && entry.delayed === 0;
155
+ }, "the burst to finish");
156
+ test.expect(peak <= 2).toBe(true);
157
+ test.expect(peak).toBeGreaterThanOrEqual(1);
158
+ }, testTimeoutMs);
159
+ test.it("retries with backoff, records attempt history, dead-letters and supports retry/discard", async () => {
160
+ flakyFailures = 5;
161
+ const accepted = await backend.enqueue("conf.flaky", { value: "x" });
162
+ if (!accepted.accepted)
163
+ throw new Error("run was rejected");
164
+ await backend.startWorkers("worker");
165
+ await waitFor(async () => (await backend.listFailed({ limit: 10 })).length === 1, "dead-letter");
166
+ const [failed] = await backend.listFailed({ limit: 10 });
167
+ test.expect(failed).toMatchObject({
168
+ runId: accepted.runId,
169
+ jobId: "conf.flaky",
170
+ input: { value: "x" },
171
+ status: "failed",
172
+ attempts: 3,
173
+ lastError: "Error: flaky 3",
174
+ });
175
+ test
176
+ .expect(failed?.history.map((item) => item.error))
177
+ .toEqual(["Error: flaky 1", "Error: flaky 2", "Error: flaky 3"]);
178
+ test.expect(calls.filter((call) => call.jobId === "conf.flaky")).toHaveLength(3);
179
+ // Manual retry re-runs once; the remaining scripted failure dead-letters it again.
180
+ const retried = await backend.retry(accepted.runId);
181
+ test.expect(retried?.status === "failed").toBe(false);
182
+ await waitFor(() => calls.filter((call) => call.jobId === "conf.flaky").length === 4, "retry run");
183
+ await waitFor(async () => (await backend.listFailed({ limit: 10 })).length === 1, "second dead-letter");
184
+ test.expect((await backend.listFailed({ limit: 10 }))[0]?.history).toHaveLength(4);
185
+ test.expect(await backend.retry("missing-run")).toBeUndefined();
186
+ const discarded = await backend.discard(accepted.runId, "operator gave up");
187
+ test
188
+ .expect(discarded)
189
+ .toMatchObject({ status: "discarded", discardReason: "operator gave up" });
190
+ test.expect(await backend.listFailed({ limit: 10 })).toHaveLength(0);
191
+ test.expect(await backend.discard(accepted.runId, "again")).toBeUndefined();
192
+ }, testTimeoutMs);
193
+ test.it("dead-letters non-retryable outcomes immediately", async () => {
194
+ await backend.enqueue("conf.final", { value: 1 });
195
+ await backend.startWorkers("worker");
196
+ await waitFor(async () => (await backend.listFailed({ limit: 10 })).length === 1, "dead-letter");
197
+ test.expect(calls.filter((call) => call.jobId === "conf.final")).toHaveLength(1);
198
+ test.expect((await backend.listFailed({ limit: 10 }))[0]).toMatchObject({
199
+ attempts: 1,
200
+ lastError: "VALIDATION_ERROR: rejected",
201
+ });
202
+ }, testTimeoutMs);
203
+ test.it("replaces schedules instead of duplicating them and unschedules cleanly", async () => {
204
+ await backend.schedule("conf.ok", { kind: "interval", everyMs: 60_000 });
205
+ await backend.schedule("conf.ok", { kind: "interval", everyMs: 120_000 });
206
+ await backend.schedule("conf.ok", { kind: "interval", everyMs: 120_000 });
207
+ await backend.startWorkers("worker");
208
+ await new Promise((resolve) => setTimeout(resolve, 100));
209
+ const entry = (await backend.health(new Date())).jobs.find((job) => job.jobId === "conf.ok");
210
+ test.expect((entry?.waiting ?? 0) + (entry?.delayed ?? 0) <= 1).toBe(true);
211
+ await backend.unschedule("conf.ok");
212
+ }, testTimeoutMs);
213
+ test.it("deletes completed and dead-lettered runs past retention", async () => {
214
+ await backend.enqueue("conf.ok", {});
215
+ await backend.enqueue("conf.final", {});
216
+ await backend.startWorkers("worker");
217
+ await waitFor(async () => {
218
+ const entry = (await backend.health(new Date())).jobs.find((job) => job.jobId === "conf.ok");
219
+ return (calls.length === 2 &&
220
+ entry?.waiting === 0 &&
221
+ entry.active === 0 &&
222
+ (await backend.listFailed({ limit: 10 })).length === 1);
223
+ }, "both runs to be recorded");
224
+ await new Promise((resolve) => setTimeout(resolve, 100));
225
+ const result = await backend.cleanup(new Date(Date.now() + 60_000));
226
+ test.expect(result.completedDeleted).toBeGreaterThanOrEqual(1);
227
+ test.expect(result.deadLetteredDeleted).toBeGreaterThanOrEqual(1);
228
+ test.expect(await backend.listFailed({ limit: 10 })).toHaveLength(0);
229
+ }, testTimeoutMs);
230
+ });
231
+ }
232
+ //# sourceMappingURL=jobs-conformance.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"jobs-conformance.js","sourceRoot":"","sources":["../src/jobs-conformance.ts"],"names":[],"mappings":"AAmCA,MAAM,WAAW,GAA4B;IAC3C,SAAS,EAAE,EAAE,QAAQ,EAAE,CAAC,EAAE,SAAS,EAAE,EAAE,EAAE;IACzC,YAAY,EAAE,EAAE,QAAQ,EAAE,CAAC,EAAE,SAAS,EAAE,EAAE,EAAE;IAC5C,YAAY,EAAE,EAAE,QAAQ,EAAE,CAAC,EAAE,SAAS,EAAE,EAAE,EAAE;IAC5C,WAAW,EAAE,EAAE,QAAQ,EAAE,CAAC,EAAE,SAAS,EAAE,EAAE,EAAE;CAC5C,CAAC;AAMF,oGAAoG;AACpG,MAAM,UAAU,eAAe;IAC7B,MAAM,MAAM,GAAG;QACb,WAAW,EAAE;YACX,OAAO,EAAE,CAAU;YACnB,MAAM,EAAE,aAAa;YACrB,QAAQ,EAAE,CAAC,KAAc,EAAE,EAAE,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC;SAC1C;KACF,CAAC;IACF,OAAO,MAAM,CAAC,MAAM,CAClB,MAAM,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,KAAK,CAAC,EAAE,EAAE,CAC9C,MAAM,CAAC,MAAM,CAAC;QACZ,EAAE;QACF,KAAK,EAAE,MAAM;QACb,OAAO,EAAE,MAAM,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,SAAkB,EAAE,CAAC;QACpD,WAAW,EAAE,MAAM,CAAC,MAAM,CAAC;YACzB,IAAI,EAAE,UAAmB;YACzB,GAAG,EAAE,CAAC;YACN,KAAK,EAAE,KAAK;YACZ,OAAO,EAAE,KAAK;SACf,CAAC;QACF,KAAK,EAAE,MAAM,CAAC,MAAM,CAAC;YACnB,QAAQ,EAAE,KAAK,CAAC,QAAQ;YACxB,OAAO,EAAE,MAAM,CAAC,MAAM,CAAC,EAAE,SAAS,EAAE,KAAK,CAAC,SAAS,EAAE,CAAC;SACvD,CAAC;QACF,SAAS,EAAE,MAAM,CAAC,MAAM,CAAC,EAAE,WAAW,EAAE,EAAE,EAAE,cAAc,EAAE,EAAE,EAAE,CAAC;QACjE,WAAW,EAAE,MAAe;KAC7B,CAAC,CACH,CACF,CAAC;AACJ,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,qBAAqB,CACnC,IAAY,EACZ,aAAuF,EACvF,IAAwB,EACxB,UAAwC,EAAE;IAE1C,MAAM,SAAS,GAAG,OAAO,CAAC,SAAS,IAAI,MAAM,CAAC;IAC9C,MAAM,aAAa,GAAG,OAAO,CAAC,aAAa,IAAI,SAAS,GAAG,KAAK,CAAC;IAEjE,IAAI,CAAC,QAAQ,CAAC,GAAG,IAAI,0BAA0B,EAAE,GAAG,EAAE;QACpD,IAAI,OAAmB,CAAC;QACxB,IAAI,KAAgE,CAAC;QACrE,IAAI,aAAqB,CAAC;QAE1B,MAAM,OAAO,GAAG,KAAK,EACnB,KAAa,EACb,KAAc,EACd,GAAoB,EACU,EAAE;YAChC,KAAK,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,KAAK,EAAE,GAAG,EAAE,CAAC,CAAC;YAClC,IAAI,KAAK,KAAK,SAAS;gBAAE,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,EAAE,CAAC;YACtE,IAAI,KAAK,KAAK,YAAY,EAAE,CAAC;gBAC3B,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,SAAS,EAAE,KAAK,EAAE,KAAK,EAAE,4BAA4B,EAAE,CAAC;YAC9E,CAAC;YACD,IAAI,KAAK,KAAK,WAAW,EAAE,CAAC;gBAC1B,MAAM,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC,CAAC;gBACzD,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC;YACvC,CAAC;YACD,IAAI,aAAa,GAAG,CAAC,EAAE,CAAC;gBACtB,aAAa,IAAI,CAAC,CAAC;gBACnB,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,gBAAgB,GAAG,CAAC,OAAO,EAAE,EAAE,CAAC;YAC9E,CAAC;YACD,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,EAAE,OAAO,EAAE,GAAG,CAAC,OAAO,EAAE,EAAE,CAAC;QACtD,CAAC,CAAC;QAEF,MAAM,OAAO,GAAG,KAAK,EAAE,SAA2C,EAAE,KAAa,EAAE,EAAE;YACnF,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;YAC3B,OAAO,IAAI,CAAC,GAAG,EAAE,GAAG,OAAO,GAAG,SAAS,EAAE,CAAC;gBACxC,IAAI,MAAM,SAAS,EAAE;oBAAE,OAAO;gBAC9B,MAAM,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,CAAC;YAC1D,CAAC;YACD,MAAM,IAAI,KAAK,CAAC,GAAG,IAAI,sCAAsC,KAAK,EAAE,CAAC,CAAC;QACxE,CAAC,CAAC;QAEF,IAAI,CAAC,UAAU,CAAC,KAAK,IAAI,EAAE;YACzB,KAAK,GAAG,EAAE,CAAC;YACX,aAAa,GAAG,CAAC,CAAC;YAClB,OAAO,GAAG,MAAM,aAAa,CAAC,EAAE,aAAa,EAAE,CAAC,EAAE,WAAW,EAAE,CAAC,EAAE,CAAC,CAAC;YACpE,MAAM,OAAO,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,eAAe,EAAE,EAAE,OAAO,EAAE,CAAC,CAAC;QAC7D,CAAC,EAAE,aAAa,CAAC,CAAC;QAElB,IAAI,CAAC,SAAS,CAAC,KAAK,IAAI,EAAE;YACxB,MAAM,OAAO,CAAC,IAAI,EAAE,CAAC;QACvB,CAAC,EAAE,aAAa,CAAC,CAAC;QAElB,IAAI,CAAC,EAAE,CACL,mEAAmE,EACnE,KAAK,IAAI,EAAE;YACT,MAAM,QAAQ,GAAG,MAAM,OAAO,CAAC,OAAO,CAAC,SAAS,EAAE,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC,CAAC;YAChE,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,aAAa,CAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,YAAY,EAAE,KAAK,EAAE,CAAC,CAAC;YAC7E,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,MAAM,CAAC,IAAI,IAAI,EAAE,CAAC,CAAC;YAChD,IAAI;iBACD,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,KAAK,KAAK,SAAS,CAAC,CAAC;iBAC1D,aAAa,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,CAAC,CAAC;YAEjC,IAAI,CAAC,MAAM,CAAC,MAAM,OAAO,CAAC,YAAY,CAAC,QAAQ,CAAC,CAAC,CAAC,sBAAsB,CAAC,CAAC,CAAC,CAAC;YAC5E,MAAM,OAAO,CAAC,GAAG,EAAE,CAAC,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,eAAe,CAAC,CAAC;YACzD,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,aAAa,CAAC;gBAClC,KAAK,EAAE,SAAS;gBAChB,KAAK,EAAE,EAAE,KAAK,EAAE,CAAC,EAAE;gBACnB,GAAG,EAAE,EAAE,OAAO,EAAE,CAAC,EAAE;aACpB,CAAC,CAAC;YACH,IAAI,CAAC,QAAQ,CAAC,QAAQ;gBAAE,MAAM,IAAI,KAAK,CAAC,aAAa,CAAC,CAAC;YACvD,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,GAAG,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;YACtD,4EAA4E;YAC5E,2EAA2E;YAC3E,qEAAqE;YACrE,MAAM,OAAO,CAAC,KAAK,IAAI,EAAE;gBACvB,MAAM,KAAK,GAAG,CAAC,MAAM,OAAO,CAAC,MAAM,CAAC,IAAI,IAAI,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CACxD,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,KAAK,KAAK,SAAS,CACjC,CAAC;gBACF,OAAO,KAAK,EAAE,OAAO,KAAK,CAAC,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,CAAC;YACpD,CAAC,EAAE,iBAAiB,CAAC,CAAC;YACtB,MAAM,KAAK,GAAG,MAAM,OAAO,CAAC,MAAM,CAAC,IAAI,IAAI,EAAE,CAAC,CAAC;YAC/C,MAAM,KAAK,GAAG,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,KAAK,KAAK,SAAS,CAAC,CAAC;YAChE,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,aAAa,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,CAAC,CAAC;YACvE,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,aAAa,KAAK,SAAS,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAC9D,CAAC,EACD,aAAa,CACd,CAAC;QAEF,IAAI,CAAC,EAAE,CACL,uEAAuE,EACvE,KAAK,IAAI,EAAE;YACT,MAAM,KAAK,GAAG,MAAM,OAAO,CAAC,OAAO,CAAC,SAAS,EAAE,EAAE,KAAK,EAAE,CAAC,EAAE,EAAE,EAAE,SAAS,EAAE,MAAM,EAAE,CAAC,CAAC;YACpF,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,OAAO,CAAC,SAAS,EAAE,EAAE,KAAK,EAAE,CAAC,EAAE,EAAE,EAAE,SAAS,EAAE,MAAM,EAAE,CAAC,CAAC;YACrF,IAAI,CAAC,KAAK,CAAC,QAAQ,IAAI,CAAC,MAAM,CAAC,QAAQ;gBAAE,MAAM,IAAI,KAAK,CAAC,oBAAoB,CAAC,CAAC;YAC/E,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,YAAY,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YAC5C,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;YAC5C,IAAI;iBACD,MAAM,CACL,CAAC,MAAM,OAAO,CAAC,MAAM,CAAC,IAAI,IAAI,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,KAAK,KAAK,SAAS,CAAC,EAAE,OAAO,CACxF;iBACA,IAAI,CAAC,CAAC,CAAC,CAAC;QACb,CAAC,EACD,aAAa,CACd,CAAC;QAEF,IAAI,CAAC,EAAE,CACL,mEAAmE,EACnE,KAAK,IAAI,EAAE;YACT,KAAK,IAAI,KAAK,GAAG,CAAC,EAAE,KAAK,GAAG,CAAC,EAAE,KAAK,IAAI,CAAC,EAAE,CAAC;gBAC1C,IAAI;qBACD,MAAM,CAAC,MAAM,OAAO,CAAC,OAAO,CAAC,SAAS,EAAE,EAAE,KAAK,EAAE,CAAC,CAAC;qBACnD,aAAa,CAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC;YACvC,CAAC;YACD,IAAI,CAAC,MAAM,CAAC,MAAM,OAAO,CAAC,OAAO,CAAC,SAAS,EAAE,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC;gBAClE,QAAQ,EAAE,KAAK;gBACf,QAAQ,EAAE,YAAY;aACvB,CAAC,CAAC;YACH,mCAAmC;YACnC,IAAI,CAAC,MAAM,CAAC,MAAM,OAAO,CAAC,OAAO,CAAC,YAAY,EAAE,EAAE,CAAC,CAAC,CAAC,aAAa,CAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC;QACzF,CAAC,EACD,aAAa,CACd,CAAC;QAEF,IAAI,CAAC,EAAE,CACL,6CAA6C,EAC7C,KAAK,IAAI,EAAE;YACT,IAAI,UAAU,GAAG,CAAC,CAAC;YACnB,IAAI,IAAI,GAAG,CAAC,CAAC;YACb,MAAM,OAAO,CAAC,IAAI,EAAE,CAAC;YACrB,OAAO,GAAG,MAAM,aAAa,CAAC,EAAE,aAAa,EAAE,EAAE,EAAE,WAAW,EAAE,EAAE,EAAE,CAAC,CAAC;YACtE,MAAM,OAAO,CAAC,MAAM,CAAC;gBACnB,IAAI,EAAE,eAAe,EAAE;gBACvB,OAAO,EAAE,KAAK,IAAI,EAAE;oBAClB,UAAU,IAAI,CAAC,CAAC;oBAChB,IAAI,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,UAAU,CAAC,CAAC;oBAClC,MAAM,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,CAAC;oBACxD,UAAU,IAAI,CAAC,CAAC;oBAChB,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC;gBACvC,CAAC;aACF,CAAC,CAAC;YACH,KAAK,IAAI,KAAK,GAAG,CAAC,EAAE,KAAK,GAAG,EAAE,EAAE,KAAK,IAAI,CAAC;gBAAE,MAAM,OAAO,CAAC,OAAO,CAAC,WAAW,EAAE,EAAE,KAAK,EAAE,CAAC,CAAC;YAC1F,MAAM,OAAO,CAAC,YAAY,CAAC,QAAQ,CAAC,CAAC;YACrC,MAAM,OAAO,CAAC,KAAK,IAAI,EAAE;gBACvB,MAAM,KAAK,GAAG,CAAC,MAAM,OAAO,CAAC,MAAM,CAAC,IAAI,IAAI,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CACxD,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,KAAK,KAAK,WAAW,CACnC,CAAC;gBACF,OAAO,KAAK,EAAE,OAAO,KAAK,CAAC,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,IAAI,KAAK,CAAC,OAAO,KAAK,CAAC,CAAC;YAC3E,CAAC,EAAE,qBAAqB,CAAC,CAAC;YAC1B,IAAI,CAAC,MAAM,CAAC,IAAI,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YAClC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,sBAAsB,CAAC,CAAC,CAAC,CAAC;QAC9C,CAAC,EACD,aAAa,CACd,CAAC;QAEF,IAAI,CAAC,EAAE,CACL,wFAAwF,EACxF,KAAK,IAAI,EAAE;YACT,aAAa,GAAG,CAAC,CAAC;YAClB,MAAM,QAAQ,GAAG,MAAM,OAAO,CAAC,OAAO,CAAC,YAAY,EAAE,EAAE,KAAK,EAAE,GAAG,EAAE,CAAC,CAAC;YACrE,IAAI,CAAC,QAAQ,CAAC,QAAQ;gBAAE,MAAM,IAAI,KAAK,CAAC,kBAAkB,CAAC,CAAC;YAC5D,MAAM,OAAO,CAAC,YAAY,CAAC,QAAQ,CAAC,CAAC;YACrC,MAAM,OAAO,CACX,KAAK,IAAI,EAAE,CAAC,CAAC,MAAM,OAAO,CAAC,UAAU,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,KAAK,CAAC,EAClE,aAAa,CACd,CAAC;YAEF,MAAM,CAAC,MAAM,CAAC,GAAG,MAAM,OAAO,CAAC,UAAU,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE,CAAC,CAAC;YACzD,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,aAAa,CAAC;gBAChC,KAAK,EAAE,QAAQ,CAAC,KAAK;gBACrB,KAAK,EAAE,YAAY;gBACnB,KAAK,EAAE,EAAE,KAAK,EAAE,GAAG,EAAE;gBACrB,MAAM,EAAE,QAAQ;gBAChB,QAAQ,EAAE,CAAC;gBACX,SAAS,EAAE,gBAAgB;aAC5B,CAAC,CAAC;YACH,IAAI;iBACD,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;iBACjD,OAAO,CAAC,CAAC,gBAAgB,EAAE,gBAAgB,EAAE,gBAAgB,CAAC,CAAC,CAAC;YACnE,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,KAAK,KAAK,YAAY,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;YAEjF,mFAAmF;YACnF,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;YACpD,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,MAAM,KAAK,QAAQ,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YACtD,MAAM,OAAO,CACX,GAAG,EAAE,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,KAAK,KAAK,YAAY,CAAC,CAAC,MAAM,KAAK,CAAC,EACtE,WAAW,CACZ,CAAC;YACF,MAAM,OAAO,CACX,KAAK,IAAI,EAAE,CAAC,CAAC,MAAM,OAAO,CAAC,UAAU,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,KAAK,CAAC,EAClE,oBAAoB,CACrB,CAAC;YACF,IAAI,CAAC,MAAM,CAAC,CAAC,MAAM,OAAO,CAAC,UAAU,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;YACnF,IAAI,CAAC,MAAM,CAAC,MAAM,OAAO,CAAC,KAAK,CAAC,aAAa,CAAC,CAAC,CAAC,aAAa,EAAE,CAAC;YAEhE,MAAM,SAAS,GAAG,MAAM,OAAO,CAAC,OAAO,CAAC,QAAQ,CAAC,KAAK,EAAE,kBAAkB,CAAC,CAAC;YAC5E,IAAI;iBACD,MAAM,CAAC,SAAS,CAAC;iBACjB,aAAa,CAAC,EAAE,MAAM,EAAE,WAAW,EAAE,aAAa,EAAE,kBAAkB,EAAE,CAAC,CAAC;YAC7E,IAAI,CAAC,MAAM,CAAC,MAAM,OAAO,CAAC,UAAU,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;YACrE,IAAI,CAAC,MAAM,CAAC,MAAM,OAAO,CAAC,OAAO,CAAC,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC,CAAC,aAAa,EAAE,CAAC;QAC9E,CAAC,EACD,aAAa,CACd,CAAC;QAEF,IAAI,CAAC,EAAE,CACL,iDAAiD,EACjD,KAAK,IAAI,EAAE;YACT,MAAM,OAAO,CAAC,OAAO,CAAC,YAAY,EAAE,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC,CAAC;YAClD,MAAM,OAAO,CAAC,YAAY,CAAC,QAAQ,CAAC,CAAC;YACrC,MAAM,OAAO,CACX,KAAK,IAAI,EAAE,CAAC,CAAC,MAAM,OAAO,CAAC,UAAU,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,KAAK,CAAC,EAClE,aAAa,CACd,CAAC;YACF,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,KAAK,KAAK,YAAY,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;YACjF,IAAI,CAAC,MAAM,CAAC,CAAC,MAAM,OAAO,CAAC,UAAU,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,aAAa,CAAC;gBACtE,QAAQ,EAAE,CAAC;gBACX,SAAS,EAAE,4BAA4B;aACxC,CAAC,CAAC;QACL,CAAC,EACD,aAAa,CACd,CAAC;QAEF,IAAI,CAAC,EAAE,CACL,wEAAwE,EACxE,KAAK,IAAI,EAAE;YACT,MAAM,OAAO,CAAC,QAAQ,CAAC,SAAS,EAAE,EAAE,IAAI,EAAE,UAAU,EAAE,OAAO,EAAE,MAAM,EAAE,CAAC,CAAC;YACzE,MAAM,OAAO,CAAC,QAAQ,CAAC,SAAS,EAAE,EAAE,IAAI,EAAE,UAAU,EAAE,OAAO,EAAE,OAAO,EAAE,CAAC,CAAC;YAC1E,MAAM,OAAO,CAAC,QAAQ,CAAC,SAAS,EAAE,EAAE,IAAI,EAAE,UAAU,EAAE,OAAO,EAAE,OAAO,EAAE,CAAC,CAAC;YAC1E,MAAM,OAAO,CAAC,YAAY,CAAC,QAAQ,CAAC,CAAC;YACrC,MAAM,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC,CAAC;YACzD,MAAM,KAAK,GAAG,CAAC,MAAM,OAAO,CAAC,MAAM,CAAC,IAAI,IAAI,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CACxD,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,KAAK,KAAK,SAAS,CACjC,CAAC;YACF,IAAI,CAAC,MAAM,CAAC,CAAC,KAAK,EAAE,OAAO,IAAI,CAAC,CAAC,GAAG,CAAC,KAAK,EAAE,OAAO,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YAC3E,MAAM,OAAO,CAAC,UAAU,CAAC,SAAS,CAAC,CAAC;QACtC,CAAC,EACD,aAAa,CACd,CAAC;QAEF,IAAI,CAAC,EAAE,CACL,yDAAyD,EACzD,KAAK,IAAI,EAAE;YACT,MAAM,OAAO,CAAC,OAAO,CAAC,SAAS,EAAE,EAAE,CAAC,CAAC;YACrC,MAAM,OAAO,CAAC,OAAO,CAAC,YAAY,EAAE,EAAE,CAAC,CAAC;YACxC,MAAM,OAAO,CAAC,YAAY,CAAC,QAAQ,CAAC,CAAC;YACrC,MAAM,OAAO,CAAC,KAAK,IAAI,EAAE;gBACvB,MAAM,KAAK,GAAG,CAAC,MAAM,OAAO,CAAC,MAAM,CAAC,IAAI,IAAI,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CACxD,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,KAAK,KAAK,SAAS,CACjC,CAAC;gBACF,OAAO,CACL,KAAK,CAAC,MAAM,KAAK,CAAC;oBAClB,KAAK,EAAE,OAAO,KAAK,CAAC;oBACpB,KAAK,CAAC,MAAM,KAAK,CAAC;oBAClB,CAAC,MAAM,OAAO,CAAC,UAAU,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,KAAK,CAAC,CACvD,CAAC;YACJ,CAAC,EAAE,0BAA0B,CAAC,CAAC;YAC/B,MAAM,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC,CAAC;YACzD,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,OAAO,CAAC,IAAI,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,MAAM,CAAC,CAAC,CAAC;YACpE,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,gBAAgB,CAAC,CAAC,sBAAsB,CAAC,CAAC,CAAC,CAAC;YAC/D,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,mBAAmB,CAAC,CAAC,sBAAsB,CAAC,CAAC,CAAC,CAAC;YAClE,IAAI,CAAC,MAAM,CAAC,MAAM,OAAO,CAAC,UAAU,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;QACvE,CAAC,EACD,aAAa,CACd,CAAC;IACJ,CAAC,CAAC,CAAC;AACL,CAAC"}
package/lib/jobs.d.ts ADDED
@@ -0,0 +1,64 @@
1
+ import type { AnyModule, ApplicationExecutor, CompiledApplication, JobBackend, JobIntervalTrigger, JobRun, JobScheduleTrigger, LockLease, LockProvider, OperationActor, OperationExecutionResult, OperationId } from "@sixthsummit/ship-core";
2
+ export interface InMemoryLockProvider extends LockProvider {
3
+ readonly adapter: "memory";
4
+ /** Currently held leases, keyed by `jobId:key`. */
5
+ readonly leases: () => ReadonlyMap<string, LockLease>;
6
+ readonly reset: () => void;
7
+ }
8
+ /** Deterministic process-local lock provider for unit tests. */
9
+ export declare function createInMemoryLockProvider(clock?: () => Date): InMemoryLockProvider;
10
+ export interface InMemoryJobBackendOptions {
11
+ /** Runs waiting or delayed per job before `enqueue` returns `queue-full`. Defaults to 100. */
12
+ readonly maxQueueDepth?: number;
13
+ /** Process-wide in-flight cap. Defaults to 4. */
14
+ readonly maxInFlight?: number;
15
+ readonly clock?: () => Date;
16
+ /** Worker polling interval once `startWorkers` runs in a worker mode. Defaults to 5 ms. */
17
+ readonly pollMs?: number;
18
+ }
19
+ export interface InMemoryJobSchedule {
20
+ readonly jobId: string;
21
+ readonly trigger: JobScheduleTrigger | JobIntervalTrigger;
22
+ readonly nextAt: Date;
23
+ }
24
+ export interface InMemoryDrainResult {
25
+ readonly executed: number;
26
+ readonly completed: number;
27
+ readonly failed: number;
28
+ }
29
+ export interface InMemoryJobBackend extends JobBackend {
30
+ readonly adapter: "memory";
31
+ /** Snapshot of every run, oldest first. */
32
+ readonly runs: () => readonly JobRun[];
33
+ readonly schedules: () => readonly InMemoryJobSchedule[];
34
+ /** Enqueues every scheduled run due at `now`; returns how many were enqueued. */
35
+ readonly tick: (now?: Date) => Promise<number>;
36
+ /** Ticks schedules, then processes runnable runs until nothing is runnable. */
37
+ readonly drain: (options?: {
38
+ readonly maxRuns?: number;
39
+ }) => Promise<InMemoryDrainResult>;
40
+ readonly reset: () => void;
41
+ }
42
+ /**
43
+ * Deterministic in-memory job backend for unit tests and the conformance suite.
44
+ * It implements the same claim, per-key fairness, retry, dead-letter,
45
+ * schedule reconciliation and retention semantics adapters are expected to,
46
+ * without any external service.
47
+ */
48
+ export declare function createInMemoryJobBackend(options?: InMemoryJobBackendOptions): InMemoryJobBackend;
49
+ /** The first occurrence strictly after `from` for an interval or cron trigger. */
50
+ export declare function nextOccurrence(trigger: JobScheduleTrigger | JobIntervalTrigger, from: Date): Date;
51
+ export interface RunJobOnceOptions {
52
+ /** Defaults to a permissionless system actor named `ship.testing.jobs`. */
53
+ readonly actor?: OperationActor;
54
+ readonly requestId?: string;
55
+ /** Reuse an executor so singleton providers persist across runs. */
56
+ readonly executor?: ApplicationExecutor<CompiledApplication<string, readonly AnyModule[]>>;
57
+ }
58
+ /**
59
+ * Runs one job through the executor exactly as a backend would, as a system
60
+ * actor with no permissions, and returns the executor result. Single-runner
61
+ * jobs still take their lease, so an application must bind a lock provider.
62
+ */
63
+ export declare function runJobOnce<TApp extends CompiledApplication<string, readonly AnyModule[]>, TId extends OperationId<TApp>>(app: TApp, jobId: TId, input: unknown, options?: RunJobOnceOptions): Promise<OperationExecutionResult<TApp["operationById"][TId]>>;
64
+ //# sourceMappingURL=jobs.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"jobs.d.ts","sourceRoot":"","sources":["../src/jobs.ts"],"names":[],"mappings":"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"}