@effect/workflow 0.13.0 → 0.13.1

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,6 @@
1
+ {
2
+ "main": "../dist/cjs/DurableQueue.js",
3
+ "module": "../dist/esm/DurableQueue.js",
4
+ "types": "../dist/dts/DurableQueue.d.ts",
5
+ "sideEffects": []
6
+ }
@@ -0,0 +1,186 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.worker = exports.process = exports.makeWorker = exports.make = exports.TypeId = void 0;
7
+ var PersistedQueue = _interopRequireWildcard(require("@effect/experimental/PersistedQueue"));
8
+ var Context = _interopRequireWildcard(require("effect/Context"));
9
+ var Effect = _interopRequireWildcard(require("effect/Effect"));
10
+ var Layer = _interopRequireWildcard(require("effect/Layer"));
11
+ var Schedule = _interopRequireWildcard(require("effect/Schedule"));
12
+ var Schema = _interopRequireWildcard(require("effect/Schema"));
13
+ var Activity = _interopRequireWildcard(require("./Activity.js"));
14
+ var DurableDeferred = _interopRequireWildcard(require("./DurableDeferred.js"));
15
+ var _crypto = require("./internal/crypto.js");
16
+ function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function (e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != typeof e && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (const t in e) "default" !== t && {}.hasOwnProperty.call(e, t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, t)) && (i.get || i.set) ? o(f, t, i) : f[t] = e[t]); return f; })(e, t); }
17
+ /**
18
+ * @since 1.0.0
19
+ */
20
+
21
+ /**
22
+ * @since 1.0.0
23
+ * @category Type IDs
24
+ */
25
+ const TypeId = exports.TypeId = "~@effect/workflow/DurableQueue";
26
+ /**
27
+ * A `DurableQueue` wraps a `PersistedQueue`, providing a way to wait for items
28
+ * to finish processing using a `DurableDeferred`.
29
+ *
30
+ * ```ts
31
+ * import { DurableQueue, Workflow } from "@effect/workflow"
32
+ * import { Effect, Schema } from "effect"
33
+ *
34
+ * // Define a DurableQueue that can be used to derive workers and offer items for
35
+ * // processing.
36
+ * const ApiQueue = DurableQueue.make({
37
+ * name: "ApiQueue",
38
+ * payload: {
39
+ * id: Schema.String
40
+ * },
41
+ * success: Schema.Void,
42
+ * error: Schema.Never,
43
+ * idempotencyKey(payload) {
44
+ * return payload.id
45
+ * }
46
+ * })
47
+ *
48
+ * const MyWorkflow = Workflow.make({
49
+ * name: "MyWorkflow",
50
+ * payload: {
51
+ * id: Schema.String
52
+ * },
53
+ * idempotencyKey: ({ id }) => id
54
+ * })
55
+ *
56
+ * const MyWorkflowLayer = MyWorkflow.toLayer(
57
+ * Effect.fn(function*() {
58
+ * // Add an item to the DurableQueue defined above.
59
+ * //
60
+ * // When the worker has finished processing the item, the workflow will
61
+ * // resume.
62
+ * //
63
+ * yield* DurableQueue.process(ApiQueue, { id: "api-call-1" })
64
+ *
65
+ * yield* Effect.log("Workflow succeeded!")
66
+ * })
67
+ * )
68
+ *
69
+ * // Define a worker layer that can process items from the DurableQueue.
70
+ * const ApiWorker = DurableQueue.worker(
71
+ * ApiQueue,
72
+ * Effect.fn(function*({ id }) {
73
+ * yield* Effect.log(`Worker processing API call with id: ${id}`)
74
+ * }),
75
+ * { concurrency: 5 } // Process up to 5 items concurrently
76
+ * )
77
+ * ```
78
+ *
79
+ * @since 1.0.0
80
+ * @category Constructors
81
+ */
82
+ const make = options => ({
83
+ [TypeId]: TypeId,
84
+ name: options.name,
85
+ payloadSchema: Schema.isSchema(options.payload) ? options.payload : Schema.Struct(options.payload),
86
+ idempotencyKey: options.idempotencyKey,
87
+ deferred: DurableDeferred.make(`DurableQueue/${options.name}`, {
88
+ success: options.success,
89
+ error: options.error
90
+ })
91
+ });
92
+ exports.make = make;
93
+ const queueSchemas = /*#__PURE__*/new WeakMap();
94
+ const getQueueSchema = payload => {
95
+ let schema = queueSchemas.get(payload);
96
+ if (!schema) {
97
+ schema = Schema.Struct({
98
+ token: Schema.String,
99
+ traceId: Schema.String,
100
+ spanId: Schema.String,
101
+ sampled: Schema.Boolean,
102
+ payload
103
+ });
104
+ queueSchemas.set(payload, schema);
105
+ }
106
+ return schema;
107
+ };
108
+ /**
109
+ * @since 1.0.0
110
+ * @category Processing
111
+ */
112
+ const process = exports.process = /*#__PURE__*/Effect.fnUntraced(function* (self, payload, options) {
113
+ const key = yield* (0, _crypto.makeHashDigest)(self.idempotencyKey(payload));
114
+ const deferred = DurableDeferred.make(`${self.deferred.name}/${key}`, {
115
+ success: self.deferred.successSchema,
116
+ error: self.deferred.errorSchema
117
+ });
118
+ yield* Activity.make({
119
+ name: `DurableQueue/${self.name}/${key}`,
120
+ execute: Effect.gen(function* () {
121
+ const span = yield* Effect.orDie(Effect.currentSpan);
122
+ const queue = yield* PersistedQueue.make({
123
+ name: `DurableQueue/${self.name}`,
124
+ schema: getQueueSchema(self.payloadSchema)
125
+ });
126
+ const token = yield* DurableDeferred.token(deferred);
127
+ yield* queue.offer({
128
+ token,
129
+ payload,
130
+ traceId: span.traceId,
131
+ spanId: span.spanId,
132
+ sampled: span.sampled
133
+ }).pipe(Effect.tapErrorCause(Effect.logWarning), Effect.catchTag("ParseError", Effect.die), Effect.retry(options?.retrySchedule ?? defaultRetrySchedule), Effect.orDie, Effect.annotateLogs({
134
+ package: "@effect/workflow",
135
+ module: "DurableQueue",
136
+ fiber: "process",
137
+ queueName: self.name
138
+ }));
139
+ })
140
+ });
141
+ return yield* DurableDeferred.await(deferred);
142
+ });
143
+ const defaultRetrySchedule = /*#__PURE__*/Schedule.exponential(500, 1.5).pipe(/*#__PURE__*/Schedule.union(/*#__PURE__*/Schedule.spaced("1 minute")));
144
+ /**
145
+ * @since 1.0.0
146
+ * @category Worker
147
+ */
148
+ const makeWorker = exports.makeWorker = /*#__PURE__*/Effect.fnUntraced(function* (self, f, options) {
149
+ const queue = yield* PersistedQueue.make({
150
+ name: `DurableQueue/${self.name}`,
151
+ schema: getQueueSchema(self.payloadSchema)
152
+ });
153
+ const concurrency = options?.concurrency ?? 1;
154
+ const worker = queue.take(item_ => {
155
+ const item = item_;
156
+ return f(item.payload).pipe(Effect.exit, Effect.flatMap(exit => DurableDeferred.done(self.deferred, {
157
+ token: item.token,
158
+ exit
159
+ })), Effect.asVoid, Effect.withSpan(`DurableQueue/${self.name}/worker`, {
160
+ captureStackTrace: false,
161
+ parent: {
162
+ _tag: "ExternalSpan",
163
+ traceId: item.traceId,
164
+ spanId: item.spanId,
165
+ sampled: item.sampled,
166
+ context: Context.empty()
167
+ }
168
+ }));
169
+ }).pipe(Effect.catchAllCause(Effect.logWarning), Effect.forever, Effect.annotateLogs({
170
+ package: "@effect/workflow",
171
+ module: "DurableQueue",
172
+ fiber: "worker"
173
+ }));
174
+ yield* Effect.replicateEffect(worker, concurrency, {
175
+ concurrency,
176
+ discard: true
177
+ });
178
+ return yield* Effect.never;
179
+ });
180
+ /**
181
+ * @since 1.0.0
182
+ * @category Worker
183
+ */
184
+ const worker = (self, f, options) => Layer.scopedDiscard(Effect.forkScoped(makeWorker(self, f, options)));
185
+ exports.worker = worker;
186
+ //# sourceMappingURL=DurableQueue.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"DurableQueue.js","names":["PersistedQueue","_interopRequireWildcard","require","Context","Effect","Layer","Schedule","Schema","Activity","DurableDeferred","_crypto","e","t","WeakMap","r","n","__esModule","o","i","f","__proto__","default","has","get","set","hasOwnProperty","call","Object","defineProperty","getOwnPropertyDescriptor","TypeId","exports","make","options","name","payloadSchema","isSchema","payload","Struct","idempotencyKey","deferred","success","error","queueSchemas","getQueueSchema","schema","token","String","traceId","spanId","sampled","Boolean","process","fnUntraced","self","key","makeHashDigest","successSchema","errorSchema","execute","gen","span","orDie","currentSpan","queue","offer","pipe","tapErrorCause","logWarning","catchTag","die","retry","retrySchedule","defaultRetrySchedule","annotateLogs","package","module","fiber","queueName","await","exponential","union","spaced","makeWorker","concurrency","worker","take","item_","item","exit","flatMap","done","asVoid","withSpan","captureStackTrace","parent","_tag","context","empty","catchAllCause","forever","replicateEffect","discard","never","scopedDiscard","forkScoped"],"sources":["../../src/DurableQueue.ts"],"sourcesContent":[null],"mappings":"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","ignoreList":[]}
package/dist/cjs/index.js CHANGED
@@ -3,13 +3,15 @@
3
3
  Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
