@effect/cluster 0.38.2 → 0.38.4
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/dist/cjs/ClusterWorkflowEngine.js +35 -66
- package/dist/cjs/ClusterWorkflowEngine.js.map +1 -1
- package/dist/cjs/Sharding.js +1 -0
- package/dist/cjs/Sharding.js.map +1 -1
- package/dist/dts/ClusterWorkflowEngine.d.ts +0 -1
- package/dist/dts/ClusterWorkflowEngine.d.ts.map +1 -1
- package/dist/dts/Sharding.d.ts +4 -0
- package/dist/dts/Sharding.d.ts.map +1 -1
- package/dist/esm/ClusterWorkflowEngine.js +35 -66
- package/dist/esm/ClusterWorkflowEngine.js.map +1 -1
- package/dist/esm/Sharding.js +1 -0
- package/dist/esm/Sharding.js.map +1 -1
- package/package.json +2 -2
- package/src/ClusterWorkflowEngine.ts +55 -89
- package/src/Sharding.ts +6 -0
@@ -42,6 +42,7 @@ export const make = Effect.gen(function*() {
|
|
42
42
|
string,
|
43
43
|
Entity.Entity<
|
44
44
|
| Rpc.Rpc<"run", Schema.Struct<{}>, Schema.Schema<Workflow.Result<any, any>>>
|
45
|
+
| Rpc.Rpc<"deferred", Schema.Struct<{ name: typeof Schema.String; exit: typeof ExitUnknown }>, typeof ExitUnknown>
|
45
46
|
| Rpc.Rpc<
|
46
47
|
"activity",
|
47
48
|
Schema.Struct<{ name: typeof Schema.String; attempt: typeof Schema.Number }>,
|
@@ -65,7 +66,6 @@ export const make = Effect.gen(function*() {
|
|
65
66
|
idleTimeToLive: "5 minutes"
|
66
67
|
})
|
67
68
|
const clockClient = yield* ClockEntity.client
|
68
|
-
const deferredClient = yield* DeferredEntity.client
|
69
69
|
|
70
70
|
const requestIdFor = Effect.fnUntraced(function*(options: {
|
71
71
|
readonly workflow: Workflow.Any
|
@@ -151,6 +151,23 @@ export const make = Effect.gen(function*() {
|
|
151
151
|
yield* storage.clearAddress(clockAddress)
|
152
152
|
})
|
153
153
|
|
154
|
+
const resume = Effect.fnUntraced(function*(workflow: Workflow.Any, executionId: string) {
|
155
|
+
const maybeReply = yield* requestReply({
|
156
|
+
workflow,
|
157
|
+
entityType: `Workflow/${workflow.name}`,
|
158
|
+
executionId,
|
159
|
+
tag: "run",
|
160
|
+
id: ""
|
161
|
+
})
|
162
|
+
const maybeSuspended = Option.filter(
|
163
|
+
maybeReply,
|
164
|
+
(reply) => reply.exit._tag === "Success" && reply.exit.value._tag === "Suspended"
|
165
|
+
)
|
166
|
+
if (Option.isNone(maybeSuspended)) return
|
167
|
+
yield* sharding.reset(Snowflake.Snowflake(maybeSuspended.value.requestId))
|
168
|
+
yield* sharding.pollStorage
|
169
|
+
})
|
170
|
+
|
154
171
|
return WorkflowEngine.of({
|
155
172
|
register(workflow, execute) {
|
156
173
|
// eslint-disable-next-line @typescript-eslint/no-this-alias
|
@@ -198,6 +215,7 @@ export const make = Effect.gen(function*() {
|
|
198
215
|
Effect.provideService(WorkflowInstance, instance)
|
199
216
|
) as any
|
200
217
|
},
|
218
|
+
|
201
219
|
activity: Effect.fnUntraced(function*(request: Entity.Request<any>) {
|
202
220
|
const activityId = `${executionId}/${request.payload.name}`
|
203
221
|
let entry = activities.get(activityId)
|
@@ -224,7 +242,12 @@ export const make = Effect.gen(function*() {
|
|
224
242
|
activities.delete(activityId)
|
225
243
|
}))
|
226
244
|
)
|
227
|
-
}, Rpc.fork)
|
245
|
+
}, Rpc.fork),
|
246
|
+
|
247
|
+
deferred: Effect.fnUntraced(function*(request: Entity.Request<any>) {
|
248
|
+
yield* ensureSuccess(resume(workflow, executionId))
|
249
|
+
return request.payload.exit
|
250
|
+
})
|
228
251
|
}
|
229
252
|
})
|
230
253
|
) as Effect.Effect<void>
|
@@ -240,17 +263,13 @@ export const make = Effect.gen(function*() {
|
|
240
263
|
|
241
264
|
interrupt: Effect.fnUntraced(
|
242
265
|
function*(this: WorkflowEngine["Type"], workflow, executionId) {
|
243
|
-
const
|
266
|
+
const reply = yield* requestReply({
|
244
267
|
workflow,
|
245
268
|
entityType: `Workflow/${workflow.name}`,
|
246
269
|
executionId,
|
247
270
|
tag: "run",
|
248
271
|
id: ""
|
249
272
|
})
|
250
|
-
if (Option.isNone(requestId)) {
|
251
|
-
return
|
252
|
-
}
|
253
|
-
const reply = yield* replyForRequestId(requestId.value)
|
254
273
|
const nonSuspendedReply = reply.pipe(
|
255
274
|
Option.filter((reply) => reply.exit._tag !== "Success" || reply.exit.value._tag !== "Suspended")
|
256
275
|
)
|
@@ -273,34 +292,6 @@ export const make = Effect.gen(function*() {
|
|
273
292
|
Effect.orDie
|
274
293
|
),
|
275
294
|
|
276
|
-
resume: Effect.fnUntraced(
|
277
|
-
function*(workflowName: string, executionId: string) {
|
278
|
-
const workflow = workflows.get(workflowName)
|
279
|
-
if (!workflow) {
|
280
|
-
return yield* Effect.dieMessage(`WorkflowEngine.resume: ${workflowName} not registered`)
|
281
|
-
}
|
282
|
-
const maybeReply = yield* requestReply({
|
283
|
-
workflow,
|
284
|
-
entityType: `Workflow/${workflowName}`,
|
285
|
-
executionId,
|
286
|
-
tag: "run",
|
287
|
-
id: ""
|
288
|
-
})
|
289
|
-
const maybeSuspended = Option.filter(
|
290
|
-
maybeReply,
|
291
|
-
(reply) => reply.exit._tag === "Success" && reply.exit.value._tag === "Suspended"
|
292
|
-
)
|
293
|
-
if (Option.isNone(maybeSuspended)) return
|
294
|
-
yield* sharding.reset(Snowflake.Snowflake(maybeSuspended.value.requestId))
|
295
|
-
},
|
296
|
-
Effect.retry({
|
297
|
-
while: (e) => e._tag === "PersistenceError",
|
298
|
-
times: 3,
|
299
|
-
schedule: Schedule.exponential(250)
|
300
|
-
}),
|
301
|
-
Effect.orDie
|
302
|
-
),
|
303
|
-
|
304
295
|
activityExecute: Effect.fnUntraced(function*({ activity, attempt }) {
|
305
296
|
const context = yield* Effect.context<WorkflowInstance>()
|
306
297
|
const instance = Context.get(context, WorkflowInstance)
|
@@ -335,9 +326,9 @@ export const make = Effect.gen(function*() {
|
|
335
326
|
Effect.flatMap((instance) =>
|
336
327
|
requestReply({
|
337
328
|
workflow: instance.workflow,
|
338
|
-
entityType:
|
329
|
+
entityType: `Workflow/${instance.workflow.name}`,
|
339
330
|
executionId: instance.executionId,
|
340
|
-
tag: "
|
331
|
+
tag: "deferred",
|
341
332
|
id: deferred.name
|
342
333
|
})
|
343
334
|
),
|
@@ -350,14 +341,15 @@ export const make = Effect.gen(function*() {
|
|
350
341
|
Effect.orDie
|
351
342
|
),
|
352
343
|
|
353
|
-
deferredDone({ deferred, executionId, exit, workflowName }) {
|
354
|
-
const client =
|
355
|
-
return Effect.orDie(
|
356
|
-
|
357
|
-
|
358
|
-
|
359
|
-
|
360
|
-
|
344
|
+
deferredDone: Effect.fnUntraced(function*({ deferred, executionId, exit, workflowName }) {
|
345
|
+
const client = yield* RcMap.get(clients, workflowName)
|
346
|
+
return yield* Effect.orDie(
|
347
|
+
client(executionId).deferred({
|
348
|
+
name: deferred.name,
|
349
|
+
exit
|
350
|
+
})
|
351
|
+
)
|
352
|
+
}, Effect.scoped),
|
361
353
|
|
362
354
|
scheduleClock(options) {
|
363
355
|
const client = clockClient(options.executionId)
|
@@ -396,7 +388,7 @@ const ActivityRpc = Rpc.make("activity", {
|
|
396
388
|
success: Schema.Unknown,
|
397
389
|
error: Schema.Unknown
|
398
390
|
})
|
399
|
-
})
|
391
|
+
}).annotate(ClusterSchema.Persisted, true)
|
400
392
|
|
401
393
|
const makeWorkflowEntity = (workflow: Workflow.Any) =>
|
402
394
|
Entity.make(`Workflow/${workflow.name}`, [
|
@@ -407,12 +399,23 @@ const makeWorkflowEntity = (workflow: Workflow.Any) =>
|
|
407
399
|
success: workflow.successSchema,
|
408
400
|
error: workflow.errorSchema
|
409
401
|
})
|
410
|
-
})
|
402
|
+
})
|
403
|
+
.annotate(ClusterSchema.Persisted, true)
|
404
|
+
.annotate(ClusterSchema.Uninterruptible, true),
|
405
|
+
|
406
|
+
Rpc.make("deferred", {
|
407
|
+
payload: {
|
408
|
+
name: Schema.String,
|
409
|
+
exit: ExitUnknown
|
410
|
+
},
|
411
|
+
primaryKey: ({ name }) => name,
|
412
|
+
success: ExitUnknown
|
413
|
+
})
|
414
|
+
.annotate(ClusterSchema.Persisted, true)
|
415
|
+
.annotate(ClusterSchema.Uninterruptible, true),
|
416
|
+
|
411
417
|
ActivityRpc
|
412
|
-
])
|
413
|
-
.annotateContext(workflow.annotations)
|
414
|
-
.annotateRpcs(ClusterSchema.Persisted, true)
|
415
|
-
.annotateRpcs(ClusterSchema.Uninterruptible, true)
|
418
|
+
]).annotateContext(workflow.annotations)
|
416
419
|
|
417
420
|
const activityPrimaryKey = (activity: string, attempt: number) => `${activity}/${attempt}`
|
418
421
|
|
@@ -422,42 +425,6 @@ const ExitUnknown = Schema.encodedSchema(Schema.Exit({
|
|
422
425
|
defect: Schema.Defect
|
423
426
|
}))
|
424
427
|
|
425
|
-
const DeferredEntity = Entity.make("Workflow/-/DurableDeferred", [
|
426
|
-
Rpc.make("set", {
|
427
|
-
payload: {
|
428
|
-
workflowName: Schema.String,
|
429
|
-
name: Schema.String,
|
430
|
-
exit: ExitUnknown
|
431
|
-
},
|
432
|
-
primaryKey: ({ name }) => name,
|
433
|
-
success: ExitUnknown
|
434
|
-
}),
|
435
|
-
Rpc.make("resume", {
|
436
|
-
payload: {
|
437
|
-
workflowName: Schema.String,
|
438
|
-
name: Schema.String
|
439
|
-
},
|
440
|
-
primaryKey: ({ name }) => name
|
441
|
-
})
|
442
|
-
])
|
443
|
-
.annotateRpcs(ClusterSchema.Persisted, true)
|
444
|
-
.annotateRpcs(ClusterSchema.Uninterruptible, true)
|
445
|
-
|
446
|
-
const DeferredEntityLayer = DeferredEntity.toLayer(Effect.gen(function*() {
|
447
|
-
const engine = yield* WorkflowEngine
|
448
|
-
const address = yield* Entity.CurrentAddress
|
449
|
-
const executionId = address.entityId
|
450
|
-
const client = (yield* DeferredEntity.client)(executionId)
|
451
|
-
return {
|
452
|
-
set: (request) =>
|
453
|
-
Effect.as(
|
454
|
-
ensureSuccess(client.resume(request.payload, { discard: true })),
|
455
|
-
request.payload.exit
|
456
|
-
),
|
457
|
-
resume: (request) => engine.resume(request.payload.workflowName, executionId)
|
458
|
-
}
|
459
|
-
}))
|
460
|
-
|
461
428
|
class ClockPayload extends Schema.Class<ClockPayload>(`Workflow/DurableClock/Run`)({
|
462
429
|
name: Schema.String,
|
463
430
|
workflowName: Schema.String,
|
@@ -504,7 +471,6 @@ export const layer: Layer.Layer<
|
|
504
471
|
WorkflowEngine,
|
505
472
|
never,
|
506
473
|
Sharding.Sharding | MessageStorage
|
507
|
-
> =
|
508
|
-
Layer.merge(ClockEntityLayer),
|
474
|
+
> = ClockEntityLayer.pipe(
|
509
475
|
Layer.provideMerge(Layer.scoped(WorkflowEngine, make))
|
510
476
|
)
|
package/src/Sharding.ts
CHANGED
@@ -154,6 +154,11 @@ export class Sharding extends Context.Tag("@effect/cluster/Sharding")<Sharding,
|
|
154
154
|
*/
|
155
155
|
readonly reset: (requestId: Snowflake.Snowflake) => Effect.Effect<boolean>
|
156
156
|
|
157
|
+
/**
|
158
|
+
* Trigger a storage read, which will read all unprocessed messages.
|
159
|
+
*/
|
160
|
+
readonly pollStorage: Effect.Effect<void>
|
161
|
+
|
157
162
|
/**
|
158
163
|
* Retrieves the active entity count for the current runner.
|
159
164
|
*/
|
@@ -1191,6 +1196,7 @@ const make = Effect.gen(function*() {
|
|
1191
1196
|
sendOutgoing: (message, discard) => sendOutgoing(message, discard),
|
1192
1197
|
notify: (message) => notifyLocal(message, false),
|
1193
1198
|
activeEntityCount,
|
1199
|
+
pollStorage: storageReadLatch.open,
|
1194
1200
|
reset
|
1195
1201
|
})
|
1196
1202
|
|