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.
- package/LICENSE +21 -0
- package/README.md +235 -0
- package/dist/Job.d.ts +222 -0
- package/dist/Job.d.ts.map +1 -0
- package/dist/Job.js +218 -0
- package/dist/Job.js.map +1 -0
- package/dist/JobStore.d.ts +401 -0
- package/dist/JobStore.d.ts.map +1 -0
- package/dist/JobStore.js +89 -0
- package/dist/JobStore.js.map +1 -0
- package/dist/MemoryJobStore.d.ts +34 -0
- package/dist/MemoryJobStore.d.ts.map +1 -0
- package/dist/MemoryJobStore.js +381 -0
- package/dist/MemoryJobStore.js.map +1 -0
- package/dist/Worker.d.ts +127 -0
- package/dist/Worker.d.ts.map +1 -0
- package/dist/Worker.js +274 -0
- package/dist/Worker.js.map +1 -0
- package/dist/drizzle/DrizzleJobStore.d.ts +59 -0
- package/dist/drizzle/DrizzleJobStore.d.ts.map +1 -0
- package/dist/drizzle/DrizzleJobStore.js +426 -0
- package/dist/drizzle/DrizzleJobStore.js.map +1 -0
- package/dist/drizzle/index.d.ts +19 -0
- package/dist/drizzle/index.d.ts.map +1 -0
- package/dist/drizzle/index.js +19 -0
- package/dist/drizzle/index.js.map +1 -0
- package/dist/drizzle/schema.d.ts +464 -0
- package/dist/drizzle/schema.d.ts.map +1 -0
- package/dist/drizzle/schema.js +68 -0
- package/dist/drizzle/schema.js.map +1 -0
- package/dist/index.d.ts +30 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +30 -0
- package/dist/index.js.map +1 -0
- package/dist/testing/conformance.d.ts +27 -0
- package/dist/testing/conformance.d.ts.map +1 -0
- package/dist/testing/conformance.js +451 -0
- package/dist/testing/conformance.js.map +1 -0
- package/dist/testing/index.d.ts +8 -0
- package/dist/testing/index.d.ts.map +1 -0
- package/dist/testing/index.js +8 -0
- package/dist/testing/index.js.map +1 -0
- package/package.json +71 -0
- package/src/Job.ts +606 -0
- package/src/JobStore.ts +446 -0
- package/src/MemoryJobStore.ts +467 -0
- package/src/Worker.ts +514 -0
- package/src/drizzle/DrizzleJobStore.ts +599 -0
- package/src/drizzle/index.ts +20 -0
- package/src/drizzle/schema.ts +116 -0
- package/src/index.ts +33 -0
- package/src/testing/conformance.ts +654 -0
- package/src/testing/index.ts +7 -0
package/dist/Job.js
ADDED
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Schema-first background job definitions.
|
|
3
|
+
*
|
|
4
|
+
* A `Job` is defined once (name, payload/success/error schemas, defaults) and
|
|
5
|
+
* used from both sides:
|
|
6
|
+
*
|
|
7
|
+
* - producers call `MyJob.enqueue(payload, options)` (requires the job's store)
|
|
8
|
+
* - runners provide `MyJob.toLayer(handler)` on top of a `Worker.layer`
|
|
9
|
+
*
|
|
10
|
+
* ```ts
|
|
11
|
+
* import { Job, JobStore } from "effect-mq"
|
|
12
|
+
* import { Effect, Schema } from "effect"
|
|
13
|
+
*
|
|
14
|
+
* const Durable = JobStore.named("durable")
|
|
15
|
+
*
|
|
16
|
+
* class SendEmail extends Job.make("SendEmail", {
|
|
17
|
+
* payload: { to: Schema.String, body: Schema.String },
|
|
18
|
+
* queue: "email",
|
|
19
|
+
* store: Durable,
|
|
20
|
+
* metadata: ({ to }) => ({ to }),
|
|
21
|
+
* defaults: { attempts: 5, backoff: { type: "exponential", delay: "1 second" } }
|
|
22
|
+
* }) {}
|
|
23
|
+
*
|
|
24
|
+
* // producer — requires the Durable store in context, enforced at compile time
|
|
25
|
+
* const jobId = yield* SendEmail.enqueue({ to: "a@b.c", body: "hi" }, { delay: "5 seconds" })
|
|
26
|
+
*
|
|
27
|
+
* // runner
|
|
28
|
+
* const SendEmailWorker = SendEmail.toLayer((payload) => Effect.log(`sending to ${payload.to}`))
|
|
29
|
+
* ```
|
|
30
|
+
*
|
|
31
|
+
* @since 0.1.0
|
|
32
|
+
*/
|
|
33
|
+
import { Duration, Effect, Layer, Option, Schedule, Schema } from "effect";
|
|
34
|
+
import { JobId, JobNotFoundError, JobStore, QueueName } from "./JobStore.js";
|
|
35
|
+
import { Worker } from "./Worker.js";
|
|
36
|
+
const TypeId = "~effect-mq/Job";
|
|
37
|
+
const defaultPollSchedule = Schedule.min([
|
|
38
|
+
Schedule.exponential(10, 2),
|
|
39
|
+
Schedule.spaced("1 second")
|
|
40
|
+
]);
|
|
41
|
+
const normalizeBackoff = (input) => input === undefined ? undefined : {
|
|
42
|
+
_tag: input.type,
|
|
43
|
+
delayMs: Duration.toMillis(input.delay),
|
|
44
|
+
factor: input.factor
|
|
45
|
+
};
|
|
46
|
+
const normalizeKeep = (input) => input === undefined ? undefined : {
|
|
47
|
+
count: input.count,
|
|
48
|
+
ageMs: input.age !== undefined ? Duration.toMillis(input.age) : undefined
|
|
49
|
+
};
|
|
50
|
+
const Proto = {
|
|
51
|
+
[TypeId]: TypeId,
|
|
52
|
+
enqueue(fields, options) {
|
|
53
|
+
return Effect.suspend(() => {
|
|
54
|
+
const payload = this.payloadSchema.make(fields);
|
|
55
|
+
const id = options?.jobId !== undefined
|
|
56
|
+
? JobId(options.jobId)
|
|
57
|
+
: this.idempotencyKey !== undefined
|
|
58
|
+
? JobId(`${this._tag}/${this.idempotencyKey(payload)}`)
|
|
59
|
+
: undefined;
|
|
60
|
+
const metadata = {
|
|
61
|
+
...this.metadata?.(payload),
|
|
62
|
+
...options?.metadata
|
|
63
|
+
};
|
|
64
|
+
return Schema.encodeEffect(this.payloadJsonSchema)(payload).pipe(Effect.orDie, Effect.flatMap((encoded) => Effect.flatMap(this.store, (store) => store.enqueue({
|
|
65
|
+
id,
|
|
66
|
+
name: this._tag,
|
|
67
|
+
queue: options?.queue !== undefined
|
|
68
|
+
? QueueName(options.queue)
|
|
69
|
+
: this.queue,
|
|
70
|
+
payload: encoded,
|
|
71
|
+
metadata,
|
|
72
|
+
priority: options?.priority ?? this.defaults.priority,
|
|
73
|
+
attemptsMax: Math.max(1, options?.attempts ?? this.defaults.attempts),
|
|
74
|
+
backoff: options?.backoff !== undefined
|
|
75
|
+
? normalizeBackoff(options.backoff)
|
|
76
|
+
: this.defaults.backoff,
|
|
77
|
+
keep: options?.keep !== undefined
|
|
78
|
+
? normalizeKeep(options.keep)
|
|
79
|
+
: this.defaults.keep,
|
|
80
|
+
delayMs: options?.delay !== undefined
|
|
81
|
+
? Duration.toMillis(options.delay)
|
|
82
|
+
: this.defaults.delayMs
|
|
83
|
+
}))), Effect.orDie, Effect.map((result) => result.id));
|
|
84
|
+
}).pipe(Effect.withSpan(`${this._tag}.enqueue`, {}, { captureStackTrace: false }));
|
|
85
|
+
},
|
|
86
|
+
poll(jobId) {
|
|
87
|
+
const self = this;
|
|
88
|
+
return Effect.flatMap(this.store, (store) => store.getJob(jobId).pipe(Effect.orDie, Effect.flatMap(Option.match({
|
|
89
|
+
onNone: () => Effect.succeedNone,
|
|
90
|
+
onSome: (record) => Effect.gen(function* () {
|
|
91
|
+
const exit = record.exit === undefined
|
|
92
|
+
? Option.none()
|
|
93
|
+
: Option.some(yield* Schema.decodeUnknownEffect(self.exitSchema)(record.exit).pipe(Effect.orDie));
|
|
94
|
+
return Option.some({
|
|
95
|
+
state: record.state,
|
|
96
|
+
attemptsMade: record.attemptsMade,
|
|
97
|
+
metadata: record.metadata,
|
|
98
|
+
exit,
|
|
99
|
+
failedReason: record.failedReason
|
|
100
|
+
});
|
|
101
|
+
})
|
|
102
|
+
})))).pipe(Effect.withSpan(`${this._tag}.poll`, { attributes: { jobId } }, { captureStackTrace: false }));
|
|
103
|
+
},
|
|
104
|
+
attempts(jobId) {
|
|
105
|
+
const self = this;
|
|
106
|
+
return Effect.flatMap(this.store, (store) => store.getAttempts(jobId).pipe(Effect.orDie, Effect.flatMap(Effect.forEach((attempt) => Effect.map(attempt.exit === undefined
|
|
107
|
+
? Effect.succeedNone
|
|
108
|
+
: Schema.decodeUnknownEffect(self.exitSchema)(attempt.exit).pipe(Effect.orDie, Effect.map(Option.some)), (exit) => ({
|
|
109
|
+
attempt: attempt.attempt,
|
|
110
|
+
startedAt: attempt.startedAt,
|
|
111
|
+
finishedAt: attempt.finishedAt,
|
|
112
|
+
outcome: attempt.outcome,
|
|
113
|
+
exit
|
|
114
|
+
})))))).pipe(Effect.withSpan(`${this._tag}.attempts`, { attributes: { jobId } }, { captureStackTrace: false }));
|
|
115
|
+
},
|
|
116
|
+
awaitResult(jobId, options) {
|
|
117
|
+
const self = this;
|
|
118
|
+
return Effect.gen(function* () {
|
|
119
|
+
const schedule = options?.pollSchedule ?? defaultPollSchedule;
|
|
120
|
+
let sleep;
|
|
121
|
+
while (true) {
|
|
122
|
+
const status = yield* self.poll(jobId);
|
|
123
|
+
if (Option.isNone(status)) {
|
|
124
|
+
return yield* Effect.die(new JobNotFoundError({ jobId }));
|
|
125
|
+
}
|
|
126
|
+
const { exit, failedReason, state } = status.value;
|
|
127
|
+
if (state === "completed" || state === "failed") {
|
|
128
|
+
if (Option.isSome(exit)) {
|
|
129
|
+
return yield* exit.value;
|
|
130
|
+
}
|
|
131
|
+
return yield* Effect.die(new Error(`effect-mq: job "${jobId}" failed without a result${failedReason === undefined ? "" : `: ${failedReason}`}`));
|
|
132
|
+
}
|
|
133
|
+
sleep ??= (yield* Schedule.toStepWithSleep(schedule))(void 0).pipe(Effect.catch(() => Effect.die(`${self._tag}.awaitResult: poll schedule exhausted`)));
|
|
134
|
+
yield* sleep;
|
|
135
|
+
}
|
|
136
|
+
}).pipe(Effect.withSpan(`${this._tag}.awaitResult`, { attributes: { jobId } }, { captureStackTrace: false }));
|
|
137
|
+
},
|
|
138
|
+
execute(fields, options) {
|
|
139
|
+
return Effect.flatMap(this.enqueue(fields, options), (jobId) => this.awaitResult(jobId));
|
|
140
|
+
},
|
|
141
|
+
retry(jobId) {
|
|
142
|
+
return Effect.flatMap(this.store, (store) => store.retry(jobId).pipe(Effect.catchTag("JobStoreError", (error) => Effect.die(error)))).pipe(Effect.withSpan(`${this._tag}.retry`, { attributes: { jobId } }, { captureStackTrace: false }));
|
|
143
|
+
},
|
|
144
|
+
toLayer(handler, options) {
|
|
145
|
+
return Layer.effectDiscard(Effect.flatMap(Worker, (worker) => worker.register(this, handler, options)));
|
|
146
|
+
}
|
|
147
|
+
};
|
|
148
|
+
const boundMethods = [
|
|
149
|
+
"enqueue",
|
|
150
|
+
"poll",
|
|
151
|
+
"attempts",
|
|
152
|
+
"awaitResult",
|
|
153
|
+
"execute",
|
|
154
|
+
"retry",
|
|
155
|
+
"toLayer"
|
|
156
|
+
];
|
|
157
|
+
const makeProto = (options) => {
|
|
158
|
+
function JobDefinition() { }
|
|
159
|
+
Object.setPrototypeOf(JobDefinition, Proto);
|
|
160
|
+
Object.assign(JobDefinition, options);
|
|
161
|
+
// Cosmetic only (job identity is `_tag`): function `name` is read-only for
|
|
162
|
+
// assignment but configurable.
|
|
163
|
+
Object.defineProperty(JobDefinition, "name", { value: options._tag, configurable: true });
|
|
164
|
+
// Bind the API as own properties so methods survive destructuring
|
|
165
|
+
// (`const { enqueue } = MyJob`) and passing as values.
|
|
166
|
+
for (const key of boundMethods) {
|
|
167
|
+
// SAFETY: every entry in `boundMethods` is a `this`-dependent function on
|
|
168
|
+
// `Proto`; binding only fixes the receiver. The precise signatures are
|
|
169
|
+
// re-declared by the public `Job` interface.
|
|
170
|
+
const method = Proto[key];
|
|
171
|
+
Object.defineProperty(JobDefinition, key, {
|
|
172
|
+
value: method.bind(JobDefinition),
|
|
173
|
+
configurable: true
|
|
174
|
+
});
|
|
175
|
+
}
|
|
176
|
+
return JobDefinition;
|
|
177
|
+
};
|
|
178
|
+
/**
|
|
179
|
+
* Define a job.
|
|
180
|
+
*
|
|
181
|
+
* @since 0.1.0
|
|
182
|
+
*/
|
|
183
|
+
export const make = (name, options) => {
|
|
184
|
+
// SAFETY: `Schema.isSchema` discriminates the `Payload` union at runtime;
|
|
185
|
+
// TypeScript cannot narrow an unresolved generic, so each branch asserts
|
|
186
|
+
// the side the guard just proved.
|
|
187
|
+
const payloadSchema = Schema.isSchema(options.payload)
|
|
188
|
+
? options.payload
|
|
189
|
+
: Schema.Struct(options.payload);
|
|
190
|
+
const successSchema = options.success ?? Schema.Void;
|
|
191
|
+
const errorSchema = options.error ?? Schema.Never;
|
|
192
|
+
// Wrapping the whole Exit schema in the JSON codec makes the *encoded* side
|
|
193
|
+
// plain JSON (a live Exit/Cause instance would not survive serializing
|
|
194
|
+
// drivers like Redis/Postgres).
|
|
195
|
+
const exitSchema = Schema.toCodecJson(Schema.Exit(Schema.toCodecJson(successSchema), Schema.toCodecJson(errorSchema), Schema.Defect()));
|
|
196
|
+
return makeProto({
|
|
197
|
+
_tag: name,
|
|
198
|
+
queue: QueueName(options.queue ?? "default"),
|
|
199
|
+
store: options.store ?? JobStore,
|
|
200
|
+
payloadSchema,
|
|
201
|
+
payloadJsonSchema: Schema.toCodecJson(payloadSchema),
|
|
202
|
+
successSchema,
|
|
203
|
+
errorSchema,
|
|
204
|
+
exitSchema,
|
|
205
|
+
idempotencyKey: options.idempotencyKey,
|
|
206
|
+
metadata: options.metadata,
|
|
207
|
+
defaults: {
|
|
208
|
+
delayMs: options.defaults?.delay !== undefined
|
|
209
|
+
? Duration.toMillis(options.defaults.delay)
|
|
210
|
+
: 0,
|
|
211
|
+
priority: options.defaults?.priority ?? 0,
|
|
212
|
+
attempts: Math.max(1, options.defaults?.attempts ?? 1),
|
|
213
|
+
backoff: normalizeBackoff(options.defaults?.backoff),
|
|
214
|
+
keep: normalizeKeep(options.defaults?.keep)
|
|
215
|
+
}
|
|
216
|
+
});
|
|
217
|
+
};
|
|
218
|
+
//# sourceMappingURL=Job.js.map
|
package/dist/Job.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Job.js","sourceRoot":"","sources":["../src/Job.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,401 @@
|
|
|
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, type Effect, type Option } from "effect";
|
|
20
|
+
/**
|
|
21
|
+
* The identifier of an enqueued job. Produced by `enqueue` (either
|
|
22
|
+
* store-assigned or derived from a custom id / idempotency key).
|
|
23
|
+
*
|
|
24
|
+
* @since 0.1.0
|
|
25
|
+
*/
|
|
26
|
+
export type JobId = Brand.Branded<string, "effect-mq/JobId">;
|
|
27
|
+
/**
|
|
28
|
+
* Brand a raw string as a `JobId`.
|
|
29
|
+
*
|
|
30
|
+
* @since 0.1.0
|
|
31
|
+
*/
|
|
32
|
+
export declare const JobId: Brand.Constructor<JobId>;
|
|
33
|
+
/**
|
|
34
|
+
* The name of a queue.
|
|
35
|
+
*
|
|
36
|
+
* @since 0.1.0
|
|
37
|
+
*/
|
|
38
|
+
export type QueueName = Brand.Branded<string, "effect-mq/QueueName">;
|
|
39
|
+
/**
|
|
40
|
+
* Brand a raw string as a `QueueName`.
|
|
41
|
+
*
|
|
42
|
+
* @since 0.1.0
|
|
43
|
+
*/
|
|
44
|
+
export declare const QueueName: Brand.Constructor<QueueName>;
|
|
45
|
+
/**
|
|
46
|
+
* The lifecycle states of a job.
|
|
47
|
+
*
|
|
48
|
+
* - `waiting`: runnable now, ordered by (priority desc, enqueue order asc)
|
|
49
|
+
* - `delayed`: must not run before `runAt`
|
|
50
|
+
* - `active`: claimed by a worker holding a lock token
|
|
51
|
+
* - `completed` / `failed`: terminal, with an encoded `Exit` stored
|
|
52
|
+
*
|
|
53
|
+
* @since 0.1.0
|
|
54
|
+
*/
|
|
55
|
+
export type JobState = "waiting" | "delayed" | "active" | "completed" | "failed";
|
|
56
|
+
/**
|
|
57
|
+
* Retry backoff policy, persisted on the job record so any worker can route
|
|
58
|
+
* retries consistently. Delay for attempt `n` (1-based):
|
|
59
|
+
*
|
|
60
|
+
* - `fixed`: `delayMs`
|
|
61
|
+
* - `exponential`: `delayMs * factor ** (n - 1)` (factor defaults to 2)
|
|
62
|
+
*
|
|
63
|
+
* @since 0.1.0
|
|
64
|
+
*/
|
|
65
|
+
export interface BackoffPolicy {
|
|
66
|
+
readonly _tag: "fixed" | "exponential";
|
|
67
|
+
readonly delayMs: number;
|
|
68
|
+
readonly factor?: number | undefined;
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Retention policy for terminal (completed/failed) jobs, persisted on the
|
|
72
|
+
* record. Applied by the store after terminal acks, scoped to jobs with the
|
|
73
|
+
* same name and state. Default (undefined) keeps records forever.
|
|
74
|
+
*
|
|
75
|
+
* @since 0.1.0
|
|
76
|
+
*/
|
|
77
|
+
export interface KeepPolicy {
|
|
78
|
+
/** Keep at most this many terminal records (per name + state). */
|
|
79
|
+
readonly count?: number | undefined;
|
|
80
|
+
/** Remove terminal records older than this many milliseconds. */
|
|
81
|
+
readonly ageMs?: number | undefined;
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* One run of a job, persisted so the full run history is durable and
|
|
85
|
+
* inspectable — the storage-level analogue of `tapError` before a rerun,
|
|
86
|
+
* extended to successes. Attempt numbers are monotonic per job and survive
|
|
87
|
+
* `retry` (they are decoupled from the record's `attemptsMade` budget).
|
|
88
|
+
*
|
|
89
|
+
* @since 0.1.0
|
|
90
|
+
*/
|
|
91
|
+
export interface AttemptRecord {
|
|
92
|
+
/** 1-based, monotonic per job (= previous ledger length + 1). */
|
|
93
|
+
readonly attempt: number;
|
|
94
|
+
/** Claim time of this run (epoch millis). */
|
|
95
|
+
readonly startedAt: number | undefined;
|
|
96
|
+
/** Ack/recovery time of this run (epoch millis). */
|
|
97
|
+
readonly finishedAt: number;
|
|
98
|
+
readonly outcome: "completed" | "retried" | "failed" | "stalled";
|
|
99
|
+
/** Schema-encoded `Exit`; undefined for `stalled`. */
|
|
100
|
+
readonly exit: unknown;
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* A job as persisted by the store. `payload` and `exit` are schema-encoded
|
|
104
|
+
* (JSON-safe) values — the store never inspects them. The per-run ledger is
|
|
105
|
+
* fetched separately via `getAttempts` so listings stay cheap.
|
|
106
|
+
*
|
|
107
|
+
* @since 0.1.0
|
|
108
|
+
*/
|
|
109
|
+
export interface JobRecord {
|
|
110
|
+
readonly id: JobId;
|
|
111
|
+
readonly name: string;
|
|
112
|
+
readonly queue: QueueName;
|
|
113
|
+
readonly payload: unknown;
|
|
114
|
+
/** Flat, indexable projection of business context for querying/UIs. */
|
|
115
|
+
readonly metadata: Readonly<Record<string, string>>;
|
|
116
|
+
readonly state: JobState;
|
|
117
|
+
readonly priority: number;
|
|
118
|
+
/** Total attempts allowed (including the first run). */
|
|
119
|
+
readonly attemptsMax: number;
|
|
120
|
+
/** Attempts consumed in the current budget (reset by `retry`). */
|
|
121
|
+
readonly attemptsMade: number;
|
|
122
|
+
readonly stalledCount: number;
|
|
123
|
+
readonly backoff: BackoffPolicy | undefined;
|
|
124
|
+
readonly keep: KeepPolicy | undefined;
|
|
125
|
+
/** Epoch millis before which the job must not be claimed. */
|
|
126
|
+
readonly runAt: number;
|
|
127
|
+
readonly enqueuedAt: number;
|
|
128
|
+
readonly processedAt: number | undefined;
|
|
129
|
+
readonly finishedAt: number | undefined;
|
|
130
|
+
/** Schema-encoded `Exit`, present for completed/failed jobs. */
|
|
131
|
+
readonly exit: unknown;
|
|
132
|
+
/** Set when the store itself failed the job (e.g. exceeded stall limit). */
|
|
133
|
+
readonly failedReason: string | undefined;
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* @since 0.1.0
|
|
137
|
+
*/
|
|
138
|
+
export interface EnqueueRequest {
|
|
139
|
+
/**
|
|
140
|
+
* Custom/idempotency id. When a job with this id already exists (in any
|
|
141
|
+
* state), the request is a no-op and the result has `duplicate: true`.
|
|
142
|
+
* When `undefined` the store assigns a unique id.
|
|
143
|
+
*/
|
|
144
|
+
readonly id: JobId | undefined;
|
|
145
|
+
readonly name: string;
|
|
146
|
+
readonly queue: QueueName;
|
|
147
|
+
readonly payload: unknown;
|
|
148
|
+
readonly metadata: Readonly<Record<string, string>>;
|
|
149
|
+
readonly priority: number;
|
|
150
|
+
readonly attemptsMax: number;
|
|
151
|
+
readonly backoff: BackoffPolicy | undefined;
|
|
152
|
+
readonly keep: KeepPolicy | undefined;
|
|
153
|
+
readonly delayMs: number;
|
|
154
|
+
}
|
|
155
|
+
/**
|
|
156
|
+
* @since 0.1.0
|
|
157
|
+
*/
|
|
158
|
+
export interface EnqueueResult {
|
|
159
|
+
readonly id: JobId;
|
|
160
|
+
/** True when a job with this id already existed; nothing was modified. */
|
|
161
|
+
readonly duplicate: boolean;
|
|
162
|
+
}
|
|
163
|
+
/**
|
|
164
|
+
* @since 0.1.0
|
|
165
|
+
*/
|
|
166
|
+
export interface ClaimOptions {
|
|
167
|
+
readonly queue: QueueName;
|
|
168
|
+
/** Only jobs with these names may be claimed (the worker's registered handlers). */
|
|
169
|
+
readonly names: ReadonlyArray<string>;
|
|
170
|
+
/** Worker-generated lock token; all subsequent acks must present it. */
|
|
171
|
+
readonly token: string;
|
|
172
|
+
readonly lockDurationMs: number;
|
|
173
|
+
}
|
|
174
|
+
/**
|
|
175
|
+
* Result of a claim attempt. `Empty.nextRunAt` is the earliest `runAt` among
|
|
176
|
+
* matching delayed jobs (so the worker knows how long to sleep), and
|
|
177
|
+
* `wakeToken` is an opaque cursor for `awaitWake` so wake-ups that happen
|
|
178
|
+
* between the claim and the wait are not lost.
|
|
179
|
+
*
|
|
180
|
+
* @since 0.1.0
|
|
181
|
+
*/
|
|
182
|
+
export type ClaimResult = {
|
|
183
|
+
readonly _tag: "Claimed";
|
|
184
|
+
readonly job: JobRecord;
|
|
185
|
+
} | {
|
|
186
|
+
readonly _tag: "Empty";
|
|
187
|
+
readonly nextRunAt: number | undefined;
|
|
188
|
+
readonly wakeToken: number;
|
|
189
|
+
};
|
|
190
|
+
/**
|
|
191
|
+
* How a worker acknowledges a claimed job. Retry routing (backoff delay,
|
|
192
|
+
* attempts accounting) is computed by the worker; the store only applies it.
|
|
193
|
+
*
|
|
194
|
+
* Every outcome appends an `AttemptRecord` to the job's ledger (`Complete` →
|
|
195
|
+
* completed, `Retry` → retried, `Fail` → failed).
|
|
196
|
+
*
|
|
197
|
+
* @since 0.1.0
|
|
198
|
+
*/
|
|
199
|
+
export type AckOutcome = {
|
|
200
|
+
readonly _tag: "Complete";
|
|
201
|
+
readonly exit: unknown;
|
|
202
|
+
} | {
|
|
203
|
+
readonly _tag: "Retry";
|
|
204
|
+
readonly delayMs: number;
|
|
205
|
+
readonly exit: unknown;
|
|
206
|
+
} | {
|
|
207
|
+
readonly _tag: "Fail";
|
|
208
|
+
readonly exit: unknown;
|
|
209
|
+
};
|
|
210
|
+
/**
|
|
211
|
+
* Filters and pagination for `list`. Results are ordered newest-first
|
|
212
|
+
* (`enqueuedAt` desc, then id desc); pass the returned `cursor` back to get
|
|
213
|
+
* the next page.
|
|
214
|
+
*
|
|
215
|
+
* @since 0.1.0
|
|
216
|
+
*/
|
|
217
|
+
export interface ListOptions {
|
|
218
|
+
readonly queue?: QueueName | undefined;
|
|
219
|
+
readonly name?: string | undefined;
|
|
220
|
+
readonly states?: ReadonlyArray<JobState> | undefined;
|
|
221
|
+
/** Every entry must match the record's metadata exactly (AND semantics). */
|
|
222
|
+
readonly metadata?: Readonly<Record<string, string>> | undefined;
|
|
223
|
+
readonly cursor?: string | undefined;
|
|
224
|
+
/** Page size; default 50. */
|
|
225
|
+
readonly limit?: number | undefined;
|
|
226
|
+
}
|
|
227
|
+
/**
|
|
228
|
+
* @since 0.1.0
|
|
229
|
+
*/
|
|
230
|
+
export interface ListResult {
|
|
231
|
+
readonly items: ReadonlyArray<JobRecord>;
|
|
232
|
+
/** Present when more items may exist; pass back via `ListOptions.cursor`. */
|
|
233
|
+
readonly cursor: string | undefined;
|
|
234
|
+
}
|
|
235
|
+
declare const JobStoreError_base: new <A extends Record<string, any> = {}>(args: import("effect/Types").VoidIfEmpty<{ readonly [P in keyof A as P extends "_tag" ? never : P]: A[P]; }>) => import("effect/Cause").YieldableError & {
|
|
236
|
+
readonly _tag: "JobStoreError";
|
|
237
|
+
} & Readonly<A>;
|
|
238
|
+
/**
|
|
239
|
+
* A transient or fatal driver error (connection loss, serialization, etc.).
|
|
240
|
+
*
|
|
241
|
+
* @since 0.1.0
|
|
242
|
+
*/
|
|
243
|
+
export declare class JobStoreError extends JobStoreError_base<{
|
|
244
|
+
readonly message: string;
|
|
245
|
+
readonly cause?: unknown;
|
|
246
|
+
}> {
|
|
247
|
+
}
|
|
248
|
+
/**
|
|
249
|
+
* Tag-based guard (safe across duplicate module copies, unlike `instanceof`).
|
|
250
|
+
*
|
|
251
|
+
* @since 0.1.0
|
|
252
|
+
*/
|
|
253
|
+
export declare const isJobStoreError: (u: unknown) => u is JobStoreError;
|
|
254
|
+
declare const LockLostError_base: new <A extends Record<string, any> = {}>(args: import("effect/Types").VoidIfEmpty<{ readonly [P in keyof A as P extends "_tag" ? never : P]: A[P]; }>) => import("effect/Cause").YieldableError & {
|
|
255
|
+
readonly _tag: "LockLostError";
|
|
256
|
+
} & Readonly<A>;
|
|
257
|
+
/**
|
|
258
|
+
* The presented lock token no longer owns the job (it stalled and was
|
|
259
|
+
* recovered, or another worker claimed it).
|
|
260
|
+
*
|
|
261
|
+
* @since 0.1.0
|
|
262
|
+
*/
|
|
263
|
+
export declare class LockLostError extends LockLostError_base<{
|
|
264
|
+
readonly jobId: JobId;
|
|
265
|
+
}> {
|
|
266
|
+
}
|
|
267
|
+
declare const JobNotFoundError_base: new <A extends Record<string, any> = {}>(args: import("effect/Types").VoidIfEmpty<{ readonly [P in keyof A as P extends "_tag" ? never : P]: A[P]; }>) => import("effect/Cause").YieldableError & {
|
|
268
|
+
readonly _tag: "JobNotFoundError";
|
|
269
|
+
} & Readonly<A>;
|
|
270
|
+
/**
|
|
271
|
+
* @since 0.1.0
|
|
272
|
+
*/
|
|
273
|
+
export declare class JobNotFoundError extends JobNotFoundError_base<{
|
|
274
|
+
readonly jobId: JobId;
|
|
275
|
+
}> {
|
|
276
|
+
}
|
|
277
|
+
declare const JobNotRetryableError_base: new <A extends Record<string, any> = {}>(args: import("effect/Types").VoidIfEmpty<{ readonly [P in keyof A as P extends "_tag" ? never : P]: A[P]; }>) => import("effect/Cause").YieldableError & {
|
|
278
|
+
readonly _tag: "JobNotRetryableError";
|
|
279
|
+
} & Readonly<A>;
|
|
280
|
+
/**
|
|
281
|
+
* `retry` was called on a job that is not in the `failed` state.
|
|
282
|
+
*
|
|
283
|
+
* @since 0.1.0
|
|
284
|
+
*/
|
|
285
|
+
export declare class JobNotRetryableError extends JobNotRetryableError_base<{
|
|
286
|
+
readonly jobId: JobId;
|
|
287
|
+
readonly state: JobState;
|
|
288
|
+
}> {
|
|
289
|
+
}
|
|
290
|
+
/**
|
|
291
|
+
* The service shape every store implements.
|
|
292
|
+
*
|
|
293
|
+
* @since 0.1.0
|
|
294
|
+
*/
|
|
295
|
+
export interface Service {
|
|
296
|
+
/**
|
|
297
|
+
* Insert a job. Routing: `delayMs > 0` lands in `delayed`, otherwise
|
|
298
|
+
* `waiting`. Duplicate ids are a silent no-op (see `EnqueueRequest.id`).
|
|
299
|
+
*/
|
|
300
|
+
readonly enqueue: (request: EnqueueRequest) => Effect.Effect<EnqueueResult, JobStoreError>;
|
|
301
|
+
/**
|
|
302
|
+
* Atomically: promote due delayed jobs, then claim the best runnable job
|
|
303
|
+
* matching `queue` + `names` (highest priority first, FIFO within a
|
|
304
|
+
* priority), locking it with `token` for `lockDurationMs`.
|
|
305
|
+
*/
|
|
306
|
+
readonly claim: (options: ClaimOptions) => Effect.Effect<ClaimResult, JobStoreError>;
|
|
307
|
+
/**
|
|
308
|
+
* Acknowledge a claimed job. Verifies the lock token, releases the lock,
|
|
309
|
+
* increments `attemptsMade`, appends to the attempts ledger, then applies
|
|
310
|
+
* the outcome (`Complete`/`Fail` are terminal and apply the record's `keep`
|
|
311
|
+
* policy; `Retry` re-queues after `delayMs`).
|
|
312
|
+
*/
|
|
313
|
+
readonly ack: (id: JobId, token: string, outcome: AckOutcome) => Effect.Effect<void, JobStoreError | JobNotFoundError | LockLostError>;
|
|
314
|
+
/**
|
|
315
|
+
* Return a claimed job to `waiting` without consuming an attempt or
|
|
316
|
+
* recording a ledger entry (used on worker shutdown).
|
|
317
|
+
*/
|
|
318
|
+
readonly release: (id: JobId, token: string) => Effect.Effect<void, JobStoreError | JobNotFoundError | LockLostError>;
|
|
319
|
+
/**
|
|
320
|
+
* Heartbeat: extend the given locks. Returns the ids whose lock could NOT
|
|
321
|
+
* be extended (lost to stall recovery or another worker).
|
|
322
|
+
*/
|
|
323
|
+
readonly extendLocks: (locks: ReadonlyArray<{
|
|
324
|
+
readonly id: JobId;
|
|
325
|
+
readonly token: string;
|
|
326
|
+
}>, durationMs: number) => Effect.Effect<ReadonlyArray<JobId>, JobStoreError>;
|
|
327
|
+
/**
|
|
328
|
+
* Sweep active jobs whose lock has expired. Each recovered job gets
|
|
329
|
+
* `stalledCount + 1` and a `stalled` ledger entry; jobs exceeding
|
|
330
|
+
* `maxStalledCount` are failed (`failed: true` in the result), the rest
|
|
331
|
+
* return to `waiting`.
|
|
332
|
+
*/
|
|
333
|
+
readonly recoverStalled: (options: {
|
|
334
|
+
readonly maxStalledCount: number;
|
|
335
|
+
}) => Effect.Effect<ReadonlyArray<{
|
|
336
|
+
readonly id: JobId;
|
|
337
|
+
readonly failed: boolean;
|
|
338
|
+
}>, JobStoreError>;
|
|
339
|
+
/**
|
|
340
|
+
* Resolve when new work *may* be runnable for the given queues since the
|
|
341
|
+
* `wakeToken` observed by a previous `claim`. Spurious wake-ups are fine;
|
|
342
|
+
* callers must combine with their own timeout. Must be interruptible.
|
|
343
|
+
* Polling-only drivers may never resolve.
|
|
344
|
+
*/
|
|
345
|
+
readonly awaitWake: (queues: ReadonlyArray<QueueName>, wakeToken: number) => Effect.Effect<void, JobStoreError>;
|
|
346
|
+
readonly getJob: (id: JobId) => Effect.Effect<Option.Option<JobRecord>, JobStoreError>;
|
|
347
|
+
/** The job's run ledger, oldest first. Empty for unknown ids. */
|
|
348
|
+
readonly getAttempts: (id: JobId) => Effect.Effect<ReadonlyArray<AttemptRecord>, JobStoreError>;
|
|
349
|
+
/** Query jobs (newest first) — the data layer for dashboards/UIs. */
|
|
350
|
+
readonly list: (options: ListOptions) => Effect.Effect<ListResult, JobStoreError>;
|
|
351
|
+
/**
|
|
352
|
+
* Re-run a failed job: back to `waiting` with a fresh attempt budget
|
|
353
|
+
* (`attemptsMade`/`stalledCount` reset, terminal fields cleared). The
|
|
354
|
+
* attempts ledger is preserved and keeps numbering monotonically.
|
|
355
|
+
*/
|
|
356
|
+
readonly retry: (id: JobId) => Effect.Effect<void, JobStoreError | JobNotFoundError | JobNotRetryableError>;
|
|
357
|
+
readonly counts: (queue?: QueueName) => Effect.Effect<Record<JobState, number>, JobStoreError>;
|
|
358
|
+
/** Remove a job (and its ledger). Refuses (returns false) when active. */
|
|
359
|
+
readonly remove: (id: JobId) => Effect.Effect<boolean, JobStoreError>;
|
|
360
|
+
}
|
|
361
|
+
declare const JobStore_base: Context.ServiceClass<JobStore, "effect-mq/JobStore", Service>;
|
|
362
|
+
/**
|
|
363
|
+
* The default store key. Jobs without an explicit `store` binding use this.
|
|
364
|
+
*
|
|
365
|
+
* @since 0.1.0
|
|
366
|
+
*/
|
|
367
|
+
export declare class JobStore extends JobStore_base {
|
|
368
|
+
}
|
|
369
|
+
/**
|
|
370
|
+
* Phantom identifier for a named store — appears in `R` so the type system
|
|
371
|
+
* enforces that the right store layer is provided.
|
|
372
|
+
*
|
|
373
|
+
* @since 0.1.0
|
|
374
|
+
*/
|
|
375
|
+
export interface Named<in out Name extends string> {
|
|
376
|
+
readonly "~effect-mq/JobStore/Named": Name;
|
|
377
|
+
}
|
|
378
|
+
/**
|
|
379
|
+
* Create a named store key. Jobs bound to it (via `Job.make`'s `store`
|
|
380
|
+
* option) require it in `R` instead of the default `JobStore`, letting
|
|
381
|
+
* different jobs run on different storage infrastructure:
|
|
382
|
+
*
|
|
383
|
+
* ```ts
|
|
384
|
+
* const Durable = JobStore.named("durable") // -> Postgres in prod
|
|
385
|
+
* const Ephemeral = JobStore.named("ephemeral") // -> Redis in prod
|
|
386
|
+
* ```
|
|
387
|
+
*
|
|
388
|
+
* Keys are identified by their name string: two `named("durable")` calls are
|
|
389
|
+
* interchangeable.
|
|
390
|
+
*
|
|
391
|
+
* @since 0.1.0
|
|
392
|
+
*/
|
|
393
|
+
export declare const named: <const Name extends string>(name: Name) => Context.Key<Named<Name>, Service>;
|
|
394
|
+
/**
|
|
395
|
+
* Any store key — the default `JobStore` or a `named` one.
|
|
396
|
+
*
|
|
397
|
+
* @since 0.1.0
|
|
398
|
+
*/
|
|
399
|
+
export type AnyKey = Context.Key<any, Service>;
|
|
400
|
+
export {};
|
|
401
|
+
//# sourceMappingURL=JobStore.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"JobStore.d.ts","sourceRoot":"","sources":["../src/JobStore.ts"],"names":[],"mappings":"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"}
|