effect-mq 0.1.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.
Files changed (53) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +235 -0
  3. package/dist/Job.d.ts +222 -0
  4. package/dist/Job.d.ts.map +1 -0
  5. package/dist/Job.js +218 -0
  6. package/dist/Job.js.map +1 -0
  7. package/dist/JobStore.d.ts +401 -0
  8. package/dist/JobStore.d.ts.map +1 -0
  9. package/dist/JobStore.js +89 -0
  10. package/dist/JobStore.js.map +1 -0
  11. package/dist/MemoryJobStore.d.ts +34 -0
  12. package/dist/MemoryJobStore.d.ts.map +1 -0
  13. package/dist/MemoryJobStore.js +381 -0
  14. package/dist/MemoryJobStore.js.map +1 -0
  15. package/dist/Worker.d.ts +127 -0
  16. package/dist/Worker.d.ts.map +1 -0
  17. package/dist/Worker.js +274 -0
  18. package/dist/Worker.js.map +1 -0
  19. package/dist/drizzle/DrizzleJobStore.d.ts +59 -0
  20. package/dist/drizzle/DrizzleJobStore.d.ts.map +1 -0
  21. package/dist/drizzle/DrizzleJobStore.js +426 -0
  22. package/dist/drizzle/DrizzleJobStore.js.map +1 -0
  23. package/dist/drizzle/index.d.ts +19 -0
  24. package/dist/drizzle/index.d.ts.map +1 -0
  25. package/dist/drizzle/index.js +19 -0
  26. package/dist/drizzle/index.js.map +1 -0
  27. package/dist/drizzle/schema.d.ts +464 -0
  28. package/dist/drizzle/schema.d.ts.map +1 -0
  29. package/dist/drizzle/schema.js +68 -0
  30. package/dist/drizzle/schema.js.map +1 -0
  31. package/dist/index.d.ts +30 -0
  32. package/dist/index.d.ts.map +1 -0
  33. package/dist/index.js +30 -0
  34. package/dist/index.js.map +1 -0
  35. package/dist/testing/conformance.d.ts +27 -0
  36. package/dist/testing/conformance.d.ts.map +1 -0
  37. package/dist/testing/conformance.js +451 -0
  38. package/dist/testing/conformance.js.map +1 -0
  39. package/dist/testing/index.d.ts +8 -0
  40. package/dist/testing/index.d.ts.map +1 -0
  41. package/dist/testing/index.js +8 -0
  42. package/dist/testing/index.js.map +1 -0
  43. package/package.json +71 -0
  44. package/src/Job.ts +606 -0
  45. package/src/JobStore.ts +446 -0
  46. package/src/MemoryJobStore.ts +467 -0
  47. package/src/Worker.ts +514 -0
  48. package/src/drizzle/DrizzleJobStore.ts +599 -0
  49. package/src/drizzle/index.ts +20 -0
  50. package/src/drizzle/schema.ts +116 -0
  51. package/src/index.ts +33 -0
  52. package/src/testing/conformance.ts +654 -0
  53. package/src/testing/index.ts +7 -0