- exports.WorkflowProxyServer = exports.WorkflowProxy = exports.WorkflowEngine = exports.Workflow = exports.DurableRateLimiter = exports.DurableDeferred = exports.DurableClock = exports.Activity = void 0;
6
+ exports.WorkflowProxyServer = exports.WorkflowProxy = exports.WorkflowEngine = exports.Workflow = exports.DurableRateLimiter = exports.DurableQueue = exports.DurableDeferred = exports.DurableClock = exports.Activity = void 0;
7
7
  var _Activity = _interopRequireWildcard(require("./Activity.js"));
8
8
  exports.Activity = _Activity;
9
9
  var _DurableClock = _interopRequireWildcard(require("./DurableClock.js"));
10
10
  exports.DurableClock = _DurableClock;
11
11
  var _DurableDeferred = _interopRequireWildcard(require("./DurableDeferred.js"));
12
12
  exports.DurableDeferred = _DurableDeferred;
13
+ var _DurableQueue = _interopRequireWildcard(require("./DurableQueue.js"));
14
+ exports.DurableQueue = _DurableQueue;
13
15
  var _DurableRateLimiter = _interopRequireWildcard(require("./DurableRateLimiter.js"));
14
16
  exports.DurableRateLimiter = _DurableRateLimiter;
15
17
  var _Workflow = _interopRequireWildcard(require("./Workflow.js"));
