@hotmeshio/hotmesh 0.12.1 → 0.14.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 +18 -22
- package/build/modules/enums.d.ts +60 -5
- package/build/modules/enums.js +62 -7
- package/build/modules/errors.d.ts +15 -2
- package/build/modules/errors.js +17 -1
- package/build/modules/storage.d.ts +1 -0
- package/build/modules/storage.js +2 -1
- package/build/package.json +8 -2
- package/build/services/activities/activity/context.d.ts +22 -0
- package/build/services/activities/activity/context.js +76 -0
- package/build/services/activities/activity/index.d.ts +116 -0
- package/build/services/activities/activity/index.js +299 -0
- package/build/services/activities/activity/mapping.d.ts +12 -0
- package/build/services/activities/activity/mapping.js +63 -0
- package/build/services/activities/activity/process.d.ts +28 -0
- package/build/services/activities/activity/process.js +100 -0
- package/build/services/activities/activity/protocol.d.ts +39 -0
- package/build/services/activities/activity/protocol.js +151 -0
- package/build/services/activities/activity/state.d.ts +40 -0
- package/build/services/activities/activity/state.js +143 -0
- package/build/services/activities/activity/transition.d.ts +23 -0
- package/build/services/activities/activity/transition.js +71 -0
- package/build/services/activities/activity/verify.d.ts +22 -0
- package/build/services/activities/activity/verify.js +85 -0
- package/build/services/activities/await.d.ts +1 -4
- package/build/services/activities/await.js +2 -36
- package/build/services/activities/cycle.d.ts +1 -11
- package/build/services/activities/cycle.js +3 -46
- package/build/services/activities/hook.d.ts +2 -11
- package/build/services/activities/hook.js +30 -50
- package/build/services/activities/interrupt.d.ts +2 -4
- package/build/services/activities/interrupt.js +4 -38
- package/build/services/activities/signal.d.ts +1 -11
- package/build/services/activities/signal.js +3 -48
- package/build/services/activities/trigger.d.ts +1 -3
- package/build/services/activities/trigger.js +0 -3
- package/build/services/activities/worker.d.ts +3 -6
- package/build/services/activities/worker.js +4 -40
- package/build/services/connector/factory.d.ts +6 -0
- package/build/services/connector/factory.js +24 -0
- package/build/services/dba/index.d.ts +14 -4
- package/build/services/dba/index.js +57 -18
- package/build/services/durable/activity.d.ts +30 -0
- package/build/services/durable/activity.js +46 -0
- package/build/services/durable/client.d.ts +26 -31
- package/build/services/durable/client.js +26 -31
- package/build/services/durable/connection.d.ts +13 -7
- package/build/services/durable/connection.js +13 -7
- package/build/services/durable/exporter.d.ts +2 -2
- package/build/services/durable/exporter.js +27 -12
- package/build/services/durable/handle.d.ts +59 -41
- package/build/services/durable/handle.js +61 -41
- package/build/services/durable/index.d.ts +152 -283
- package/build/services/durable/index.js +161 -289
- package/build/services/durable/interceptor.d.ts +43 -33
- package/build/services/durable/interceptor.js +59 -39
- package/build/services/durable/schemas/factory.d.ts +2 -3
- package/build/services/durable/schemas/factory.js +180 -30
- package/build/services/durable/telemetry.d.ts +80 -0
- package/build/services/durable/telemetry.js +137 -0
- package/build/services/durable/worker.d.ts +100 -21
- package/build/services/durable/worker.js +314 -60
- package/build/services/durable/workflow/all.d.ts +1 -1
- package/build/services/durable/workflow/all.js +1 -1
- package/build/services/durable/workflow/cancellationScope.d.ts +104 -0
- package/build/services/durable/workflow/cancellationScope.js +139 -0
- package/build/services/durable/workflow/common.d.ts +5 -4
- package/build/services/durable/workflow/common.js +6 -1
- package/build/services/durable/workflow/{waitFor.d.ts → condition.d.ts} +9 -8
- package/build/services/durable/workflow/{waitFor.js → condition.js} +44 -11
- package/build/services/durable/workflow/continueAsNew.d.ts +65 -0
- package/build/services/durable/workflow/continueAsNew.js +92 -0
- package/build/services/durable/workflow/didRun.d.ts +2 -2
- package/build/services/durable/workflow/didRun.js +4 -4
- package/build/services/durable/workflow/enrich.d.ts +5 -0
- package/build/services/durable/workflow/enrich.js +5 -0
- package/build/services/durable/workflow/entityMethods.d.ts +7 -0
- package/build/services/durable/workflow/entityMethods.js +7 -0
- package/build/services/durable/workflow/execHook.js +3 -3
- package/build/services/durable/workflow/execHookBatch.js +2 -2
- package/build/services/durable/workflow/{execChild.d.ts → executeChild.d.ts} +4 -40
- package/build/services/durable/workflow/{execChild.js → executeChild.js} +36 -45
- package/build/services/durable/workflow/hook.d.ts +1 -1
- package/build/services/durable/workflow/hook.js +4 -3
- package/build/services/durable/workflow/index.d.ts +45 -50
- package/build/services/durable/workflow/index.js +46 -51
- package/build/services/durable/workflow/interruption.d.ts +7 -6
- package/build/services/durable/workflow/interruption.js +11 -7
- package/build/services/durable/workflow/patched.d.ts +72 -0
- package/build/services/durable/workflow/patched.js +110 -0
- package/build/services/durable/workflow/proxyActivities.d.ts +7 -7
- package/build/services/durable/workflow/proxyActivities.js +51 -15
- package/build/services/durable/workflow/searchMethods.d.ts +7 -0
- package/build/services/durable/workflow/searchMethods.js +7 -0
- package/build/services/durable/workflow/signal.d.ts +4 -4
- package/build/services/durable/workflow/signal.js +4 -4
- package/build/services/durable/workflow/{sleepFor.d.ts → sleep.d.ts} +7 -7
- package/build/services/durable/workflow/{sleepFor.js → sleep.js} +39 -10
- package/build/services/durable/workflow/terminate.d.ts +55 -0
- package/build/services/durable/workflow/{interrupt.js → terminate.js} +21 -21
- package/build/services/durable/workflow/trace.js +2 -2
- package/build/services/durable/workflow/uuid4.d.ts +14 -0
- package/build/services/durable/workflow/uuid4.js +39 -0
- package/build/services/durable/workflow/{context.d.ts → workflowInfo.d.ts} +5 -5
- package/build/services/durable/workflow/{context.js → workflowInfo.js} +7 -7
- package/build/services/engine/compiler.d.ts +19 -0
- package/build/services/engine/compiler.js +20 -0
- package/build/services/engine/completion.d.ts +46 -0
- package/build/services/engine/completion.js +145 -0
- package/build/services/engine/dispatch.d.ts +24 -0
- package/build/services/engine/dispatch.js +98 -0
- package/build/services/engine/index.d.ts +49 -81
- package/build/services/engine/index.js +175 -573
- package/build/services/engine/init.d.ts +42 -0
- package/build/services/engine/init.js +74 -0
- package/build/services/engine/pubsub.d.ts +50 -0
- package/build/services/engine/pubsub.js +118 -0
- package/build/services/engine/reporting.d.ts +20 -0
- package/build/services/engine/reporting.js +38 -0
- package/build/services/engine/schema.d.ts +23 -0
- package/build/services/engine/schema.js +62 -0
- package/build/services/engine/signal.d.ts +57 -0
- package/build/services/engine/signal.js +117 -0
- package/build/services/engine/state.d.ts +35 -0
- package/build/services/engine/state.js +61 -0
- package/build/services/engine/version.d.ts +31 -0
- package/build/services/engine/version.js +73 -0
- package/build/services/hotmesh/deployment.d.ts +21 -0
- package/build/services/hotmesh/deployment.js +25 -0
- package/build/services/hotmesh/index.d.ts +142 -533
- package/build/services/hotmesh/index.js +223 -674
- package/build/services/hotmesh/init.d.ts +42 -0
- package/build/services/hotmesh/init.js +93 -0
- package/build/services/hotmesh/jobs.d.ts +67 -0
- package/build/services/hotmesh/jobs.js +99 -0
- package/build/services/hotmesh/pubsub.d.ts +38 -0
- package/build/services/hotmesh/pubsub.js +54 -0
- package/build/services/hotmesh/quorum.d.ts +30 -0
- package/build/services/hotmesh/quorum.js +62 -0
- package/build/services/hotmesh/validation.d.ts +6 -0
- package/build/services/hotmesh/validation.js +28 -0
- package/build/services/quorum/index.js +1 -0
- package/build/services/router/consumption/index.d.ts +11 -5
- package/build/services/router/consumption/index.js +24 -17
- package/build/services/router/error-handling/index.d.ts +2 -2
- package/build/services/router/error-handling/index.js +14 -14
- package/build/services/router/index.d.ts +1 -1
- package/build/services/router/index.js +2 -2
- package/build/services/serializer/index.d.ts +22 -0
- package/build/services/serializer/index.js +39 -1
- package/build/services/store/index.d.ts +1 -0
- package/build/services/store/providers/postgres/exporter-sql.d.ts +2 -2
- package/build/services/store/providers/postgres/exporter-sql.js +4 -4
- package/build/services/store/providers/postgres/kvtables.js +7 -6
- package/build/services/store/providers/postgres/kvtypes/hash/basic.js +67 -52
- package/build/services/store/providers/postgres/kvtypes/hash/jsonb.js +87 -72
- package/build/services/store/providers/postgres/kvtypes/hash/udata.js +106 -79
- package/build/services/store/providers/postgres/kvtypes/hash/utils.d.ts +16 -0
- package/build/services/store/providers/postgres/kvtypes/hash/utils.js +29 -16
- package/build/services/store/providers/postgres/postgres.d.ts +1 -0
- package/build/services/store/providers/postgres/postgres.js +14 -4
- package/build/services/stream/factory.d.ts +3 -1
- package/build/services/stream/factory.js +2 -2
- package/build/services/stream/index.d.ts +1 -0
- package/build/services/stream/providers/nats/nats.d.ts +1 -0
- package/build/services/stream/providers/nats/nats.js +1 -0
- package/build/services/stream/providers/postgres/credentials.d.ts +56 -0
- package/build/services/stream/providers/postgres/credentials.js +129 -0
- package/build/services/stream/providers/postgres/kvtables.js +18 -0
- package/build/services/stream/providers/postgres/messages.js +7 -7
- package/build/services/stream/providers/postgres/notifications.js +16 -2
- package/build/services/stream/providers/postgres/postgres.d.ts +7 -0
- package/build/services/stream/providers/postgres/postgres.js +35 -4
- package/build/services/stream/providers/postgres/procedures.d.ts +21 -0
- package/build/services/stream/providers/postgres/procedures.js +213 -0
- package/build/services/stream/providers/postgres/secured.d.ts +34 -0
- package/build/services/stream/providers/postgres/secured.js +146 -0
- package/build/services/stream/providers/postgres/stats.d.ts +1 -0
- package/build/services/stream/providers/postgres/stats.js +1 -0
- package/build/services/stream/registry.d.ts +1 -1
- package/build/services/stream/registry.js +5 -2
- package/build/services/telemetry/index.d.ts +10 -1
- package/build/services/telemetry/index.js +40 -7
- package/build/services/worker/credentials.d.ts +51 -0
- package/build/services/worker/credentials.js +87 -0
- package/build/services/worker/index.d.ts +2 -2
- package/build/services/worker/index.js +7 -6
- package/build/types/codec.d.ts +84 -0
- package/build/types/codec.js +2 -0
- package/build/types/dba.d.ts +39 -3
- package/build/types/durable.d.ts +123 -25
- package/build/types/error.d.ts +10 -0
- package/build/types/exporter.d.ts +1 -1
- package/build/types/hotmesh.d.ts +67 -4
- package/build/types/index.d.ts +2 -1
- package/build/types/provider.d.ts +2 -2
- package/build/types/quorum.d.ts +35 -1
- package/build/types/stream.d.ts +12 -6
- package/package.json +8 -2
- package/build/services/activities/activity.d.ts +0 -192
- package/build/services/activities/activity.js +0 -786
- package/build/services/durable/workflow/interrupt.d.ts +0 -55
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { WorkflowInboundCallsInterceptor, InterceptorRegistry, WorkflowOutboundCallsInterceptor, WorkflowOutboundCallsInterceptorContext, ActivityInboundCallsInterceptor } from '../../types/durable';
|
|
2
2
|
/**
|
|
3
3
|
* Service for managing workflow interceptors that wrap workflow execution
|
|
4
4
|
* in an onion-like pattern. Each interceptor can perform actions before
|
|
@@ -44,7 +44,7 @@ import { WorkflowInterceptor, InterceptorRegistry, ActivityInterceptor, Activity
|
|
|
44
44
|
* });
|
|
45
45
|
*
|
|
46
46
|
* // Execute workflow through interceptor chain
|
|
47
|
-
* const result = await service.
|
|
47
|
+
* const result = await service.executeInboundChain(context, async () => {
|
|
48
48
|
* return await workflowFn();
|
|
49
49
|
* });
|
|
50
50
|
* ```
|
|
@@ -52,7 +52,7 @@ import { WorkflowInterceptor, InterceptorRegistry, ActivityInterceptor, Activity
|
|
|
52
52
|
* ## Durable Interceptors with Durable Functions
|
|
53
53
|
*
|
|
54
54
|
* Interceptors run within the workflow's async local storage context, which means
|
|
55
|
-
* they can use Durable functions like `
|
|
55
|
+
* they can use Durable functions like `sleep`, `entity`, `proxyActivities`, etc.
|
|
56
56
|
* These interceptors participate in the HotMesh interruption/replay pattern.
|
|
57
57
|
*
|
|
58
58
|
* @example
|
|
@@ -60,16 +60,16 @@ import { WorkflowInterceptor, InterceptorRegistry, ActivityInterceptor, Activity
|
|
|
60
60
|
* import { Durable } from '@hotmeshio/hotmesh';
|
|
61
61
|
*
|
|
62
62
|
* // Rate limiting interceptor that sleeps before execution
|
|
63
|
-
* const rateLimitInterceptor:
|
|
63
|
+
* const rateLimitInterceptor: WorkflowInboundCallsInterceptor = {
|
|
64
64
|
* async execute(ctx, next) {
|
|
65
65
|
* try {
|
|
66
66
|
* // This sleep will cause an interruption on first execution
|
|
67
|
-
* await Durable.workflow.
|
|
67
|
+
* await Durable.workflow.sleep('1 second');
|
|
68
68
|
*
|
|
69
69
|
* const result = await next();
|
|
70
70
|
*
|
|
71
71
|
* // Another sleep after workflow completes
|
|
72
|
-
* await Durable.workflow.
|
|
72
|
+
* await Durable.workflow.sleep('500 milliseconds');
|
|
73
73
|
*
|
|
74
74
|
* return result;
|
|
75
75
|
* } catch (err) {
|
|
@@ -85,7 +85,7 @@ import { WorkflowInterceptor, InterceptorRegistry, ActivityInterceptor, Activity
|
|
|
85
85
|
* };
|
|
86
86
|
*
|
|
87
87
|
* // Entity-based audit interceptor
|
|
88
|
-
* const auditInterceptor:
|
|
88
|
+
* const auditInterceptor: WorkflowInboundCallsInterceptor = {
|
|
89
89
|
* async execute(ctx, next) {
|
|
90
90
|
* try {
|
|
91
91
|
* const entity = await Durable.workflow.entity();
|
|
@@ -126,8 +126,8 @@ import { WorkflowInterceptor, InterceptorRegistry, ActivityInterceptor, Activity
|
|
|
126
126
|
* };
|
|
127
127
|
*
|
|
128
128
|
* // Register interceptors
|
|
129
|
-
* Durable.
|
|
130
|
-
* Durable.
|
|
129
|
+
* Durable.registerInboundInterceptor(rateLimitInterceptor);
|
|
130
|
+
* Durable.registerInboundInterceptor(auditInterceptor);
|
|
131
131
|
* ```
|
|
132
132
|
*
|
|
133
133
|
* ## Execution Pattern with Interruptions
|
|
@@ -135,7 +135,7 @@ import { WorkflowInterceptor, InterceptorRegistry, ActivityInterceptor, Activity
|
|
|
135
135
|
* When interceptors use Durable functions, the workflow will execute multiple times
|
|
136
136
|
* due to the interruption/replay pattern:
|
|
137
137
|
*
|
|
138
|
-
* 1. **First execution**: Interceptor calls `
|
|
138
|
+
* 1. **First execution**: Interceptor calls `sleep` → throws `DurableSleepError` → workflow pauses
|
|
139
139
|
* 2. **Second execution**: Interceptor sleep replays (skipped), workflow runs → proxy activity throws `DurableProxyError` → workflow pauses
|
|
140
140
|
* 3. **Third execution**: All previous operations replay, interceptor sleep after workflow → throws `DurableSleepError` → workflow pauses
|
|
141
141
|
* 4. **Fourth execution**: Everything replays successfully, workflow completes
|
|
@@ -145,7 +145,7 @@ import { WorkflowInterceptor, InterceptorRegistry, ActivityInterceptor, Activity
|
|
|
145
145
|
* @example
|
|
146
146
|
* ```typescript
|
|
147
147
|
* // Interceptor with complex Durable operations
|
|
148
|
-
* const complexInterceptor:
|
|
148
|
+
* const complexInterceptor: WorkflowInboundCallsInterceptor = {
|
|
149
149
|
* async execute(ctx, next) {
|
|
150
150
|
* try {
|
|
151
151
|
* // Get persistent state
|
|
@@ -154,7 +154,7 @@ import { WorkflowInterceptor, InterceptorRegistry, ActivityInterceptor, Activity
|
|
|
154
154
|
*
|
|
155
155
|
* // Conditional durable operations
|
|
156
156
|
* if (!state.preProcessed) {
|
|
157
|
-
* await Durable.workflow.
|
|
157
|
+
* await Durable.workflow.sleep('100 milliseconds');
|
|
158
158
|
* await entity.merge({ preProcessed: true });
|
|
159
159
|
* }
|
|
160
160
|
*
|
|
@@ -163,7 +163,7 @@ import { WorkflowInterceptor, InterceptorRegistry, ActivityInterceptor, Activity
|
|
|
163
163
|
*
|
|
164
164
|
* // Post-processing with child workflow
|
|
165
165
|
* if (!state.postProcessed) {
|
|
166
|
-
* await Durable.workflow.
|
|
166
|
+
* await Durable.workflow.executeChild({
|
|
167
167
|
* taskQueue: 'cleanup',
|
|
168
168
|
* workflowName: 'cleanupWorkflow',
|
|
169
169
|
* args: [result]
|
|
@@ -199,11 +199,11 @@ import { WorkflowInterceptor, InterceptorRegistry, ActivityInterceptor, Activity
|
|
|
199
199
|
* @example
|
|
200
200
|
* ```typescript
|
|
201
201
|
* import { Durable } from '@hotmeshio/hotmesh';
|
|
202
|
-
* import type {
|
|
202
|
+
* import type { WorkflowOutboundCallsInterceptor } from '@hotmeshio/hotmesh/types/durable';
|
|
203
203
|
* import * as activities from './activities';
|
|
204
204
|
*
|
|
205
205
|
* // Activity interceptor that publishes results via a proxy activity
|
|
206
|
-
* const publishResultInterceptor:
|
|
206
|
+
* const publishResultInterceptor: WorkflowOutboundCallsInterceptor = {
|
|
207
207
|
* async execute(activityCtx, workflowCtx, next) {
|
|
208
208
|
* try {
|
|
209
209
|
* // BEFORE: inspect or modify the activity input
|
|
@@ -221,7 +221,7 @@ import { WorkflowInterceptor, InterceptorRegistry, ActivityInterceptor, Activity
|
|
|
221
221
|
* publishToSNS: (topic: string, payload: any) => Promise<void>;
|
|
222
222
|
* }>({
|
|
223
223
|
* taskQueue: 'shared-notifications',
|
|
224
|
-
*
|
|
224
|
+
* retry: { maximumAttempts: 3, throwOnError: true },
|
|
225
225
|
* });
|
|
226
226
|
*
|
|
227
227
|
* await publishToSNS('activity-results', {
|
|
@@ -240,7 +240,7 @@ import { WorkflowInterceptor, InterceptorRegistry, ActivityInterceptor, Activity
|
|
|
240
240
|
* },
|
|
241
241
|
* };
|
|
242
242
|
*
|
|
243
|
-
* Durable.
|
|
243
|
+
* Durable.registerOutboundInterceptor(publishResultInterceptor);
|
|
244
244
|
* ```
|
|
245
245
|
*
|
|
246
246
|
* ## Activity Interceptor Replay Pattern
|
|
@@ -256,8 +256,9 @@ import { WorkflowInterceptor, InterceptorRegistry, ActivityInterceptor, Activity
|
|
|
256
256
|
* its stored result → interceptor returns → workflow continues
|
|
257
257
|
*/
|
|
258
258
|
export declare class InterceptorService implements InterceptorRegistry {
|
|
259
|
-
|
|
260
|
-
|
|
259
|
+
inbound: WorkflowInboundCallsInterceptor[];
|
|
260
|
+
outbound: WorkflowOutboundCallsInterceptor[];
|
|
261
|
+
activityInbound: ActivityInboundCallsInterceptor[];
|
|
261
262
|
/**
|
|
262
263
|
* Register a new workflow interceptor that will wrap workflow execution.
|
|
263
264
|
* Interceptors are executed in the order they are registered, with the
|
|
@@ -279,7 +280,7 @@ export declare class InterceptorService implements InterceptorRegistry {
|
|
|
279
280
|
* });
|
|
280
281
|
* ```
|
|
281
282
|
*/
|
|
282
|
-
|
|
283
|
+
registerInbound(interceptor: WorkflowInboundCallsInterceptor): void;
|
|
283
284
|
/**
|
|
284
285
|
* Execute the interceptor chain around the workflow function.
|
|
285
286
|
* The chain is built in an onion pattern where each interceptor
|
|
@@ -292,7 +293,7 @@ export declare class InterceptorService implements InterceptorRegistry {
|
|
|
292
293
|
* @example
|
|
293
294
|
* ```typescript
|
|
294
295
|
* // Execute workflow with timing
|
|
295
|
-
* const result = await service.
|
|
296
|
+
* const result = await service.executeInboundChain(context, async () => {
|
|
296
297
|
* const start = Date.now();
|
|
297
298
|
* try {
|
|
298
299
|
* return await workflowFn();
|
|
@@ -302,7 +303,7 @@ export declare class InterceptorService implements InterceptorRegistry {
|
|
|
302
303
|
* });
|
|
303
304
|
* ```
|
|
304
305
|
*/
|
|
305
|
-
|
|
306
|
+
executeInboundChain(ctx: Map<string, any>, fn: () => Promise<any>): Promise<any>;
|
|
306
307
|
/**
|
|
307
308
|
* Register a new activity interceptor that will wrap individual
|
|
308
309
|
* proxied activity calls. Interceptors are executed in the order
|
|
@@ -310,28 +311,37 @@ export declare class InterceptorService implements InterceptorRegistry {
|
|
|
310
311
|
*
|
|
311
312
|
* @param interceptor The activity interceptor to register
|
|
312
313
|
*/
|
|
313
|
-
|
|
314
|
+
registerOutbound(interceptor: WorkflowOutboundCallsInterceptor): void;
|
|
314
315
|
/**
|
|
315
316
|
* Execute the activity interceptor chain around an activity invocation.
|
|
316
|
-
* Uses the same onion/reduceRight pattern as
|
|
317
|
+
* Uses the same onion/reduceRight pattern as executeInboundChain.
|
|
317
318
|
*
|
|
318
319
|
* @param activityCtx - Metadata about the activity (name, args, options)
|
|
319
320
|
* @param workflowCtx - The workflow context Map
|
|
320
321
|
* @param fn - The core activity function (registers with interruptionRegistry, sleeps, throws)
|
|
321
322
|
* @returns The result of the activity (from replay or after future execution)
|
|
322
323
|
*/
|
|
323
|
-
|
|
324
|
+
executeOutboundChain(activityCtx: WorkflowOutboundCallsInterceptorContext, workflowCtx: Map<string, any>, fn: () => Promise<any>): Promise<any>;
|
|
324
325
|
/**
|
|
325
|
-
*
|
|
326
|
+
* Register an activity inbound interceptor that wraps the actual
|
|
327
|
+
* activity function execution on the activity worker side.
|
|
326
328
|
*/
|
|
327
|
-
|
|
329
|
+
registerActivityInbound(interceptor: ActivityInboundCallsInterceptor): void;
|
|
328
330
|
/**
|
|
329
|
-
*
|
|
330
|
-
*
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
*
|
|
331
|
+
* Execute the activity inbound interceptor chain around the actual
|
|
332
|
+
* activity function invocation on the worker.
|
|
333
|
+
*/
|
|
334
|
+
executeActivityInboundChain(activityName: string, args: any[], fn: () => Promise<any>): Promise<any>;
|
|
335
|
+
/**
|
|
336
|
+
* Clear all registered outbound interceptors.
|
|
337
|
+
*/
|
|
338
|
+
clearOutbound(): void;
|
|
339
|
+
/**
|
|
340
|
+
* Clear all registered activity inbound interceptors.
|
|
341
|
+
*/
|
|
342
|
+
clearActivityInbound(): void;
|
|
343
|
+
/**
|
|
344
|
+
* Clear all registered interceptors.
|
|
335
345
|
*/
|
|
336
346
|
clear(): void;
|
|
337
347
|
}
|
|
@@ -46,7 +46,7 @@ exports.InterceptorService = void 0;
|
|
|
46
46
|
* });
|
|
47
47
|
*
|
|
48
48
|
* // Execute workflow through interceptor chain
|
|
49
|
-
* const result = await service.
|
|
49
|
+
* const result = await service.executeInboundChain(context, async () => {
|
|
50
50
|
* return await workflowFn();
|
|
51
51
|
* });
|
|
52
52
|
* ```
|
|
@@ -54,7 +54,7 @@ exports.InterceptorService = void 0;
|
|
|
54
54
|
* ## Durable Interceptors with Durable Functions
|
|
55
55
|
*
|
|
56
56
|
* Interceptors run within the workflow's async local storage context, which means
|
|
57
|
-
* they can use Durable functions like `
|
|
57
|
+
* they can use Durable functions like `sleep`, `entity`, `proxyActivities`, etc.
|
|
58
58
|
* These interceptors participate in the HotMesh interruption/replay pattern.
|
|
59
59
|
*
|
|
60
60
|
* @example
|
|
@@ -62,16 +62,16 @@ exports.InterceptorService = void 0;
|
|
|
62
62
|
* import { Durable } from '@hotmeshio/hotmesh';
|
|
63
63
|
*
|
|
64
64
|
* // Rate limiting interceptor that sleeps before execution
|
|
65
|
-
* const rateLimitInterceptor:
|
|
65
|
+
* const rateLimitInterceptor: WorkflowInboundCallsInterceptor = {
|
|
66
66
|
* async execute(ctx, next) {
|
|
67
67
|
* try {
|
|
68
68
|
* // This sleep will cause an interruption on first execution
|
|
69
|
-
* await Durable.workflow.
|
|
69
|
+
* await Durable.workflow.sleep('1 second');
|
|
70
70
|
*
|
|
71
71
|
* const result = await next();
|
|
72
72
|
*
|
|
73
73
|
* // Another sleep after workflow completes
|
|
74
|
-
* await Durable.workflow.
|
|
74
|
+
* await Durable.workflow.sleep('500 milliseconds');
|
|
75
75
|
*
|
|
76
76
|
* return result;
|
|
77
77
|
* } catch (err) {
|
|
@@ -87,7 +87,7 @@ exports.InterceptorService = void 0;
|
|
|
87
87
|
* };
|
|
88
88
|
*
|
|
89
89
|
* // Entity-based audit interceptor
|
|
90
|
-
* const auditInterceptor:
|
|
90
|
+
* const auditInterceptor: WorkflowInboundCallsInterceptor = {
|
|
91
91
|
* async execute(ctx, next) {
|
|
92
92
|
* try {
|
|
93
93
|
* const entity = await Durable.workflow.entity();
|
|
@@ -128,8 +128,8 @@ exports.InterceptorService = void 0;
|
|
|
128
128
|
* };
|
|
129
129
|
*
|
|
130
130
|
* // Register interceptors
|
|
131
|
-
* Durable.
|
|
132
|
-
* Durable.
|
|
131
|
+
* Durable.registerInboundInterceptor(rateLimitInterceptor);
|
|
132
|
+
* Durable.registerInboundInterceptor(auditInterceptor);
|
|
133
133
|
* ```
|
|
134
134
|
*
|
|
135
135
|
* ## Execution Pattern with Interruptions
|
|
@@ -137,7 +137,7 @@ exports.InterceptorService = void 0;
|
|
|
137
137
|
* When interceptors use Durable functions, the workflow will execute multiple times
|
|
138
138
|
* due to the interruption/replay pattern:
|
|
139
139
|
*
|
|
140
|
-
* 1. **First execution**: Interceptor calls `
|
|
140
|
+
* 1. **First execution**: Interceptor calls `sleep` → throws `DurableSleepError` → workflow pauses
|
|
141
141
|
* 2. **Second execution**: Interceptor sleep replays (skipped), workflow runs → proxy activity throws `DurableProxyError` → workflow pauses
|
|
142
142
|
* 3. **Third execution**: All previous operations replay, interceptor sleep after workflow → throws `DurableSleepError` → workflow pauses
|
|
143
143
|
* 4. **Fourth execution**: Everything replays successfully, workflow completes
|
|
@@ -147,7 +147,7 @@ exports.InterceptorService = void 0;
|
|
|
147
147
|
* @example
|
|
148
148
|
* ```typescript
|
|
149
149
|
* // Interceptor with complex Durable operations
|
|
150
|
-
* const complexInterceptor:
|
|
150
|
+
* const complexInterceptor: WorkflowInboundCallsInterceptor = {
|
|
151
151
|
* async execute(ctx, next) {
|
|
152
152
|
* try {
|
|
153
153
|
* // Get persistent state
|
|
@@ -156,7 +156,7 @@ exports.InterceptorService = void 0;
|
|
|
156
156
|
*
|
|
157
157
|
* // Conditional durable operations
|
|
158
158
|
* if (!state.preProcessed) {
|
|
159
|
-
* await Durable.workflow.
|
|
159
|
+
* await Durable.workflow.sleep('100 milliseconds');
|
|
160
160
|
* await entity.merge({ preProcessed: true });
|
|
161
161
|
* }
|
|
162
162
|
*
|
|
@@ -165,7 +165,7 @@ exports.InterceptorService = void 0;
|
|
|
165
165
|
*
|
|
166
166
|
* // Post-processing with child workflow
|
|
167
167
|
* if (!state.postProcessed) {
|
|
168
|
-
* await Durable.workflow.
|
|
168
|
+
* await Durable.workflow.executeChild({
|
|
169
169
|
* taskQueue: 'cleanup',
|
|
170
170
|
* workflowName: 'cleanupWorkflow',
|
|
171
171
|
* args: [result]
|
|
@@ -201,11 +201,11 @@ exports.InterceptorService = void 0;
|
|
|
201
201
|
* @example
|
|
202
202
|
* ```typescript
|
|
203
203
|
* import { Durable } from '@hotmeshio/hotmesh';
|
|
204
|
-
* import type {
|
|
204
|
+
* import type { WorkflowOutboundCallsInterceptor } from '@hotmeshio/hotmesh/types/durable';
|
|
205
205
|
* import * as activities from './activities';
|
|
206
206
|
*
|
|
207
207
|
* // Activity interceptor that publishes results via a proxy activity
|
|
208
|
-
* const publishResultInterceptor:
|
|
208
|
+
* const publishResultInterceptor: WorkflowOutboundCallsInterceptor = {
|
|
209
209
|
* async execute(activityCtx, workflowCtx, next) {
|
|
210
210
|
* try {
|
|
211
211
|
* // BEFORE: inspect or modify the activity input
|
|
@@ -223,7 +223,7 @@ exports.InterceptorService = void 0;
|
|
|
223
223
|
* publishToSNS: (topic: string, payload: any) => Promise<void>;
|
|
224
224
|
* }>({
|
|
225
225
|
* taskQueue: 'shared-notifications',
|
|
226
|
-
*
|
|
226
|
+
* retry: { maximumAttempts: 3, throwOnError: true },
|
|
227
227
|
* });
|
|
228
228
|
*
|
|
229
229
|
* await publishToSNS('activity-results', {
|
|
@@ -242,7 +242,7 @@ exports.InterceptorService = void 0;
|
|
|
242
242
|
* },
|
|
243
243
|
* };
|
|
244
244
|
*
|
|
245
|
-
* Durable.
|
|
245
|
+
* Durable.registerOutboundInterceptor(publishResultInterceptor);
|
|
246
246
|
* ```
|
|
247
247
|
*
|
|
248
248
|
* ## Activity Interceptor Replay Pattern
|
|
@@ -259,8 +259,9 @@ exports.InterceptorService = void 0;
|
|
|
259
259
|
*/
|
|
260
260
|
class InterceptorService {
|
|
261
261
|
constructor() {
|
|
262
|
-
this.
|
|
263
|
-
this.
|
|
262
|
+
this.inbound = [];
|
|
263
|
+
this.outbound = [];
|
|
264
|
+
this.activityInbound = [];
|
|
264
265
|
}
|
|
265
266
|
/**
|
|
266
267
|
* Register a new workflow interceptor that will wrap workflow execution.
|
|
@@ -283,8 +284,8 @@ class InterceptorService {
|
|
|
283
284
|
* });
|
|
284
285
|
* ```
|
|
285
286
|
*/
|
|
286
|
-
|
|
287
|
-
this.
|
|
287
|
+
registerInbound(interceptor) {
|
|
288
|
+
this.inbound.push(interceptor);
|
|
288
289
|
}
|
|
289
290
|
/**
|
|
290
291
|
* Execute the interceptor chain around the workflow function.
|
|
@@ -298,7 +299,7 @@ class InterceptorService {
|
|
|
298
299
|
* @example
|
|
299
300
|
* ```typescript
|
|
300
301
|
* // Execute workflow with timing
|
|
301
|
-
* const result = await service.
|
|
302
|
+
* const result = await service.executeInboundChain(context, async () => {
|
|
302
303
|
* const start = Date.now();
|
|
303
304
|
* try {
|
|
304
305
|
* return await workflowFn();
|
|
@@ -308,9 +309,9 @@ class InterceptorService {
|
|
|
308
309
|
* });
|
|
309
310
|
* ```
|
|
310
311
|
*/
|
|
311
|
-
async
|
|
312
|
+
async executeInboundChain(ctx, fn) {
|
|
312
313
|
// Create the onion-like chain of interceptors
|
|
313
|
-
const chain = this.
|
|
314
|
+
const chain = this.inbound.reduceRight((next, interceptor) => {
|
|
314
315
|
return () => interceptor.execute(ctx, next);
|
|
315
316
|
}, fn);
|
|
316
317
|
return chain();
|
|
@@ -322,41 +323,60 @@ class InterceptorService {
|
|
|
322
323
|
*
|
|
323
324
|
* @param interceptor The activity interceptor to register
|
|
324
325
|
*/
|
|
325
|
-
|
|
326
|
-
this.
|
|
326
|
+
registerOutbound(interceptor) {
|
|
327
|
+
this.outbound.push(interceptor);
|
|
327
328
|
}
|
|
328
329
|
/**
|
|
329
330
|
* Execute the activity interceptor chain around an activity invocation.
|
|
330
|
-
* Uses the same onion/reduceRight pattern as
|
|
331
|
+
* Uses the same onion/reduceRight pattern as executeInboundChain.
|
|
331
332
|
*
|
|
332
333
|
* @param activityCtx - Metadata about the activity (name, args, options)
|
|
333
334
|
* @param workflowCtx - The workflow context Map
|
|
334
335
|
* @param fn - The core activity function (registers with interruptionRegistry, sleeps, throws)
|
|
335
336
|
* @returns The result of the activity (from replay or after future execution)
|
|
336
337
|
*/
|
|
337
|
-
async
|
|
338
|
-
const chain = this.
|
|
338
|
+
async executeOutboundChain(activityCtx, workflowCtx, fn) {
|
|
339
|
+
const chain = this.outbound.reduceRight((next, interceptor) => {
|
|
339
340
|
return () => interceptor.execute(activityCtx, workflowCtx, next);
|
|
340
341
|
}, fn);
|
|
341
342
|
return chain();
|
|
342
343
|
}
|
|
343
344
|
/**
|
|
344
|
-
*
|
|
345
|
+
* Register an activity inbound interceptor that wraps the actual
|
|
346
|
+
* activity function execution on the activity worker side.
|
|
345
347
|
*/
|
|
346
|
-
|
|
347
|
-
this.
|
|
348
|
+
registerActivityInbound(interceptor) {
|
|
349
|
+
this.activityInbound.push(interceptor);
|
|
348
350
|
}
|
|
349
351
|
/**
|
|
350
|
-
*
|
|
351
|
-
*
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
352
|
+
* Execute the activity inbound interceptor chain around the actual
|
|
353
|
+
* activity function invocation on the worker.
|
|
354
|
+
*/
|
|
355
|
+
async executeActivityInboundChain(activityName, args, fn) {
|
|
356
|
+
const chain = this.activityInbound.reduceRight((next, interceptor) => {
|
|
357
|
+
return () => interceptor.execute(activityName, args, next);
|
|
358
|
+
}, fn);
|
|
359
|
+
return chain();
|
|
360
|
+
}
|
|
361
|
+
/**
|
|
362
|
+
* Clear all registered outbound interceptors.
|
|
363
|
+
*/
|
|
364
|
+
clearOutbound() {
|
|
365
|
+
this.outbound = [];
|
|
366
|
+
}
|
|
367
|
+
/**
|
|
368
|
+
* Clear all registered activity inbound interceptors.
|
|
369
|
+
*/
|
|
370
|
+
clearActivityInbound() {
|
|
371
|
+
this.activityInbound = [];
|
|
372
|
+
}
|
|
373
|
+
/**
|
|
374
|
+
* Clear all registered interceptors.
|
|
356
375
|
*/
|
|
357
376
|
clear() {
|
|
358
|
-
this.
|
|
359
|
-
this.
|
|
377
|
+
this.inbound = [];
|
|
378
|
+
this.outbound = [];
|
|
379
|
+
this.activityInbound = [];
|
|
360
380
|
}
|
|
361
381
|
}
|
|
362
382
|
exports.InterceptorService = InterceptorService;
|
|
@@ -2,8 +2,7 @@
|
|
|
2
2
|
*********** HOTMESH 'DURABLE' MODULE APPLICATION GRAPH **********
|
|
3
3
|
*
|
|
4
4
|
* This HotMesh application spec uses 50 activities and 25 transitions
|
|
5
|
-
* to model
|
|
6
|
-
* a pluggable backend.
|
|
5
|
+
* to model a durable workflow engine using a pluggable backend.
|
|
7
6
|
*
|
|
8
7
|
* This YAML file can also serve as a useful starting point for building
|
|
9
8
|
* Integration/BPM/Workflow servers in general (MuleSoft, etc) without the need
|
|
@@ -17,7 +16,7 @@
|
|
|
17
16
|
* * Service Meshes
|
|
18
17
|
* * Master Data Management systems
|
|
19
18
|
*/
|
|
20
|
-
declare const APP_VERSION = "
|
|
19
|
+
declare const APP_VERSION = "11";
|
|
21
20
|
declare const APP_ID = "durable";
|
|
22
21
|
/**
|
|
23
22
|
* returns a new durable workflow schema
|