@@ -0,0 +1,89 @@
1
+ /**
2
+ * The storage seam of effect-mq.
3
+ *
4
+ * `JobStore` is the minimal, storage-agnostic interface a queue backend must
5
+ * implement. Every method must be atomic within the driver. The reference
6
+ * implementation is `MemoryJobStore`; Postgres (via `effect-mq/drizzle`),
7
+ * Redis, etc. drivers implement the same service.
8
+ *
9
+ * The store works entirely on *encoded* (JSON-safe) payloads and exits —
10
+ * schema encoding/decoding happens in `Job` (producer side) and `Worker`
11
+ * (consumer side), so drivers stay dumb.
12
+ *
13
+ * Multiple stores can coexist in one application via named store keys (see
14
+ * `named`): each job definition binds to a store key, so business-critical
15
+ * jobs can live in Postgres while disposable ones live elsewhere.
16
+ *
17
+ * @since 0.1.0
18
+ */
19
+ import { Brand, Context, Data, Predicate } from "effect";
20
+ /**
21
+ * Brand a raw string as a `JobId`.
22
+ *
23
+ * @since 0.1.0
24
+ */
25
+ export const JobId = Brand.nominal();
26
+ /**
27
+ * Brand a raw string as a `QueueName`.
28
+ *
29
+ * @since 0.1.0
30
+ */
31
+ export const QueueName = Brand.nominal();
32
+ /**
33
+ * A transient or fatal driver error (connection loss, serialization, etc.).
34
+ *
35
+ * @since 0.1.0
36
+ */
37
+ export class JobStoreError extends Data.TaggedError("JobStoreError") {
38
+ }
39
+ /**
40
+ * Tag-based guard (safe across duplicate module copies, unlike `instanceof`).
41
+ *
42
+ * @since 0.1.0
43
+ */
44
+ // oxlint-disable-next-line anti-slop/no-unknown-parameters -- a type guard IS the boundary parser; `unknown` input is its purpose
45
+ export const isJobStoreError = (u) => Predicate.hasProperty(u, "_tag") && u._tag === "JobStoreError";
46
+ /**
47
+ * The presented lock token no longer owns the job (it stalled and was
48
+ * recovered, or another worker claimed it).
49
+ *
50
+ * @since 0.1.0
51
+ */
52
+ export class LockLostError extends Data.TaggedError("LockLostError") {
53
+ }
54
+ /**
55
+ * @since 0.1.0
56
+ */
57
+ export class JobNotFoundError extends Data.TaggedError("JobNotFoundError") {
58
+ }
59
+ /**
60
+ * `retry` was called on a job that is not in the `failed` state.
61
+ *
62
+ * @since 0.1.0
63
+ */
64
+ export class JobNotRetryableError extends Data.TaggedError("JobNotRetryableError") {
65
+ }
66
+ /**
67
+ * The default store key. Jobs without an explicit `store` binding use this.
68
+ *
69
+ * @since 0.1.0
70
+ */
71
+ export class JobStore extends Context.Service()("effect-mq/JobStore") {
72
+ }
73
+ /**
74
+ * Create a named store key. Jobs bound to it (via `Job.make`'s `store`
75
+ * option) require it in `R` instead of the default `JobStore`, letting
76
+ * different jobs run on different storage infrastructure:
77
+ *
78
+ * ```ts
79
+ * const Durable = JobStore.named("durable") // -> Postgres in prod
80
+ * const Ephemeral = JobStore.named("ephemeral") // -> Redis in prod
81
+ * ```
82
+ *
83
+ * Keys are identified by their name string: two `named("durable")` calls are
84
+ * interchangeable.
85
+ *
86
+ * @since 0.1.0
87
+ */
88
+ export const named = (name) => Context.Service(`effect-mq/JobStore/${name}`);
89
+ //# sourceMappingURL=JobStore.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"JobStore.js","sourceRoot":"","sources":["../src/JobStore.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AACH,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,IAAI,EAA4B,SAAS,EAAE,MAAM,QAAQ,CAAA;AAUlF;;;;GAIG;AACH,MAAM,CAAC,MAAM,KAAK,GAA6B,KAAK,CAAC,OAAO,EAAS,CAAA;AASrE;;;;GAIG;AACH,MAAM,CAAC,MAAM,SAAS,GAAiC,KAAK,CAAC,OAAO,EAAa,CAAA;AAoMjF;;;;GAIG;AACH,MAAM,OAAO,aAAc,SAAQ,IAAI,CAAC,WAAW,CAAC,eAAe,CAGjE;CAAG;AAEL;;;;GAIG;AACH,kIAAkI;AAClI,MAAM,CAAC,MAAM,eAAe,GAAG,CAAC,CAAU,EAAsB,EAAE,CAChE,SAAS,CAAC,WAAW,CAAC,CAAC,EAAE,MAAM,CAAC,IAAI,CAAC,CAAC,IAAI,KAAK,eAAe,CAAA;AAGhE;;;;;GAKG;AACH,MAAM,OAAO,aAAc,SAAQ,IAAI,CAAC,WAAW,CAAC,eAAe,CAEjE;CAAG;AAEL;;GAEG;AACH,MAAM,OAAO,gBAAiB,SAAQ,IAAI,CAAC,WAAW,CAAC,kBAAkB,CAEvE;CAAG;AAEL;;;;GAIG;AACH,MAAM,OAAO,oBAAqB,SAAQ,IAAI,CAAC,WAAW,CAAC,sBAAsB,CAG/E;CAAG;AAiHL;;;;GAIG;AACH,MAAM,OAAO,QAAS,SAAQ,OAAO,CAAC,OAAO,EAAqB,CAChE,oBAAoB,CACrB;CAAG;AAYJ;;;;;;;;;;;;;;GAcG;AACH,MAAM,CAAC,MAAM,KAAK,GAAG,CACnB,IAAU,EACyB,EAAE,CACrC,OAAO,CAAC,OAAO,CAAuB,sBAAsB,IAAI,EAAE,CAAC,CAAA"}
@@ -0,0 +1,34 @@
1
+ /**
2
+ * In-memory `JobStore` built purely on Effect primitives.
3
+ *
4
+ * The reference driver: used for tests, local development and as the template
5
+ * for real storage adapters. Time comes from `Clock`, so everything is fully
6
+ * `TestClock`-compatible.
7
+ *
8
+ * Atomicity note: every operation reads the clock once and then mutates state
9
+ * in a single synchronous block, which is atomic on the JavaScript runtime.
10
+ *
11
+ * @since 0.1.0
12
+ */
13
+ import { type Context, Effect, Layer } from "effect";
14
+ import { JobStore, type Service } from "./JobStore.ts";
15
+ /**
16
+ * Build a fresh in-memory `JobStore` implementation.
17
+ *
18
+ * @since 0.1.0
19
+ */
20
+ export declare const make: Effect.Effect<Service>;
21
+ /**
22
+ * A fresh in-memory `JobStore` layer. Pass a named store key to provide a
23
+ * `JobStore.named(...)` slot instead of the default.
24
+ *
25
+ * @since 0.1.0
26
+ */
27
+ export declare const layer: Layer.Layer<JobStore>;
28
+ /**
29
+ * An in-memory layer for a specific store key.
30
+ *
31
+ * @since 0.1.0
32
+ */
33
+ export declare const layerFor: <Id>(store: Context.Key<Id, Service>) => Layer.Layer<Id>;
34
+ //# sourceMappingURL=MemoryJobStore.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"MemoryJobStore.d.ts","sourceRoot":"","sources":["../src/MemoryJobStore.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AACH,OAAO,EAAS,KAAK,OAAO,EAAY,MAAM,EAAQ,KAAK,EAAU,MAAM,QAAQ,CAAA;AACnF,OAAO,EASL,QAAQ,EAIR,KAAK,OAAO,EACb,MAAM,eAAe,CAAA;AA0DtB;;;;GAIG;AACH,eAAO,MAAM,IAAI,EAAE,MAAM,CAAC,MAAM,CAAC,OAAO,CAuWtC,CAAA;AAEF;;;;;GAKG;AACH,eAAO,MAAM,KAAK,EAAE,KAAK,CAAC,KAAK,CAAC,QAAQ,CAAgC,CAAA;AAExE;;;;GAIG;AACH,eAAO,MAAM,QAAQ,GAAI,EAAE,SAClB,OAAO,CAAC,GAAG,CAAC,EAAE,EAAE,OAAO,CAAC,KAC9B,KAAK,CAAC,KAAK,CAAC,EAAE,CAA8B,CAAA"}
@@ -0,0 +1,381 @@
1
+ /**
2
+ * In-memory `JobStore` built purely on Effect primitives.
3
+ *
4
+ * The reference driver: used for tests, local development and as the template
5
+ * for real storage adapters. Time comes from `Clock`, so everything is fully
6
+ * `TestClock`-compatible.
7
+ *
8
+ * Atomicity note: every operation reads the clock once and then mutates state
9
+ * in a single synchronous block, which is atomic on the JavaScript runtime.
10
+ *
11
+ * @since 0.1.0
12
+ */
13
+ import { Clock, Deferred, Effect, Exit, Layer, Option } from "effect";
14
+ import { JobId, JobNotFoundError, JobNotRetryableError, JobStore, LockLostError } from "./JobStore.js";
15
+ const snapshot = (job) => ({
16
+ id: job.id,
17
+ name: job.name,
18
+ queue: job.queue,
19
+ payload: job.payload,
20
+ metadata: job.metadata,
21
+ state: job.state,
22
+ priority: job.priority,
23
+ attemptsMax: job.attemptsMax,
24
+ attemptsMade: job.attemptsMade,
25
+ stalledCount: job.stalledCount,
26
+ backoff: job.backoff,
27
+ keep: job.keep,
28
+ runAt: job.runAt,
29
+ enqueuedAt: job.enqueuedAt,
30
+ processedAt: job.processedAt,
31
+ finishedAt: job.finishedAt,
32
+ exit: job.exit,
33
+ failedReason: job.failedReason
34
+ });
35
+ const metadataMatches = (record, filter) => {
36
+ for (const [key, value] of Object.entries(filter)) {
37
+ if (record[key] !== value)
38
+ return false;
39
+ }
40
+ return true;
41
+ };
42
+ /**
43
+ * Build a fresh in-memory `JobStore` implementation.
44
+ *
45
+ * @since 0.1.0
46
+ */
47
+ export const make = Effect.sync(() => {
48
+ const jobs = new Map();
49
+ let seq = 0;
50
+ let idCounter = 0;
51
+ let wakeVersion = 0;
52
+ let wake = Deferred.makeUnsafe();
53
+ // Synchronous on purpose: it is called inside the same synchronous block as
54
+ // the state mutation, so no effect-op boundary (where an interrupt could
55
+ // land) can separate a mutation from its wake-up signal.
56
+ const signalWake = () => {
57
+ wakeVersion += 1;
58
+ const current = wake;
59
+ wake = Deferred.makeUnsafe();
60
+ Deferred.doneUnsafe(current, Exit.succeed(void 0));
61
+ };
62
+ const promoteDue = (now) => {
63
+ for (const job of jobs.values()) {
64
+ if (job.state === "delayed" && job.runAt <= now) {
65
+ job.state = "waiting";
66
+ }
67
+ }
68
+ };
69
+ const clearLock = (job) => {
70
+ job.lockToken = undefined;
71
+ job.lockExpiresAt = undefined;
72
+ };
73
+ const recordAttempt = (job, outcome, finishedAt, exit) => {
74
+ job.attempts.push({
75
+ attempt: job.attempts.length + 1,
76
+ startedAt: job.processedAt,
77
+ finishedAt,
78
+ outcome,
79
+ exit
80
+ });
81
+ };
82
+ // Terminal retention: keep at most `count` and drop older than `ageMs`
83
+ // among terminal jobs sharing this job's name + state.
84
+ const applyKeep = (job, now) => {
85
+ if (job.keep === undefined)
86
+ return;
87
+ const peers = Array.from(jobs.values())
88
+ .filter((peer) => peer.name === job.name && peer.state === job.state)
89
+ .toSorted((a, b) => ((b.finishedAt ?? 0) - (a.finishedAt ?? 0)) || (b.seq - a.seq));
90
+ const remove = new Set();
91
+ if (job.keep.ageMs !== undefined) {
92
+ for (const peer of peers) {
93
+ if (peer.finishedAt !== undefined && peer.finishedAt <= now - job.keep.ageMs) {
94
+ remove.add(peer.id);
95
+ }
96
+ }
97
+ }
98
+ if (job.keep.count !== undefined) {
99
+ for (const peer of peers.slice(Math.max(0, job.keep.count))) {
100
+ remove.add(peer.id);
101
+ }
102
+ }
103
+ for (const id of remove) {
104
+ jobs.delete(id);
105
+ }
106
+ };
107
+ return JobStore.of({
108
+ enqueue: (request) => Effect.gen(function* () {
109
+ const now = yield* Clock.currentTimeMillis;
110
+ let id = request.id;
111
+ if (id === undefined) {
112
+ // Store-assigned ids must never collide with user-supplied ones.
113
+ do {
114
+ id = JobId(`j-${++idCounter}`);
115
+ } while (jobs.has(id));
116
+ }
117
+ else if (jobs.has(id)) {
118
+ return { id, duplicate: true };
119
+ }
120
+ jobs.set(id, {
121
+ id,
122
+ name: request.name,
123
+ queue: request.queue,
124
+ payload: request.payload,
125
+ metadata: request.metadata,
126
+ state: request.delayMs > 0 ? "delayed" : "waiting",
127
+ priority: request.priority,
128
+ attemptsMax: request.attemptsMax,
129
+ attemptsMade: 0,
130
+ stalledCount: 0,
131
+ backoff: request.backoff,
132
+ keep: request.keep,
133
+ runAt: now + Math.max(0, request.delayMs),
134
+ enqueuedAt: now,
135
+ processedAt: undefined,
136
+ finishedAt: undefined,
137
+ exit: undefined,
138
+ failedReason: undefined,
139
+ attempts: [],
140
+ seq: ++seq,
141
+ lockToken: undefined,
142
+ lockExpiresAt: undefined
143
+ });
144
+ signalWake();
145
+ return { id, duplicate: false };
146
+ }),
147
+ claim: (options) => Effect.gen(function* () {
148
+ const now = yield* Clock.currentTimeMillis;
149
+ promoteDue(now);
150
+ const names = new Set(options.names);
151
+ let best;
152
+ let nextRunAt;
153
+ for (const job of jobs.values()) {
154
+ if (job.queue !== options.queue || !names.has(job.name))
155
+ continue;
156
+ if (job.state === "waiting") {
157
+ if (best === undefined ||
158
+ job.priority > best.priority ||
159
+ (job.priority === best.priority && job.seq < best.seq)) {
160
+ best = job;
161
+ }
162
+ }
163
+ else if (job.state === "delayed") {
164
+ if (nextRunAt === undefined || job.runAt < nextRunAt) {
165
+ nextRunAt = job.runAt;
166
+ }
167
+ }
168
+ }
169
+ if (best === undefined) {
170
+ const empty = { _tag: "Empty", nextRunAt, wakeToken: wakeVersion };
171
+ return empty;
172
+ }
173
+ best.state = "active";
174
+ best.lockToken = options.token;
175
+ best.lockExpiresAt = now + options.lockDurationMs;
176
+ best.processedAt = now;
177
+ const claimed = { _tag: "Claimed", job: snapshot(best) };
178
+ return claimed;
179
+ }),
180
+ ack: (id, token, outcome) => Effect.gen(function* () {
181
+ const now = yield* Clock.currentTimeMillis;
182
+ const job = jobs.get(id);
183
+ if (job === undefined) {
184
+ return yield* new JobNotFoundError({ jobId: id });
185
+ }
186
+ if (job.state !== "active" || job.lockToken !== token) {
187
+ return yield* new LockLostError({ jobId: id });
188
+ }
189
+ clearLock(job);
190
+ job.attemptsMade += 1;
191
+ switch (outcome._tag) {
192
+ case "Complete": {
193
+ job.state = "completed";
194
+ job.exit = outcome.exit;
195
+ job.finishedAt = now;
196
+ recordAttempt(job, "completed", now, outcome.exit);
197
+ applyKeep(job, now);
198
+ break;
199
+ }
200
+ case "Fail": {
201
+ job.state = "failed";
202
+ job.exit = outcome.exit;
203
+ job.finishedAt = now;
204
+ recordAttempt(job, "failed", now, outcome.exit);
205
+ applyKeep(job, now);
206
+ break;
207
+ }
208
+ case "Retry": {
209
+ recordAttempt(job, "retried", now, outcome.exit);
210
+ job.runAt = now + Math.max(0, outcome.delayMs);
211
+ job.state = outcome.delayMs > 0 ? "delayed" : "waiting";
212
+ job.seq = ++seq;
213
+ signalWake();
214
+ break;
215
+ }
216
+ }
217
+ }),
218
+ release: (id, token) => Effect.gen(function* () {
219
+ const job = jobs.get(id);
220
+ if (job === undefined) {
221
+ return yield* new JobNotFoundError({ jobId: id });
222
+ }
223
+ if (job.state !== "active" || job.lockToken !== token) {
224
+ return yield* new LockLostError({ jobId: id });
225
+ }
226
+ clearLock(job);
227
+ job.state = "waiting";
228
+ signalWake();
229
+ }),
230
+ extendLocks: (locks, durationMs) => Effect.gen(function* () {
231
+ const now = yield* Clock.currentTimeMillis;
232
+ const lost = [];
233
+ for (const lock of locks) {
234
+ const job = jobs.get(lock.id);
235
+ if (job !== undefined &&
236
+ job.state === "active" &&
237
+ job.lockToken === lock.token) {
238
+ job.lockExpiresAt = now + durationMs;
239
+ }
240
+ else {
241
+ lost.push(lock.id);
242
+ }
243
+ }
244
+ return lost;
245
+ }),
246
+ recoverStalled: (options) => Effect.gen(function* () {
247
+ const now = yield* Clock.currentTimeMillis;
248
+ const recovered = [];
249
+ for (const job of jobs.values()) {
250
+ if (job.state !== "active" ||
251
+ job.lockExpiresAt === undefined ||
252
+ job.lockExpiresAt > now) {
253
+ continue;
254
+ }
255
+ clearLock(job);
256
+ job.stalledCount += 1;
257
+ recordAttempt(job, "stalled", now, undefined);
258
+ if (job.stalledCount > options.maxStalledCount) {
259
+ job.state = "failed";
260
+ job.finishedAt = now;
261
+ job.failedReason = "job stalled more than allowable limit";
262
+ recovered.push({ id: job.id, failed: true });
263
+ }
264
+ else {
265
+ job.state = "waiting";
266
+ recovered.push({ id: job.id, failed: false });
267
+ }
268
+ }
269
+ if (recovered.some((entry) => !entry.failed)) {
270
+ signalWake();
271
+ }
272
+ return recovered;
273
+ }),
274
+ awaitWake: (_queues, wakeToken) => Effect.suspend(() => {
275
+ if (wakeVersion > wakeToken)
276
+ return Effect.void;
277
+ return Deferred.await(wake);
278
+ }),
279
+ getJob: (id) => Effect.sync(() => {
280
+ const job = jobs.get(id);
281
+ return job === undefined ? Option.none() : Option.some(snapshot(job));
282
+ }),
283
+ getAttempts: (id) => Effect.sync(() => {
284
+ const job = jobs.get(id);
285
+ return job === undefined ? [] : [...job.attempts];
286
+ }),
287
+ list: (options) => Effect.sync(() => {
288
+ const limit = Math.max(1, options.limit ?? 50);
289
+ const states = options.states === undefined ? undefined : new Set(options.states);
290
+ // Newest first, stable across retries: (enqueuedAt desc, id desc).
291
+ let cursor;
292
+ if (options.cursor !== undefined) {
293
+ const split = options.cursor.indexOf(":");
294
+ cursor = {
295
+ at: Number(options.cursor.slice(0, split)),
296
+ id: options.cursor.slice(split + 1)
297
+ };
298
+ }
299
+ const matches = Array.from(jobs.values())
300
+ .filter((job) => (options.queue === undefined || job.queue === options.queue) &&
301
+ (options.name === undefined || job.name === options.name) &&
302
+ (states === undefined || states.has(job.state)) &&
303
+ (options.metadata === undefined || metadataMatches(job.metadata, options.metadata)))
304
+ .toSorted((a, b) => b.enqueuedAt !== a.enqueuedAt
305
+ ? b.enqueuedAt - a.enqueuedAt
306
+ : b.id < a.id
307
+ ? -1
308
+ : b.id > a.id
309
+ ? 1
310
+ : 0)
311
+ .filter((job) => cursor === undefined ||
312
+ job.enqueuedAt < cursor.at ||
313
+ (job.enqueuedAt === cursor.at && job.id < cursor.id));
314
+ const items = matches.slice(0, limit).map(snapshot);
315
+ const last = items[items.length - 1];
316
+ const result = {
317
+ items,
318
+ cursor: matches.length > limit && last !== undefined
319
+ ? `${last.enqueuedAt}:${last.id}`
320
+ : undefined
321
+ };
322
+ return result;
323
+ }),
324
+ retry: (id) => Effect.gen(function* () {
325
+ const job = jobs.get(id);
326
+ if (job === undefined) {
327
+ return yield* new JobNotFoundError({ jobId: id });
328
+ }
329
+ if (job.state !== "failed") {
330
+ return yield* new JobNotRetryableError({ jobId: id, state: job.state });
331
+ }
332
+ const now = yield* Clock.currentTimeMillis;
333
+ job.state = "waiting";
334
+ job.attemptsMade = 0;
335
+ job.stalledCount = 0;
336
+ job.exit = undefined;
337
+ job.failedReason = undefined;
338
+ job.finishedAt = undefined;
339
+ job.processedAt = undefined;
340
+ job.runAt = now;
341
+ job.seq = ++seq;
342
+ signalWake();
343
+ }),
344
+ counts: (queue) => Effect.sync(() => {
345
+ const counts = {
346
+ waiting: 0,
347
+ delayed: 0,
348
+ active: 0,
349
+ completed: 0,
350
+ failed: 0
351
+ };
352
+ for (const job of jobs.values()) {
353
+ if (queue !== undefined && job.queue !== queue)
354
+ continue;
355
+ counts[job.state] += 1;
356
+ }
357
+ return counts;
358
+ }),
359
+ remove: (id) => Effect.sync(() => {
360
+ const job = jobs.get(id);
361
+ if (job === undefined || job.state === "active")
362
+ return false;
363
+ jobs.delete(id);
364
+ return true;
365
+ })
366
+ });
367
+ });
368
+ /**
369
+ * A fresh in-memory `JobStore` layer. Pass a named store key to provide a
370
+ * `JobStore.named(...)` slot instead of the default.
371
+ *
372
+ * @since 0.1.0
373
+ */
374
+ export const layer = Layer.effect(JobStore, make);
375
+ /**
376
+ * An in-memory layer for a specific store key.
377
+ *
378
+ * @since 0.1.0
379
+ */
380
+ export const layerFor = (store) => Layer.effect(store, make);
381
+ //# sourceMappingURL=MemoryJobStore.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"MemoryJobStore.js","sourceRoot":"","sources":["../src/MemoryJobStore.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,127 @@
1
+ /**
2
+ * The worker runtime of effect-mq.
3
+ *
4
+ * `Worker` is a service that runs registered job handlers against a
5
+ * `JobStore`. Handlers are registered through `Job.toLayer(handler)`; the
6
+ * worker starts a set of taker fibers per queue (bounded by the queue's
7
+ * concurrency), each running the loop:
8
+ *
9
+ * claim -> decode payload -> run handler -> ack (complete | retry | fail)
10
+ *
11
+ * plus two maintenance fibers: lock renewal for in-flight jobs, and stalled
12
+ * job recovery. On scope close, in-flight handlers are interrupted and their
13
+ * jobs released back to `waiting` without consuming an attempt.
14
+ *
15
+ * @since 0.1.0
16
+ */
17
+ import { Context, Duration, Effect, Exit, Layer, Schema, type Scope } from "effect";
18
+ import { type BackoffPolicy, type JobId, JobStore, QueueName, type Service as StoreService } from "./JobStore.ts";
19
+ /**
20
+ * Information about the currently running attempt, passed to handlers as the
21
+ * second argument.
22
+ *
23
+ * @since 0.1.0
24
+ */
25
+ export interface JobContext {
26
+ readonly jobId: JobId;
27
+ readonly name: string;
28
+ readonly queue: QueueName;
29
+ /** 1-based attempt number. */
30
+ readonly attempt: number;
31
+ /** Total attempts allowed for this job. */
32
+ readonly attemptsMax: number;
33
+ }
34
+ /**
35
+ * The structural shape of a job definition the worker needs for
36
+ * registration. `Job.Job` satisfies this — the indirection avoids a module
37
+ * cycle between `Job` and `Worker`.
38
+ *
39
+ * @since 0.1.0
40
+ */
41
+ export interface JobDescriptor<Payload extends Schema.Top, Success extends Schema.Top, Error extends Schema.Top> {
42
+ readonly _tag: string;
43
+ readonly queue: QueueName;
44
+ /** The store this job is bound to; must match the worker's store. */
45
+ readonly store: Context.Key<any, StoreService>;
46
+ readonly payloadSchema: Payload;
47
+ /** JSON codec for the payload (what is actually stored). */
48
+ readonly payloadJsonSchema: Schema.Top & {
49
+ readonly Type: Payload["Type"];
50
+ };
51
+ /** JSON codec for handler exits (what is actually stored). */
52
+ readonly exitSchema: Schema.Top & {
53
+ readonly Type: Exit.Exit<Success["Type"], Error["Type"]>;
54
+ };
55
+ }
56
+ /**
57
+ * @since 0.1.0
58
+ */
59
+ export interface RegisterOptions {
60
+ /**
61
+ * Taker fibers for this job's queue. The first registration for a queue
62
+ * decides; later values for the same queue are ignored.
63
+ */
64
+ readonly concurrency?: number | undefined;
65
+ /** Override the queue this handler consumes (defaults to the job's queue). */
66
+ readonly queue?: string | undefined;
67
+ }
68
+ /**
69
+ * @since 0.1.0
70
+ */
71
+ export interface WorkerOptions<StoreId = JobStore> {
72
+ /**
73
+ * The store this worker claims from (a `JobStore.named(...)` key). Default:
74
+ * the default `JobStore`. To run workers for several stores in one process,
75
+ * provide each `Worker.layer({ store })` *locally* to its handler group via
76
+ * `Layer.provide` (not `provideMerge`).
77
+ */
78
+ readonly store?: Context.Key<StoreId, StoreService> | undefined;
79
+ /** Default taker fibers per queue (default 1). */
80
+ readonly concurrency?: number | undefined;
81
+ /** Per-queue configuration, keyed by queue name. */
82
+ readonly queues?: Readonly<Record<string, {
83
+ readonly concurrency?: number | undefined;
84
+ }>> | undefined;
85
+ /** How long a claim's lock lasts before the job counts as stalled (default 30s). */
86
+ readonly lockDuration?: Duration.Input | undefined;
87
+ /** Lock heartbeat interval (default half of `lockDuration`). */
88
+ readonly lockRenewInterval?: Duration.Input | undefined;
89
+ /** How often to sweep for stalled jobs (default 30s). */
90
+ readonly stalledInterval?: Duration.Input | undefined;
91
+ /** Stalls tolerated before a job is failed outright (default 1). */
92
+ readonly maxStalledCount?: number | undefined;
93
+ /** Fallback polling interval when idle and no wake-up arrives (default 5s). */
94
+ readonly pollInterval?: Duration.Input | undefined;
95
+ /** Identifier used in lock tokens (default: random). */
96
+ readonly id?: string | undefined;
97
+ }
98
+ declare const Worker_base: Context.ServiceClass<Worker, "effect-mq/Worker", {
99
+ readonly register: <Payload extends Schema.Top, Success extends Schema.Top, Error extends Schema.Top, R>(job: JobDescriptor<Payload, Success, Error>, handler: (payload: Payload["Type"], context: JobContext) => Effect.Effect<Success["Type"], Error["Type"], R>, options?: RegisterOptions | undefined) => Effect.Effect<void, never, Scope.Scope | R | Payload["DecodingServices"] | Success["EncodingServices"] | Error["EncodingServices"]>;
100
+ }>;
101
+ /**
102
+ * @since 0.1.0
103
+ */
104
+ export declare class Worker extends Worker_base {
105
+ }
106
+ /**
107
+ * Delay before attempt `attempt` (1-based) re-runs, per the job's policy.
108
+ *
109
+ * @internal
110
+ */
111
+ export declare const backoffDelayMs: (backoff: BackoffPolicy | undefined, attempt: number) => number;
112
+ /**
113
+ * Build the worker service. Requires a `Scope` (fibers live in it) and the
114
+ * `JobStore`.
115
+ *
116
+ * @since 0.1.0
117
+ */
118
+ export declare const make: <StoreId = JobStore>(options?: WorkerOptions<StoreId> | undefined) => Effect.Effect<Worker["Service"], never, Scope.Scope | StoreId>;
119
+ /**
120
+ * Run a worker as a layer. Provide handler layers (`Job.toLayer(...)`) on top
121
+ * of this, and a `JobStore` below it.
122
+ *
123
+ * @since 0.1.0
124
+ */
125
+ export declare const layer: <StoreId = JobStore>(options?: WorkerOptions<StoreId> | undefined) => Layer.Layer<Worker, never, StoreId>;
126
+ export {};
127
+ //# sourceMappingURL=Worker.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Worker.d.ts","sourceRoot":"","sources":["../src/Worker.ts"],"names":[],"mappings":"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"}