@@ -0,0 +1,116 @@
1
+ /**
2
+ * @since 1.0.0
3
+ */
4
+ import * as PersistedQueue from "@effect/experimental/PersistedQueue";
5
+ import * as Effect from "effect/Effect";
6
+ import * as Layer from "effect/Layer";
7
+ import * as Schedule from "effect/Schedule";
8
+ import * as Schema from "effect/Schema";
9
+ import * as DurableDeferred from "./DurableDeferred.js";
10
+ import type * as WorkflowEngine from "./WorkflowEngine.js";
11
+ /**
12
+ * @since 1.0.0
13
+ * @category Type IDs
14
+ */
15
+ export type TypeId = "~@effect/workflow/DurableQueue";
16
+ /**
17
+ * @since 1.0.0
18
+ * @category Type IDs
19
+ */
20
+ export declare const TypeId: TypeId;
21
+ /**
22
+ * @since 1.0.0
23
+ * @category Models
24
+ */
25
+ export interface DurableQueue<Payload extends Schema.Schema.Any, Success extends Schema.Schema.Any = typeof Schema.Void, Error extends Schema.Schema.All = typeof Schema.Never> {
26
+ readonly [TypeId]: TypeId;
27
+ readonly name: string;
28
+ readonly payloadSchema: Payload;
29
+ readonly idempotencyKey: (payload: Payload["Type"]) => string;
30
+ readonly deferred: DurableDeferred.DurableDeferred<Success, Error>;
31
+ }
32
+ /**
33
+ * A `DurableQueue` wraps a `PersistedQueue`, providing a way to wait for items
34
+ * to finish processing using a `DurableDeferred`.
35
+ *
36
+ * ```ts
37
+ * import { DurableQueue, Workflow } from "@effect/workflow"
38
+ * import { Effect, Schema } from "effect"
39
+ *
40
+ * // Define a DurableQueue that can be used to derive workers and offer items for
41
+ * // processing.
42
+ * const ApiQueue = DurableQueue.make({
43
+ * name: "ApiQueue",
44
+ * payload: {
45
+ * id: Schema.String
46
+ * },
47
+ * success: Schema.Void,
48
+ * error: Schema.Never,
49
+ * idempotencyKey(payload) {
50
+ * return payload.id
51
+ * }
52
+ * })
53
+ *
54
+ * const MyWorkflow = Workflow.make({
55
+ * name: "MyWorkflow",
56
+ * payload: {
57
+ * id: Schema.String
58
+ * },
59
+ * idempotencyKey: ({ id }) => id
60
+ * })
61
+ *
62
+ * const MyWorkflowLayer = MyWorkflow.toLayer(
63
+ * Effect.fn(function*() {
64
+ * // Add an item to the DurableQueue defined above.
65
+ * //
66
+ * // When the worker has finished processing the item, the workflow will
67
+ * // resume.
68
+ * //
69
+ * yield* DurableQueue.process(ApiQueue, { id: "api-call-1" })
70
+ *
71
+ * yield* Effect.log("Workflow succeeded!")
72
+ * })
73
+ * )
74
+ *
75
+ * // Define a worker layer that can process items from the DurableQueue.
76
+ * const ApiWorker = DurableQueue.worker(
77
+ * ApiQueue,
78
+ * Effect.fn(function*({ id }) {
79
+ * yield* Effect.log(`Worker processing API call with id: ${id}`)
80
+ * }),
81
+ * { concurrency: 5 } // Process up to 5 items concurrently
82
+ * )
83
+ * ```
84
+ *
85
+ * @since 1.0.0
86
+ * @category Constructors
87
+ */
88
+ export declare const make: <Payload extends Schema.Schema.Any | Schema.Struct.Fields, Success extends Schema.Schema.Any = typeof Schema.Void, Error extends Schema.Schema.All = typeof Schema.Never>(options: {
89
+ readonly name: string;
90
+ readonly payload: Payload;
91
+ readonly idempotencyKey: (payload: Payload extends Schema.Struct.Fields ? Schema.Struct<Payload>["Type"] : Payload["Type"]) => string;
92
+ readonly success?: Success | undefined;
93
+ readonly error?: Error | undefined;
94
+ }) => DurableQueue<Payload extends Schema.Struct.Fields ? Schema.Struct<Payload> : Payload, Success, Error>;
95
+ /**
96
+ * @since 1.0.0
97
+ * @category Processing
98
+ */
99
+ export declare const process: <Payload extends Schema.Schema.Any, Success extends Schema.Schema.Any, Error extends Schema.Schema.All>(self: DurableQueue<Payload, Success, Error>, payload: Payload["Type"], options?: {
100
+ readonly retrySchedule?: Schedule.Schedule<any, PersistedQueue.PersistedQueueError> | undefined;
101
+ }) => Effect.Effect<Success["Type"], Error["Type"], WorkflowEngine.WorkflowEngine | WorkflowEngine.WorkflowInstance | PersistedQueue.PersistedQueueFactory | Success["Context"] | Error["Context"] | Payload["Context"]>;
102
+ /**
103
+ * @since 1.0.0
104
+ * @category Worker
105
+ */
106
+ export declare const makeWorker: <Payload extends Schema.Schema.Any, Success extends Schema.Schema.Any, Error extends Schema.Schema.All, R>(self: DurableQueue<Payload, Success, Error>, f: (payload: Payload["Type"]) => Effect.Effect<Success["Type"], Error["Type"], R>, options?: {
107
+ readonly concurrency?: number | undefined;
108
+ } | undefined) => Effect.Effect<never, never, WorkflowEngine.WorkflowEngine | PersistedQueue.PersistedQueueFactory | R | Payload["Context"] | Success["Context"] | Error["Context"]>;
109
+ /**
110
+ * @since 1.0.0
111
+ * @category Worker
112
+ */
113
+ export declare const worker: <Payload extends Schema.Schema.Any, Success extends Schema.Schema.Any, Error extends Schema.Schema.All, R>(self: DurableQueue<Payload, Success, Error>, f: (payload: Payload["Type"]) => Effect.Effect<Success["Type"], Error["Type"], R>, options?: {
114
+ readonly concurrency?: number | undefined;
115
+ } | undefined) => Layer.Layer<never, never, WorkflowEngine.WorkflowEngine | PersistedQueue.PersistedQueueFactory | R | Payload["Context"] | Success["Context"] | Error["Context"]>;
116
+ //# sourceMappingURL=DurableQueue.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"DurableQueue.d.ts","sourceRoot":"","sources":["../../src/DurableQueue.ts"],"names":[],"mappings":"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"}
@@ -10,6 +10,10 @@ export * as DurableClock from "./DurableClock.js";
10
10
  * @since 1.0.0
