effect-mq 0.5.0 → 0.7.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/README.md +85 -17
- package/dist/Flow.d.ts +381 -0
- package/dist/Flow.d.ts.map +1 -0
- package/dist/Flow.js +340 -0
- package/dist/Flow.js.map +1 -0
- package/dist/Job.d.ts +31 -6
- package/dist/Job.d.ts.map +1 -1
- package/dist/Job.js +16 -2
- package/dist/Job.js.map +1 -1
- package/dist/JobStore.d.ts +353 -13
- package/dist/JobStore.d.ts.map +1 -1
- package/dist/JobStore.js +10 -0
- package/dist/JobStore.js.map +1 -1
- package/dist/MemoryJobStore.d.ts.map +1 -1
- package/dist/MemoryJobStore.js +361 -21
- package/dist/MemoryJobStore.js.map +1 -1
- package/dist/Metrics.d.ts +31 -0
- package/dist/Metrics.d.ts.map +1 -1
- package/dist/Metrics.js +39 -0
- package/dist/Metrics.js.map +1 -1
- package/dist/Worker.d.ts +120 -11
- package/dist/Worker.d.ts.map +1 -1
- package/dist/Worker.js +452 -26
- package/dist/Worker.js.map +1 -1
- package/dist/drizzle-postgres/DrizzleJobStore.d.ts +19 -1
- package/dist/drizzle-postgres/DrizzleJobStore.d.ts.map +1 -1
- package/dist/drizzle-postgres/DrizzleJobStore.js +678 -80
- package/dist/drizzle-postgres/DrizzleJobStore.js.map +1 -1
- package/dist/drizzle-postgres/schema.d.ts +293 -3
- package/dist/drizzle-postgres/schema.d.ts.map +1 -1
- package/dist/drizzle-postgres/schema.js +66 -1
- package/dist/drizzle-postgres/schema.js.map +1 -1
- package/dist/index.d.ts +7 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +7 -0
- package/dist/index.js.map +1 -1
- package/dist/redis/RedisJobStore.d.ts +53 -0
- package/dist/redis/RedisJobStore.d.ts.map +1 -1
- package/dist/redis/RedisJobStore.js +402 -50
- package/dist/redis/RedisJobStore.js.map +1 -1
- package/dist/redis/scripts.d.ts +213 -35
- package/dist/redis/scripts.d.ts.map +1 -1
- package/dist/redis/scripts.js +689 -73
- package/dist/redis/scripts.js.map +1 -1
- package/dist/testing/conformance.d.ts +6 -0
- package/dist/testing/conformance.d.ts.map +1 -1
- package/dist/testing/conformance.js +855 -12
- package/dist/testing/conformance.js.map +1 -1
- package/package.json +1 -1
- package/src/Flow.ts +778 -0
- package/src/Job.ts +35 -11
- package/src/JobStore.ts +377 -12
- package/src/MemoryJobStore.ts +396 -25
- package/src/Metrics.ts +43 -0
- package/src/Worker.ts +726 -37
- package/src/drizzle-postgres/DrizzleJobStore.ts +844 -81
- package/src/drizzle-postgres/schema.ts +92 -0
- package/src/index.ts +8 -0
- package/src/redis/RedisJobStore.ts +540 -39
- package/src/redis/scripts.ts +751 -78
- package/src/testing/conformance.ts +1088 -12
|
@@ -36,6 +36,7 @@ import { sql } from "drizzle-orm"
|
|
|
36
36
|
import {
|
|
37
37
|
type AnyPgColumnBuilder,
|
|
38
38
|
bigint,
|
|
39
|
+
bigserial,
|
|
39
40
|
boolean,
|
|
40
41
|
index,
|
|
41
42
|
integer,
|
|
@@ -56,6 +57,10 @@ type BackoffPolicy = JobStore.BackoffPolicy
|
|
|
56
57
|
type KeepPolicy = JobStore.KeepPolicy
|
|
57
58
|
type AttemptOutcome = JobStore.AttemptRecord["outcome"]
|
|
58
59
|
type TraceContext = JobStore.TraceContext
|
|
60
|
+
type ParentEnvelope = JobStore.ParentEnvelope
|
|
61
|
+
type EnqueueRequest = JobStore.EnqueueRequest
|
|
62
|
+
type FlowChildStatus = JobStore.FlowChildRecord["status"]
|
|
63
|
+
type FlowChildReport = JobStore.FlowChildReport
|
|
59
64
|
|
|
60
65
|
/**
|
|
61
66
|
* Table-factory options: `extraConfig` receives the table's columns (exactly
|
|
@@ -89,6 +94,14 @@ const jobsColumns = <JobName extends string, Queue extends string>() => ({
|
|
|
89
94
|
cancelRequested: boolean("cancel_requested").notNull().default(false),
|
|
90
95
|
dedupeKey: text("dedupe_key"),
|
|
91
96
|
trace: jsonb("trace").$type<TraceContext>(),
|
|
97
|
+
/** Flow-parent link on child jobs (opaque envelope, like `trace`). */
|
|
98
|
+
parent: jsonb("parent").$type<ParentEnvelope>(),
|
|
99
|
+
/** Flow bookkeeping: NULL together until a FanOut ack lands the manifest. */
|
|
100
|
+
flowFailFast: boolean("flow_fail_fast"),
|
|
101
|
+
flowPending: integer("flow_pending"),
|
|
102
|
+
flowCompleted: integer("flow_completed"),
|
|
103
|
+
flowFailed: integer("flow_failed"),
|
|
104
|
+
flowCancelled: integer("flow_cancelled"),
|
|
92
105
|
runAt: timestamp("run_at", { withTimezone: true, mode: "date" }).notNull(),
|
|
93
106
|
enqueuedAt: timestamp("enqueued_at", { withTimezone: true, mode: "date" }).notNull(),
|
|
94
107
|
processedAt: timestamp("processed_at", { withTimezone: true, mode: "date" }),
|
|
@@ -245,6 +258,75 @@ export const mqDedupe = <JobName extends string = string>(
|
|
|
245
258
|
...options?.extraConfig?.(table) ?? []
|
|
246
259
|
])
|
|
247
260
|
|
|
261
|
+
const flowChildrenColumns = () => ({
|
|
262
|
+
/** The parent (flow) job's id in this store. */
|
|
263
|
+
flowId: text("flow_id").notNull().$type<JobId>(),
|
|
264
|
+
/** Unique within the flow (the idempotency mechanism). */
|
|
265
|
+
childKey: text("child_key").notNull(),
|
|
266
|
+
/** The child job's name (projection of `spec.name` for dashboards). */
|
|
267
|
+
name: text("name").notNull(),
|
|
268
|
+
/** The CHILD store's context-key string (children may live elsewhere). */
|
|
269
|
+
storeKey: text("store_key").notNull(),
|
|
270
|
+
/** The FULL `EnqueueRequest`, so the sweeper can re-enqueue from storage. */
|
|
271
|
+
spec: jsonb("spec").notNull().$type<EnqueueRequest>(),
|
|
272
|
+
status: text("status").notNull().$type<FlowChildStatus>(),
|
|
273
|
+
/** The child's schema-encoded exit; NULL for store-side failures. */
|
|
274
|
+
exit: jsonb("exit"),
|
|
275
|
+
failedReason: text("failed_reason"),
|
|
276
|
+
/** True once no cancel needs delivering into the child's store. */
|
|
277
|
+
cascaded: boolean("cascaded").notNull(),
|
|
278
|
+
pendingSince: timestamp("pending_since", { withTimezone: true, mode: "date" }).notNull()
|
|
279
|
+
})
|
|
280
|
+
|
|
281
|
+
/**
|
|
282
|
+
* Flow dependency rows (one per fan-out child; see `JobStore.FlowChildRecord`).
|
|
283
|
+
* Lives next to the PARENT store's jobs table.
|
|
284
|
+
*
|
|
285
|
+
* @since 0.6.0
|
|
286
|
+
*/
|
|
287
|
+
export const mqFlowChildren = (
|
|
288
|
+
tableName = "effect_mq_flow_children",
|
|
289
|
+
options?: MqTableOptions<ReturnType<typeof flowChildrenColumns>>
|
|
290
|
+
) =>
|
|
291
|
+
pgTable(tableName, flowChildrenColumns(), (table) => [
|
|
292
|
+
primaryKey({ columns: [table.flowId, table.childKey] }),
|
|
293
|
+
// flowSweepWork reconcile: pending rows older than the threshold.
|
|
294
|
+
index(`${tableName}_pending_idx`)
|
|
295
|
+
.on(table.pendingSince)
|
|
296
|
+
.where(sql`${table.status} = 'pending'`),
|
|
297
|
+
// flowSweepWork cascade: cancelled rows not yet delivered.
|
|
298
|
+
index(`${tableName}_cascade_idx`)
|
|
299
|
+
.on(table.flowId)
|
|
300
|
+
.where(sql`${table.status} = 'cancelled' AND NOT ${table.cascaded}`),
|
|
301
|
+
...options?.extraConfig?.(table) ?? []
|
|
302
|
+
])
|
|
303
|
+
|
|
304
|
+
const flowOutboxColumns = () => ({
|
|
305
|
+
/** Store-assigned, oldest-first; exposed to callers as an opaque string. */
|
|
306
|
+
id: bigserial("id", { mode: "number" }).primaryKey(),
|
|
307
|
+
/** The flow definition's name, for relay routing. */
|
|
308
|
+
flowName: text("flow_name").notNull(),
|
|
309
|
+
/** The PARENT store's context-key string, for relay routing. */
|
|
310
|
+
parentStoreKey: text("parent_store_key").notNull(),
|
|
311
|
+
/** The full `FlowChildReport` to deliver into the parent store. */
|
|
312
|
+
report: jsonb("report").notNull().$type<FlowChildReport>()
|
|
313
|
+
})
|
|
314
|
+
|
|
315
|
+
/**
|
|
316
|
+
* Undelivered child-result reports (one per terminal transition of an
|
|
317
|
+
* envelope-carrying job; see `JobStore.OutboxEntry`). Lives next to the
|
|
318
|
+
* CHILD store's jobs table.
|
|
319
|
+
*
|
|
320
|
+
* @since 0.6.0
|
|
321
|
+
*/
|
|
322
|
+
export const mqFlowOutbox = (
|
|
323
|
+
tableName = "effect_mq_flow_outbox",
|
|
324
|
+
options?: MqTableOptions<ReturnType<typeof flowOutboxColumns>>
|
|
325
|
+
) =>
|
|
326
|
+
pgTable(tableName, flowOutboxColumns(), (table) => [
|
|
327
|
+
...options?.extraConfig?.(table) ?? []
|
|
328
|
+
])
|
|
329
|
+
|
|
248
330
|
const queueControlColumns = <Queue extends string>() => ({
|
|
249
331
|
queue: text("queue").primaryKey().$type<Queue>(),
|
|
250
332
|
paused: boolean("paused").notNull().default(false)
|
|
@@ -287,3 +369,13 @@ export type MqQueueControlTable = ReturnType<typeof mqQueueControl<any>>
|
|
|
287
369
|
* @since 0.3.0
|
|
288
370
|
*/
|
|
289
371
|
export type MqDedupeTable = ReturnType<typeof mqDedupe<any>>
|
|
372
|
+
|
|
373
|
+
/**
|
|
374
|
+
* @since 0.6.0
|
|
375
|
+
*/
|
|
376
|
+
export type MqFlowChildrenTable = ReturnType<typeof mqFlowChildren>
|
|
377
|
+
|
|
378
|
+
/**
|
|
379
|
+
* @since 0.6.0
|
|
380
|
+
*/
|
|
381
|
+
export type MqFlowOutboxTable = ReturnType<typeof mqFlowOutbox>
|
package/src/index.ts
CHANGED
|
@@ -4,6 +4,14 @@
|
|
|
4
4
|
* @since 0.1.0
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
+
/**
|
|
8
|
+
* Cross-store parent-child flows: `Flow.make`, `Flow.children`, the
|
|
9
|
+
* two-phase `fanOut`/`collect` handler.
|
|
10
|
+
*
|
|
11
|
+
* @since 0.6.0
|
|
12
|
+
*/
|
|
13
|
+
export * as Flow from "./Flow.ts"
|
|
14
|
+
|
|
7
15
|
/**
|
|
8
16
|
* Schema-first job definitions: `Job.make`, `enqueue`, `toLayer`.
|
|
9
17
|
*
|