11
11
  */
12
12
  export * as DurableDeferred from "./DurableDeferred.js";
13
+ /**
14
+ * @since 1.0.0
15
+ */
16
+ export * as DurableQueue from "./DurableQueue.js";
13
17
  /**
14
18
  * @since 1.0.0
15
19
  */
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,OAAO,KAAK,QAAQ,MAAM,eAAe,CAAA;AAEzC;;GAEG;AACH,OAAO,KAAK,YAAY,MAAM,mBAAmB,CAAA;AAEjD;;GAEG;AACH,OAAO,KAAK,eAAe,MAAM,sBAAsB,CAAA;AAEvD;;GAEG;AACH,OAAO,KAAK,kBAAkB,MAAM,yBAAyB,CAAA;AAE7D;;GAEG;AACH,OAAO,KAAK,QAAQ,MAAM,eAAe,CAAA;AAEzC;;GAEG;AACH,OAAO,KAAK,cAAc,MAAM,qBAAqB,CAAA;AAErD;;GAEG;AACH,OAAO,KAAK,aAAa,MAAM,oBAAoB,CAAA;AAEnD;;GAEG;AACH,OAAO,KAAK,mBAAmB,MAAM,0BAA0B,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,OAAO,KAAK,QAAQ,MAAM,eAAe,CAAA;AAEzC;;GAEG;AACH,OAAO,KAAK,YAAY,MAAM,mBAAmB,CAAA;AAEjD;;GAEG;AACH,OAAO,KAAK,eAAe,MAAM,sBAAsB,CAAA;AAEvD;;GAEG;AACH,OAAO,KAAK,YAAY,MAAM,mBAAmB,CAAA;AAEjD;;GAEG;AACH,OAAO,KAAK,kBAAkB,MAAM,yBAAyB,CAAA;AAE7D;;GAEG;AACH,OAAO,KAAK,QAAQ,MAAM,eAAe,CAAA;AAEzC;;GAEG;AACH,OAAO,KAAK,cAAc,MAAM,qBAAqB,CAAA;AAErD;;GAEG;AACH,OAAO,KAAK,aAAa,MAAM,oBAAoB,CAAA;AAEnD;;GAEG;AACH,OAAO,KAAK,mBAAmB,MAAM,0BAA0B,CAAA"}
@@ -0,0 +1,176 @@
1
+ /**
2
+ * @since 1.0.0
3
+ */
4
+ import * as PersistedQueue from "@effect/experimental/PersistedQueue";
5
+ import * as Context from "effect/Context";
6
+ import * as Effect from "effect/Effect";
7
+ import * as Layer from "effect/Layer";
8
+ import * as Schedule from "effect/Schedule";
9
+ import * as Schema from "effect/Schema";
10
+ import * as Activity from "./Activity.js";
11
+ import * as DurableDeferred from "./DurableDeferred.js";
12
+ import { makeHashDigest } from "./internal/crypto.js";
13
+ /**
14
+ * @since 1.0.0
15
+ * @category Type IDs
16
+ */
17
+ export const TypeId = "~@effect/workflow/DurableQueue";
18
+ /**
19
+ * A `DurableQueue` wraps a `PersistedQueue`, providing a way to wait for items
20
+ * to finish processing using a `DurableDeferred`.
21
+ *
22
+ * ```ts
23
+ * import { DurableQueue, Workflow } from "@effect/workflow"
24
+ * import { Effect, Schema } from "effect"
25
+ *
26
+ * // Define a DurableQueue that can be used to derive workers and offer items for
27
+ * // processing.
28
+ * const ApiQueue = DurableQueue.make({
29
+ * name: "ApiQueue",
30
+ * payload: {
31
+ * id: Schema.String
32
+ * },
33
+ * success: Schema.Void,
34
+ * error: Schema.Never,
35
+ * idempotencyKey(payload) {
36
+ * return payload.id
37
+ * }
38
+ * })
39
+ *
40
+ * const MyWorkflow = Workflow.make({
41
+ * name: "MyWorkflow",
42
+ * payload: {
43
+ * id: Schema.String
44
+ * },
45
+ * idempotencyKey: ({ id }) => id
46
+ * })
47
+ *
48
+ * const MyWorkflowLayer = MyWorkflow.toLayer(
49
+ * Effect.fn(function*() {
50
+ * // Add an item to the DurableQueue defined above.
51
+ * //
52
+ * // When the worker has finished processing the item, the workflow will
53
+ * // resume.
54
+ * //
55
+ * yield* DurableQueue.process(ApiQueue, { id: "api-call-1" })
56
+ *
57
+ * yield* Effect.log("Workflow succeeded!")
58
+ * })
59
+ * )
60
+ *
61
+ * // Define a worker layer that can process items from the DurableQueue.
62
+ * const ApiWorker = DurableQueue.worker(
63
+ * ApiQueue,
64
+ * Effect.fn(function*({ id }) {
65
+ * yield* Effect.log(`Worker processing API call with id: ${id}`)
66
+ * }),
67
+ * { concurrency: 5 } // Process up to 5 items concurrently
68
+ * )
69
+ * ```
70
+ *
71
+ * @since 1.0.0
72
+ * @category Constructors
73
+ */
74
+ export const make = options => ({
75
+ [TypeId]: TypeId,
76
+ name: options.name,
77
+ payloadSchema: Schema.isSchema(options.payload) ? options.payload : Schema.Struct(options.payload),
78
+ idempotencyKey: options.idempotencyKey,
79
+ deferred: DurableDeferred.make(`DurableQueue/${options.name}`, {
80
+ success: options.success,
81
+ error: options.error
82
+ })
83
+ });
84
+ const queueSchemas = /*#__PURE__*/new WeakMap();
85
+ const getQueueSchema = payload => {
86
+ let schema = queueSchemas.get(payload);
87
+ if (!schema) {
88
+ schema = Schema.Struct({
89
+ token: Schema.String,
90
+ traceId: Schema.String,
91
+ spanId: Schema.String,
92
+ sampled: Schema.Boolean,
93
+ payload
94
+ });
95
+ queueSchemas.set(payload, schema);
96
+ }
97
+ return schema;
98
+ };
99
+ /**
100
+ * @since 1.0.0
101
+ * @category Processing
102
+ */
103
+ export const process = /*#__PURE__*/Effect.fnUntraced(function* (self, payload, options) {
104
+ const key = yield* makeHashDigest(self.idempotencyKey(payload));
105
+ const deferred = DurableDeferred.make(`${self.deferred.name}/${key}`, {
106
+ success: self.deferred.successSchema,
107
+ error: self.deferred.errorSchema
108
+ });
109
+ yield* Activity.make({
110
+ name: `DurableQueue/${self.name}/${key}`,
111
+ execute: Effect.gen(function* () {
112
+ const span = yield* Effect.orDie(Effect.currentSpan);
113
+ const queue = yield* PersistedQueue.make({
114
+ name: `DurableQueue/${self.name}`,
115
+ schema: getQueueSchema(self.payloadSchema)
116
+ });
117
+ const token = yield* DurableDeferred.token(deferred);
118
+ yield* queue.offer({
119
+ token,
120
+ payload,
121
+ traceId: span.traceId,
122
+ spanId: span.spanId,
123
+ sampled: span.sampled
124
+ }).pipe(Effect.tapErrorCause(Effect.logWarning), Effect.catchTag("ParseError", Effect.die), Effect.retry(options?.retrySchedule ?? defaultRetrySchedule), Effect.orDie, Effect.annotateLogs({
125
+ package: "@effect/workflow",
126
+ module: "DurableQueue",
127
+ fiber: "process",
128
+ queueName: self.name
129
+ }));
130
+ })
131
+ });
132
+ return yield* DurableDeferred.await(deferred);
133
+ });
134
+ const defaultRetrySchedule = /*#__PURE__*/Schedule.exponential(500, 1.5).pipe(/*#__PURE__*/Schedule.union(/*#__PURE__*/Schedule.spaced("1 minute")));
135
+ /**
136
+ * @since 1.0.0
137
+ * @category Worker
138
+ */
139
+ export const makeWorker = /*#__PURE__*/Effect.fnUntraced(function* (self, f, options) {
140
+ const queue = yield* PersistedQueue.make({
141
+ name: `DurableQueue/${self.name}`,
142
+ schema: getQueueSchema(self.payloadSchema)
143
+ });
144
+ const concurrency = options?.concurrency ?? 1;
145
+ const worker = queue.take(item_ => {
146
+ const item = item_;
147
+ return f(item.payload).pipe(Effect.exit, Effect.flatMap(exit => DurableDeferred.done(self.deferred, {
148
+ token: item.token,
149
+ exit
150
+ })), Effect.asVoid, Effect.withSpan(`DurableQueue/${self.name}/worker`, {
151
+ captureStackTrace: false,
152
+ parent: {
153
+ _tag: "ExternalSpan",
154
+ traceId: item.traceId,
155
+ spanId: item.spanId,
156
+ sampled: item.sampled,
157
+ context: Context.empty()
158
+ }
159
+ }));
160
+ }).pipe(Effect.catchAllCause(Effect.logWarning), Effect.forever, Effect.annotateLogs({
161
+ package: "@effect/workflow",
162
+ module: "DurableQueue",
163
+ fiber: "worker"
164
+ }));
165
+ yield* Effect.replicateEffect(worker, concurrency, {
166
+ concurrency,
167
+ discard: true
168
+ });
169
+ return yield* Effect.never;
170
+ });
171
+ /**
172
+ * @since 1.0.0
173
+ * @category Worker
174
+ */
175
+ export const worker = (self, f, options) => Layer.scopedDiscard(Effect.forkScoped(makeWorker(self, f, options)));
176
+ //# sourceMappingURL=DurableQueue.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"DurableQueue.js","names":["PersistedQueue","Context","Effect","Layer","Schedule","Schema","Activity","DurableDeferred","makeHashDigest","TypeId","make","options","name","payloadSchema","isSchema","payload","Struct","idempotencyKey","deferred","success","error","queueSchemas","WeakMap","getQueueSchema","schema","get","token","String","traceId","spanId","sampled","Boolean","set","process","fnUntraced","self","key","successSchema","errorSchema","execute","gen","span","orDie","currentSpan","queue","offer","pipe","tapErrorCause","logWarning","catchTag","die","retry","retrySchedule","defaultRetrySchedule","annotateLogs","package","module","fiber","queueName","await","exponential","union","spaced","makeWorker","f","concurrency","worker","take","item_","item","exit","flatMap","done","asVoid","withSpan","captureStackTrace","parent","_tag","context","empty","catchAllCause","forever","replicateEffect","discard","never","scopedDiscard","forkScoped"],"sources":["../../src/DurableQueue.ts"],"sourcesContent":[null],"mappings":"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","ignoreList":[]}
package/dist/esm/index.js CHANGED
@@ -10,6 +10,10 @@ export * as DurableClock from "./DurableClock.js";
10
10
  * @since 1.0.0
11
11
  */
12
12
  export * as DurableDeferred from "./DurableDeferred.js";
13
+ /**
14
+ * @since 1.0.0
15
+ */
16
+ export * as DurableQueue from "./DurableQueue.js";
13
17
  /**
14
18
  * @since 1.0.0
15
19
  */
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":["Activity","DurableClock","DurableDeferred","DurableRateLimiter","Workflow","WorkflowEngine","WorkflowProxy","WorkflowProxyServer"],"sources":["../../src/index.ts"],"sourcesContent":[null],"mappings":"AAAA;;;AAGA,OAAO,KAAKA,QAAQ,MAAM,eAAe;AAEzC;;;AAGA,OAAO,KAAKC,YAAY,MAAM,mBAAmB;AAEjD;;;AAGA,OAAO,KAAKC,eAAe,MAAM,sBAAsB;AAEvD;;;AAGA,OAAO,KAAKC,kBAAkB,MAAM,yBAAyB;AAE7D;;;AAGA,OAAO,KAAKC,QAAQ,MAAM,eAAe;AAEzC;;;AAGA,OAAO,KAAKC,cAAc,MAAM,qBAAqB;AAErD;;;AAGA,OAAO,KAAKC,aAAa,MAAM,oBAAoB;AAEnD;;;AAGA,OAAO,KAAKC,mBAAmB,MAAM,0BAA0B","ignoreList":[]}
1
+ {"version":3,"file":"index.js","names":["Activity","DurableClock","DurableDeferred","DurableQueue","DurableRateLimiter","Workflow","WorkflowEngine","WorkflowProxy","WorkflowProxyServer"],"sources":["../../src/index.ts"],"sourcesContent":[null],"mappings":"AAAA;;;AAGA,OAAO,KAAKA,QAAQ,MAAM,eAAe;AAEzC;;;AAGA,OAAO,KAAKC,YAAY,MAAM,mBAAmB;AAEjD;;;AAGA,OAAO,KAAKC,eAAe,MAAM,sBAAsB;AAEvD;;;AAGA,OAAO,KAAKC,YAAY,MAAM,mBAAmB;AAEjD;;;AAGA,OAAO,KAAKC,kBAAkB,MAAM,yBAAyB;AAE7D;;;AAGA,OAAO,KAAKC,QAAQ,MAAM,eAAe;AAEzC;;;AAGA,OAAO,KAAKC,cAAc,MAAM,qBAAqB;AAErD;;;AAGA,OAAO,KAAKC,aAAa,MAAM,oBAAoB;AAEnD;;;AAGA,OAAO,KAAKC,mBAAmB,MAAM,0BAA0B","ignoreList":[]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@effect/workflow",
3
- "version": "0.13.0",
3
+ "version": "0.13.1",
4
4
  "description": "Durable workflows for Effect",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -11,9 +11,9 @@
11
11
  "sideEffects": [],
12
12
  "homepage": "https://effect.website",
13
13
  "peerDependencies": {
14
- "effect": "^3.19.5",
15
- "@effect/experimental": "^0.57.3",
16
- "@effect/platform": "^0.93.3",
14
+ "effect": "^3.19.8",
15
+ "@effect/experimental": "^0.57.7",
16
+ "@effect/platform": "^0.93.5",
17
17
  "@effect/rpc": "^0.72.2"
18
18
  },
19
19
  "publishConfig": {
@@ -44,6 +44,11 @@
44
44
  "import": "./dist/esm/DurableDeferred.js",
45
45
  "default": "./dist/cjs/DurableDeferred.js"
46
46
  },
47
+ "./DurableQueue": {
48
+ "types": "./dist/dts/DurableQueue.d.ts",
49
+ "import": "./dist/esm/DurableQueue.js",
50
+ "default": "./dist/cjs/DurableQueue.js"
51
+ },
47
52
  "./DurableRateLimiter": {
48
53
  "types": "./dist/dts/DurableRateLimiter.d.ts",
49
54
  "import": "./dist/esm/DurableRateLimiter.js",
@@ -81,6 +86,9 @@
81
86
  "DurableDeferred": [
82
87
  "./dist/dts/DurableDeferred.d.ts"
83
88
  ],
89
+ "DurableQueue": [
90
+ "./dist/dts/DurableQueue.d.ts"
91
+ ],
84
92
  "DurableRateLimiter": [
85
93
  "./dist/dts/DurableRateLimiter.d.ts"
86
94
  ],
@@ -0,0 +1,332 @@
1
+ /**
2
+ * @since 1.0.0
3
+ */
4
+ import * as PersistedQueue from "@effect/experimental/PersistedQueue"
5
+ import * as Context from "effect/Context"
6
+ import * as Effect from "effect/Effect"
7
+ import * as Layer from "effect/Layer"
8
+ import * as Schedule from "effect/Schedule"
9
+ import * as Schema from "effect/Schema"
10
+ import * as Activity from "./Activity.js"
11
+ import * as DurableDeferred from "./DurableDeferred.js"
12
+ import { makeHashDigest } from "./internal/crypto.js"
13
+ import type * as WorkflowEngine from "./WorkflowEngine.js"
14
+
15
+ /**
16
+ * @since 1.0.0
17
+ * @category Type IDs
18
+ */
19
+ export type TypeId = "~@effect/workflow/DurableQueue"
20
+
21
+ /**
22
+ * @since 1.0.0
23
+ * @category Type IDs
24
+ */
25
+ export const TypeId: TypeId = "~@effect/workflow/DurableQueue"
26
+
27
+ /**
28
+ * @since 1.0.0
29
+ * @category Models
30
+ */
31
+ export interface DurableQueue<
32
+ Payload extends Schema.Schema.Any,
33
+ Success extends Schema.Schema.Any = typeof Schema.Void,
34
+ Error extends Schema.Schema.All = typeof Schema.Never
35
+ > {
36
+ readonly [TypeId]: TypeId
37
+ readonly name: string
38
+ readonly payloadSchema: Payload
39
+ readonly idempotencyKey: (payload: Payload["Type"]) => string
40
+ readonly deferred: DurableDeferred.DurableDeferred<Success, Error>
41
+ }
42
+
43
+ /**
44
+ * A `DurableQueue` wraps a `PersistedQueue`, providing a way to wait for items
45
+ * to finish processing using a `DurableDeferred`.
46
+ *
47
+ * ```ts
48
+ * import { DurableQueue, Workflow } from "@effect/workflow"
49
+ * import { Effect, Schema } from "effect"
50
+ *
51
+ * // Define a DurableQueue that can be used to derive workers and offer items for
52
+ * // processing.
53
+ * const ApiQueue = DurableQueue.make({
54
+ * name: "ApiQueue",
55
+ * payload: {
56
+ * id: Schema.String
57
+ * },
58
+ * success: Schema.Void,
59
+ * error: Schema.Never,
60
+ * idempotencyKey(payload) {
61
+ * return payload.id
62
+ * }
63
+ * })
64
+ *
65
+ * const MyWorkflow = Workflow.make({
66
+ * name: "MyWorkflow",
67
+ * payload: {
68
+ * id: Schema.String
69
+ * },
70
+ * idempotencyKey: ({ id }) => id
71
+ * })
72
+ *
73
+ * const MyWorkflowLayer = MyWorkflow.toLayer(
74
+ * Effect.fn(function*() {
75
+ * // Add an item to the DurableQueue defined above.
76
+ * //
77
+ * // When the worker has finished processing the item, the workflow will
78
+ * // resume.
79
+ * //
80
+ * yield* DurableQueue.process(ApiQueue, { id: "api-call-1" })
81
+ *
82
+ * yield* Effect.log("Workflow succeeded!")
83
+ * })
84
+ * )
85
+ *
86
+ * // Define a worker layer that can process items from the DurableQueue.
87
+ * const ApiWorker = DurableQueue.worker(
88
+ * ApiQueue,
89
+ * Effect.fn(function*({ id }) {
90
+ * yield* Effect.log(`Worker processing API call with id: ${id}`)
91
+ * }),
92
+ * { concurrency: 5 } // Process up to 5 items concurrently
93
+ * )
94
+ * ```
95
+ *
96
+ * @since 1.0.0
97
+ * @category Constructors
98
+ */
99
+ export const make = <
100
+ Payload extends Schema.Schema.Any | Schema.Struct.Fields,
101
+ Success extends Schema.Schema.Any = typeof Schema.Void,
102
+ Error extends Schema.Schema.All = typeof Schema.Never
103
+ >(
104
+ options: {
105
+ readonly name: string
106
+ readonly payload: Payload
107
+ readonly idempotencyKey: (
108
+ payload: Payload extends Schema.Struct.Fields ? Schema.Struct<Payload>["Type"] : Payload["Type"]
109
+ ) => string
110
+ readonly success?: Success | undefined
111
+ readonly error?: Error | undefined
112
+ }
113
+ ): DurableQueue<
114
+ Payload extends Schema.Struct.Fields ? Schema.Struct<Payload> : Payload,
115
+ Success,
116
+ Error
117
+ > => ({
118
+ [TypeId]: TypeId,
119
+ name: options.name,
120
+ payloadSchema: Schema.isSchema(options.payload) ? options.payload : Schema.Struct(options.payload) as any,
121
+ idempotencyKey: options.idempotencyKey as any,
122
+ deferred: DurableDeferred.make(`DurableQueue/${options.name}`, {
123
+ success: options.success,
124
+ error: options.error
125
+ })
126
+ })
127
+
128
+ const queueSchemas = new WeakMap<Schema.Schema.Any, Schema.Schema.Any>()
129
+ const getQueueSchema = <Payload extends Schema.Schema.Any>(
130
+ payload: Payload
131
+ ): Schema.Struct<{
132
+ token: typeof Schema.String
133
+ payload: Payload
134
+ traceId: typeof Schema.String
135
+ spanId: typeof Schema.String
136
+ sampled: typeof Schema.Boolean
137
+ }> => {
138
+ let schema = queueSchemas.get(payload)
139
+ if (!schema) {
140
+ schema = Schema.Struct({
141
+ token: Schema.String,
142
+ traceId: Schema.String,
143
+ spanId: Schema.String,
144
+ sampled: Schema.Boolean,
145
+ payload
146
+ })
147
+ queueSchemas.set(payload, schema)
148
+ }
149
+ return schema as any
150
+ }
151
+
152
+ /**
153
+ * @since 1.0.0
154
+ * @category Processing
155
+ */
156
+ export const process: <
157
+ Payload extends Schema.Schema.Any,
158
+ Success extends Schema.Schema.Any,
159
+ Error extends Schema.Schema.All
160
+ >(
161
+ self: DurableQueue<Payload, Success, Error>,
162
+ payload: Payload["Type"],
163
+ options?: {
164
+ readonly retrySchedule?: Schedule.Schedule<any, PersistedQueue.PersistedQueueError> | undefined
165
+ }
166
+ ) => Effect.Effect<
167
+ Success["Type"],
168
+ Error["Type"],
169
+ | WorkflowEngine.WorkflowEngine
170
+ | WorkflowEngine.WorkflowInstance
171
+ | PersistedQueue.PersistedQueueFactory
172
+ | Success["Context"]
173
+ | Error["Context"]
174
+ | Payload["Context"]
175
+ > = Effect.fnUntraced(function*<
176
+ Payload extends Schema.Schema.Any,
177
+ Success extends Schema.Schema.Any,
178
+ Error extends Schema.Schema.All
179
+ >(self: DurableQueue<Payload, Success, Error>, payload: Payload["Type"], options?: {
180
+ readonly retrySchedule?: Schedule.Schedule<any, PersistedQueue.PersistedQueueError> | undefined
181
+ }) {
182
+ const key = yield* makeHashDigest(self.idempotencyKey(payload))
183
+
184
+ const deferred = DurableDeferred.make(`${self.deferred.name}/${key}`, {
185
+ success: self.deferred.successSchema,
186
+ error: self.deferred.errorSchema
187
+ })
188
+
189
+ yield* Activity.make({
190
+ name: `DurableQueue/${self.name}/${key}`,
191
+ execute: Effect.gen(function*() {
192
+ const span = yield* Effect.orDie(Effect.currentSpan)
193
+ const queue = yield* PersistedQueue.make({
194
+ name: `DurableQueue/${self.name}`,
195
+ schema: getQueueSchema(self.payloadSchema)
196
+ })
197
+ const token = yield* DurableDeferred.token(deferred)
198
+ yield* queue.offer({
199
+ token,
200
+ payload,
201
+ traceId: span.traceId,
202
+ spanId: span.spanId,
203
+ sampled: span.sampled
204
+ } as any).pipe(
205
+ Effect.tapErrorCause(Effect.logWarning),
206
+ Effect.catchTag("ParseError", Effect.die),
207
+ Effect.retry(options?.retrySchedule ?? defaultRetrySchedule),
208
+ Effect.orDie,
209
+ Effect.annotateLogs({
210
+ package: "@effect/workflow",
211
+ module: "DurableQueue",
212
+ fiber: "process",
213
+ queueName: self.name
214
+ })
215
+ )
216
+ })
217
+ })
218
+
219
+ return yield* DurableDeferred.await(deferred)
220
+ })
221
+
222
+ const defaultRetrySchedule = Schedule.exponential(500, 1.5).pipe(
223
+ Schedule.union(Schedule.spaced("1 minute"))
224
+ )
225
+
226
+ /**
227
+ * @since 1.0.0
228
+ * @category Worker
229
+ */
230
+ export const makeWorker: <
231
+ Payload extends Schema.Schema.Any,
232
+ Success extends Schema.Schema.Any,
233
+ Error extends Schema.Schema.All,
234
+ R
235
+ >(
236
+ self: DurableQueue<Payload, Success, Error>,
237
+ f: (payload: Payload["Type"]) => Effect.Effect<Success["Type"], Error["Type"], R>,
238
+ options?: { readonly concurrency?: number | undefined } | undefined
239
+ ) => Effect.Effect<
240
+ never,
241
+ never,
242
+ | WorkflowEngine.WorkflowEngine
243
+ | PersistedQueue.PersistedQueueFactory
244
+ | R
245
+ | Payload["Context"]
246
+ | Success["Context"]
247
+ | Error["Context"]
248
+ > = Effect.fnUntraced(function*<
249
+ Payload extends Schema.Schema.Any,
250
+ Success extends Schema.Schema.Any,
251
+ Error extends Schema.Schema.All,
252
+ R
253
+ >(
254
+ self: DurableQueue<Payload, Success, Error>,
255
+ f: (payload: Payload["Type"]) => Effect.Effect<Success["Type"], Error["Type"], R>,
256
+ options?: {
257
+ readonly concurrency?: number | undefined
258
+ }
259
+ ) {
260
+ const queue = yield* PersistedQueue.make({
261
+ name: `DurableQueue/${self.name}`,
262
+ schema: getQueueSchema(self.payloadSchema)
263
+ })
264
+ const concurrency = options?.concurrency ?? 1
265
+
266
+ const worker = queue.take((item_) => {
267
+ const item = item_ as any as {
268
+ token: DurableDeferred.Token
269
+ payload: Payload["Type"]
270
+ traceId: string
271
+ spanId: string
272
+ sampled: boolean
273
+ }
274
+ return f(item.payload).pipe(
275
+ Effect.exit,
276
+ Effect.flatMap((exit) =>
277
+ DurableDeferred.done(self.deferred, {
278
+ token: item.token,
279
+ exit
280
+ })
281
+ ),
282
+ Effect.asVoid,
283
+ Effect.withSpan(`DurableQueue/${self.name}/worker`, {
284
+ captureStackTrace: false,
285
+ parent: {
286
+ _tag: "ExternalSpan",
287
+ traceId: item.traceId,
288
+ spanId: item.spanId,
289
+ sampled: item.sampled,
290
+ context: Context.empty()
291
+ }
292
+ })
293
+ )
294
+ }).pipe(
295
+ Effect.catchAllCause(Effect.logWarning),
296
+ Effect.forever,
297
+ Effect.annotateLogs({
298
+ package: "@effect/workflow",
299
+ module: "DurableQueue",
300
+ fiber: "worker"
301
+ })
302
+ )
303
+
304
+ yield* Effect.replicateEffect(worker, concurrency, { concurrency, discard: true })
305
+ return yield* Effect.never
306
+ })
307
+
308
+ /**
309
+ * @since 1.0.0
310
+ * @category Worker
311
+ */
312
+ export const worker: <
313
+ Payload extends Schema.Schema.Any,
314
+ Success extends Schema.Schema.Any,
315
+ Error extends Schema.Schema.All,
316
+ R
317
+ >(
318
+ self: DurableQueue<Payload, Success, Error>,
319
+ f: (payload: Payload["Type"]) => Effect.Effect<Success["Type"], Error["Type"], R>,
320
+ options?: {
321
+ readonly concurrency?: number | undefined
322
+ } | undefined
323
+ ) => Layer.Layer<
324
+ never,
325
+ never,
326
+ | WorkflowEngine.WorkflowEngine
327
+ | PersistedQueue.PersistedQueueFactory
328
+ | R
329
+ | Payload["Context"]
330
+ | Success["Context"]
331
+ | Error["Context"]
332
+ > = (self, f, options) => Layer.scopedDiscard(Effect.forkScoped(makeWorker(self, f, options)))
package/src/index.ts CHANGED
@@ -13,6 +13,11 @@ export * as DurableClock from "./DurableClock.js"
13
13
  */
14
14
  export * as DurableDeferred from "./DurableDeferred.js"
15
15
 
16
+ /**
17
+ * @since 1.0.0
18
+ */
19
+ export * as DurableQueue from "./DurableQueue.js"
20
+
16
21
  /**
17
22
  * @since 1.0.0
18
23
  */