@hotmeshio/hotmesh 0.13.0 → 0.14.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.
- 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 -3
- package/build/modules/errors.js +17 -2
- package/build/package.json +6 -1
- 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/durable/activity.d.ts +1 -1
- package/build/services/durable/activity.js +2 -2
- package/build/services/durable/client.d.ts +24 -29
- package/build/services/durable/client.js +24 -29
- package/build/services/durable/connection.d.ts +13 -7
- package/build/services/durable/connection.js +13 -7
- package/build/services/durable/handle.d.ts +58 -40
- package/build/services/durable/handle.js +60 -40
- package/build/services/durable/index.d.ts +148 -286
- package/build/services/durable/index.js +157 -292
- 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 +1 -1
- package/build/services/durable/schemas/factory.js +168 -38
- 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 +304 -63
- 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 +1 -1
- package/build/services/durable/workflow/didRun.js +3 -3
- 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 +50 -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 +141 -532
- package/build/services/hotmesh/index.js +222 -673
- 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 +21 -15
- 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/durable.d.ts +104 -28
- package/build/types/error.d.ts +10 -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 +6 -1
- 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,5 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { HotMesh } from '../hotmesh';
|
|
2
|
+
import { ContextType, WorkflowInboundCallsInterceptor, WorkflowOutboundCallsInterceptor, ActivityInboundCallsInterceptor } from '../../types/durable';
|
|
2
3
|
import { guid } from '../../modules/utils';
|
|
3
4
|
import { ClientService } from './client';
|
|
4
5
|
import { ConnectionService } from './connection';
|
|
@@ -10,266 +11,83 @@ import { WorkflowService } from './workflow';
|
|
|
10
11
|
import { WorkflowHandleService } from './handle';
|
|
11
12
|
import { didInterrupt } from './workflow/interruption';
|
|
12
13
|
/**
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
14
|
+
* Durable workflow engine backed by Postgres. Write workflows as plain
|
|
15
|
+
* async functions; the engine handles persistence, replay, retry, and
|
|
16
|
+
* crash recovery automatically.
|
|
16
17
|
*
|
|
17
|
-
* ##
|
|
18
|
+
* ## Architecture
|
|
18
19
|
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
*
|
|
23
|
-
*
|
|
24
|
-
*
|
|
25
|
-
* // Initialize entity state
|
|
26
|
-
* await agent.set({
|
|
27
|
-
* query,
|
|
28
|
-
* findings: [],
|
|
29
|
-
* status: 'researching'
|
|
30
|
-
* });
|
|
31
|
-
*
|
|
32
|
-
* // Update state atomically
|
|
33
|
-
* await agent.merge({ status: 'analyzing' });
|
|
34
|
-
* await agent.append('findings', newFinding);
|
|
35
|
-
* }
|
|
36
|
-
* ```
|
|
37
|
-
*
|
|
38
|
-
* ### 2. Hook Functions & Workflow Coordination
|
|
39
|
-
* Spawn and coordinate multiple perspectives/phases:
|
|
40
|
-
* ```typescript
|
|
41
|
-
* // Launch parallel research perspectives
|
|
42
|
-
* await Durable.workflow.execHook({
|
|
43
|
-
* taskQueue: 'research',
|
|
44
|
-
* workflowName: 'optimisticView',
|
|
45
|
-
* args: [query],
|
|
46
|
-
* signalId: 'optimistic-complete'
|
|
47
|
-
* });
|
|
48
|
-
*
|
|
49
|
-
* await Durable.workflow.execHook({
|
|
50
|
-
* taskQueue: 'research',
|
|
51
|
-
* workflowName: 'skepticalView',
|
|
52
|
-
* args: [query],
|
|
53
|
-
* signalId: 'skeptical-complete'
|
|
54
|
-
* });
|
|
55
|
-
*
|
|
56
|
-
* // Wait for both perspectives
|
|
57
|
-
* await Promise.all([
|
|
58
|
-
* Durable.workflow.waitFor('optimistic-complete'),
|
|
59
|
-
* Durable.workflow.waitFor('skeptical-complete')
|
|
60
|
-
* ]);
|
|
61
|
-
* ```
|
|
62
|
-
*
|
|
63
|
-
* ### 3. Durable Activities & Proxies
|
|
64
|
-
* Define and execute durable activities with automatic retry:
|
|
65
|
-
* ```typescript
|
|
66
|
-
* // Default: activities use workflow's task queue
|
|
67
|
-
* const activities = Durable.workflow.proxyActivities<{
|
|
68
|
-
* analyzeDocument: typeof analyzeDocument;
|
|
69
|
-
* validateFindings: typeof validateFindings;
|
|
70
|
-
* }>({
|
|
71
|
-
* activities: { analyzeDocument, validateFindings },
|
|
72
|
-
* retryPolicy: {
|
|
73
|
-
* maximumAttempts: 3,
|
|
74
|
-
* backoffCoefficient: 2
|
|
75
|
-
* }
|
|
76
|
-
* });
|
|
77
|
-
*
|
|
78
|
-
* // Activities are durable and automatically retried
|
|
79
|
-
* const analysis = await activities.analyzeDocument(data);
|
|
80
|
-
* const validation = await activities.validateFindings(analysis);
|
|
81
|
-
* ```
|
|
82
|
-
*
|
|
83
|
-
* ### 4. Explicit Activity Registration
|
|
84
|
-
* Register activity workers explicitly before workflows start:
|
|
85
|
-
* ```typescript
|
|
86
|
-
* // Register shared activity pool for interceptors
|
|
87
|
-
* await Durable.registerActivityWorker({
|
|
88
|
-
* connection: {
|
|
89
|
-
* class: Postgres,
|
|
90
|
-
* options: { connectionString: 'postgresql://usr:pwd@localhost:5432/db' }
|
|
91
|
-
* },
|
|
92
|
-
* taskQueue: 'shared-activities'
|
|
93
|
-
* }, sharedActivities, 'shared-activities');
|
|
94
|
-
*
|
|
95
|
-
* // Register custom activity pool for specific use cases
|
|
96
|
-
* await Durable.registerActivityWorker({
|
|
97
|
-
* connection: {
|
|
98
|
-
* class: Postgres,
|
|
99
|
-
* options: { connectionString: 'postgresql://usr:pwd@localhost:5432/db' }
|
|
100
|
-
* },
|
|
101
|
-
* taskQueue: 'priority-activities'
|
|
102
|
-
* }, priorityActivities, 'priority-activities');
|
|
103
|
-
* ```
|
|
104
|
-
*
|
|
105
|
-
* ### 5. Workflow Composition
|
|
106
|
-
* Build complex workflows through composition:
|
|
107
|
-
* ```typescript
|
|
108
|
-
* // Start a child workflow
|
|
109
|
-
* const childResult = await Durable.workflow.execChild({
|
|
110
|
-
* taskQueue: 'analysis',
|
|
111
|
-
* workflowName: 'detailedAnalysis',
|
|
112
|
-
* args: [data],
|
|
113
|
-
* // Child workflow config
|
|
114
|
-
* config: {
|
|
115
|
-
* maximumAttempts: 5,
|
|
116
|
-
* backoffCoefficient: 2
|
|
117
|
-
* }
|
|
118
|
-
* });
|
|
20
|
+
* | Component | Role |
|
|
21
|
+
* |-----------|------|
|
|
22
|
+
* | {@link Worker} | Hosts workflow and activity functions |
|
|
23
|
+
* | {@link Client} | Starts workflows, sends signals, reads results |
|
|
24
|
+
* | {@link workflow} | In-workflow API (`proxyActivities`, `sleep`, `condition`, ...) |
|
|
119
25
|
*
|
|
120
|
-
*
|
|
121
|
-
* await Durable.workflow.startChild({
|
|
122
|
-
* taskQueue: 'notifications',
|
|
123
|
-
* workflowName: 'sendUpdates',
|
|
124
|
-
* args: [updates]
|
|
125
|
-
* });
|
|
126
|
-
* ```
|
|
127
|
-
*
|
|
128
|
-
* ### 6. Workflow Interceptors
|
|
129
|
-
* Add cross-cutting concerns through interceptors that run as durable functions:
|
|
130
|
-
* ```typescript
|
|
131
|
-
* // First register shared activity worker for interceptors
|
|
132
|
-
* await Durable.registerActivityWorker({
|
|
133
|
-
* connection: {
|
|
134
|
-
* class: Postgres,
|
|
135
|
-
* options: { connectionString: 'postgresql://usr:pwd@localhost:5432/db' }
|
|
136
|
-
* },
|
|
137
|
-
* taskQueue: 'interceptor-activities'
|
|
138
|
-
* }, { auditLog }, 'interceptor-activities');
|
|
26
|
+
* ## Workflow Primitives
|
|
139
27
|
*
|
|
140
|
-
*
|
|
141
|
-
*
|
|
142
|
-
*
|
|
143
|
-
* try {
|
|
144
|
-
* // Interceptors use explicit taskQueue to prevent per-workflow queues
|
|
145
|
-
* const { auditLog } = Durable.workflow.proxyActivities<typeof activities>({
|
|
146
|
-
* activities: { auditLog },
|
|
147
|
-
* taskQueue: 'interceptor-activities', // Explicit shared queue
|
|
148
|
-
* retryPolicy: { maximumAttempts: 3 }
|
|
149
|
-
* });
|
|
28
|
+
* All methods below are available as `Durable.workflow.<method>` inside
|
|
29
|
+
* a workflow function. Each call is durable — results are persisted and
|
|
30
|
+
* replayed deterministically on recovery.
|
|
150
31
|
*
|
|
151
|
-
*
|
|
32
|
+
* | Primitive | Purpose |
|
|
33
|
+
* |-----------|---------|
|
|
34
|
+
* | `proxyActivities` | Execute side-effectful code with automatic retry |
|
|
35
|
+
* | `sleep` | Durable timer (survives restarts) |
|
|
36
|
+
* | `condition` | Pause until a named signal arrives (with optional timeout) |
|
|
37
|
+
* | `signal` | Deliver data to a waiting `condition` |
|
|
38
|
+
* | `executeChild` | Spawn a child workflow and await its result |
|
|
39
|
+
* | `startChild` | Fire-and-forget child workflow |
|
|
40
|
+
* | `continueAsNew` | Restart the workflow with new args (resets history) |
|
|
41
|
+
* | `patched` / `deprecatePatch` | Safe versioning for in-flight workflow code changes |
|
|
42
|
+
* | `CancellationScope.nonCancellable` | Shield cleanup code from cancellation |
|
|
43
|
+
* | `isCancellation` | Detect cooperative cancellation errors |
|
|
152
44
|
*
|
|
153
|
-
*
|
|
45
|
+
* ## Quick Start
|
|
154
46
|
*
|
|
155
|
-
* await auditLog(ctx.get('workflowId'), 'completed');
|
|
156
|
-
*
|
|
157
|
-
* return result;
|
|
158
|
-
* } catch (err) {
|
|
159
|
-
* // CRITICAL: Always check for HotMesh interruptions
|
|
160
|
-
* if (Durable.didInterrupt(err)) {
|
|
161
|
-
* throw err; // Rethrow for replay system
|
|
162
|
-
* }
|
|
163
|
-
* throw err;
|
|
164
|
-
* }
|
|
165
|
-
* }
|
|
166
|
-
* });
|
|
167
|
-
* ```
|
|
168
|
-
*
|
|
169
|
-
* ### 7. Activity Interceptors
|
|
170
|
-
* Wrap individual proxied activity calls with cross-cutting logic.
|
|
171
|
-
* Unlike workflow interceptors (which wrap the entire workflow), activity
|
|
172
|
-
* interceptors execute around each `proxyActivities` call. They run inside
|
|
173
|
-
* the workflow's execution context and have access to all Durable workflow
|
|
174
|
-
* methods (`proxyActivities`, `sleepFor`, `waitFor`, `execChild`, etc.).
|
|
175
|
-
* Multiple activity interceptors execute in onion order (first registered
|
|
176
|
-
* is outermost).
|
|
177
47
|
* ```typescript
|
|
178
|
-
*
|
|
179
|
-
* Durable.registerActivityInterceptor({
|
|
180
|
-
* async execute(activityCtx, workflowCtx, next) {
|
|
181
|
-
* console.log(`Activity ${activityCtx.activityName} starting`);
|
|
182
|
-
* try {
|
|
183
|
-
* const result = await next();
|
|
184
|
-
* console.log(`Activity ${activityCtx.activityName} completed`);
|
|
185
|
-
* return result;
|
|
186
|
-
* } catch (err) {
|
|
187
|
-
* if (Durable.didInterrupt(err)) throw err;
|
|
188
|
-
* console.error(`Activity ${activityCtx.activityName} failed`);
|
|
189
|
-
* throw err;
|
|
190
|
-
* }
|
|
191
|
-
* }
|
|
192
|
-
* });
|
|
193
|
-
*
|
|
194
|
-
* // Interceptor that calls its own proxy activities
|
|
195
|
-
* await Durable.registerActivityWorker({
|
|
196
|
-
* connection: {
|
|
197
|
-
* class: Postgres,
|
|
198
|
-
* options: { connectionString: 'postgresql://usr:pwd@localhost:5432/db' }
|
|
199
|
-
* },
|
|
200
|
-
* taskQueue: 'audit-activities'
|
|
201
|
-
* }, { auditLog }, 'audit-activities');
|
|
202
|
-
*
|
|
203
|
-
* Durable.registerActivityInterceptor({
|
|
204
|
-
* async execute(activityCtx, workflowCtx, next) {
|
|
205
|
-
* try {
|
|
206
|
-
* const { auditLog } = Durable.workflow.proxyActivities<{
|
|
207
|
-
* auditLog: (id: string, action: string) => Promise<void>;
|
|
208
|
-
* }>({
|
|
209
|
-
* taskQueue: 'audit-activities',
|
|
210
|
-
* retryPolicy: { maximumAttempts: 3 }
|
|
211
|
-
* });
|
|
212
|
-
*
|
|
213
|
-
* await auditLog(workflowCtx.get('workflowId'), `before:${activityCtx.activityName}`);
|
|
214
|
-
* const result = await next();
|
|
215
|
-
* await auditLog(workflowCtx.get('workflowId'), `after:${activityCtx.activityName}`);
|
|
216
|
-
* return result;
|
|
217
|
-
* } catch (err) {
|
|
218
|
-
* if (Durable.didInterrupt(err)) throw err;
|
|
219
|
-
* throw err;
|
|
220
|
-
* }
|
|
221
|
-
* }
|
|
222
|
-
* });
|
|
223
|
-
* ```
|
|
224
|
-
*
|
|
225
|
-
* ## Basic Usage Example
|
|
226
|
-
*
|
|
227
|
-
* ```typescript
|
|
228
|
-
* import { Client, Worker, Durable } from '@hotmeshio/hotmesh';
|
|
48
|
+
* import { Durable } from '@hotmeshio/hotmesh';
|
|
229
49
|
* import { Client as Postgres } from 'pg';
|
|
230
50
|
* import * as activities from './activities';
|
|
231
51
|
*
|
|
232
|
-
* //
|
|
233
|
-
*
|
|
234
|
-
*
|
|
235
|
-
*
|
|
236
|
-
*
|
|
237
|
-
* }
|
|
238
|
-
* taskQueue: 'shared-activities'
|
|
239
|
-
* }, sharedActivities, 'shared-activities');
|
|
52
|
+
* // 1. Define a workflow
|
|
53
|
+
* async function orderWorkflow(orderId: string): Promise<string> {
|
|
54
|
+
* const { charge, notify } = Durable.workflow.proxyActivities<typeof activities>({
|
|
55
|
+
* activities,
|
|
56
|
+
* retry: { maximumAttempts: 3 },
|
|
57
|
+
* });
|
|
240
58
|
*
|
|
241
|
-
*
|
|
242
|
-
*
|
|
243
|
-
*
|
|
244
|
-
*
|
|
245
|
-
*
|
|
246
|
-
* },
|
|
247
|
-
* taskQueue: 'default',
|
|
248
|
-
* workflow: workflows.example
|
|
249
|
-
* });
|
|
59
|
+
* const receipt = await charge(orderId);
|
|
60
|
+
* await Durable.workflow.sleep('1 hour');
|
|
61
|
+
* await notify(orderId, receipt);
|
|
62
|
+
* return receipt;
|
|
63
|
+
* }
|
|
250
64
|
*
|
|
251
|
-
* //
|
|
252
|
-
* const
|
|
253
|
-
*
|
|
254
|
-
* class: Postgres,
|
|
255
|
-
* options: { connectionString: 'postgresql://usr:pwd@localhost:5432/db' }
|
|
256
|
-
* }
|
|
257
|
-
* });
|
|
65
|
+
* // 2. Start a worker
|
|
66
|
+
* const connection = { class: Postgres, options: { connectionString: 'postgresql://...' } };
|
|
67
|
+
* await Durable.Worker.create({ connection, taskQueue: 'orders', workflow: orderWorkflow });
|
|
258
68
|
*
|
|
259
|
-
* // Start workflow
|
|
69
|
+
* // 3. Start a workflow from the client
|
|
70
|
+
* const client = new Durable.Client({ connection });
|
|
260
71
|
* const handle = await client.workflow.start({
|
|
261
|
-
* args: ['
|
|
262
|
-
* taskQueue: '
|
|
263
|
-
* workflowName: '
|
|
264
|
-
* workflowId: Durable.guid()
|
|
72
|
+
* args: ['order-123'],
|
|
73
|
+
* taskQueue: 'orders',
|
|
74
|
+
* workflowName: 'orderWorkflow',
|
|
75
|
+
* workflowId: Durable.guid(),
|
|
265
76
|
* });
|
|
266
|
-
*
|
|
267
|
-
* // Get result
|
|
268
77
|
* const result = await handle.result();
|
|
269
|
-
*
|
|
270
|
-
* // Cleanup
|
|
271
|
-
* await Durable.shutdown();
|
|
272
78
|
* ```
|
|
79
|
+
*
|
|
80
|
+
* ## Interceptors
|
|
81
|
+
*
|
|
82
|
+
* Cross-cutting concerns (logging, auth, metrics) attach via interceptors.
|
|
83
|
+
* See {@link registerInboundInterceptor} (wraps workflows) and
|
|
84
|
+
* {@link registerOutboundInterceptor} (wraps individual activity calls).
|
|
85
|
+
*
|
|
86
|
+
* ## Secured Workers
|
|
87
|
+
*
|
|
88
|
+
* For production isolation, workers can connect with scoped Postgres
|
|
89
|
+
* credentials that restrict access to specific task queues via stored
|
|
90
|
+
* procedures. See {@link WorkerService.create} and {@link provisionWorkerRole}.
|
|
273
91
|
*/
|
|
274
92
|
declare class DurableClass {
|
|
275
93
|
/**
|
|
@@ -277,33 +95,30 @@ declare class DurableClass {
|
|
|
277
95
|
*/
|
|
278
96
|
constructor();
|
|
279
97
|
/**
|
|
280
|
-
*
|
|
281
|
-
*
|
|
98
|
+
* Starts workflows, sends signals, and reads results. Instantiate
|
|
99
|
+
* with a connection, then use `client.workflow.start()` to launch
|
|
100
|
+
* a workflow and obtain a {@link Handle}.
|
|
282
101
|
*/
|
|
283
102
|
static Client: typeof ClientService;
|
|
284
103
|
/**
|
|
285
|
-
*
|
|
286
|
-
*
|
|
104
|
+
* Declares connection options (class + config) for Postgres.
|
|
105
|
+
* The actual connection is established lazily when a workflow
|
|
106
|
+
* or worker is started.
|
|
287
107
|
*/
|
|
288
108
|
static Connection: typeof ConnectionService;
|
|
289
|
-
/**
|
|
290
|
-
* @private
|
|
291
|
-
*/
|
|
109
|
+
/** @private */
|
|
292
110
|
static Search: typeof Search;
|
|
293
|
-
/**
|
|
294
|
-
* @private
|
|
295
|
-
*/
|
|
111
|
+
/** @private */
|
|
296
112
|
static Entity: typeof Entity;
|
|
297
113
|
/**
|
|
298
|
-
*
|
|
299
|
-
*
|
|
300
|
-
*
|
|
301
|
-
* is typically accessed via the Durable.Client class (workflow.getHandle).
|
|
114
|
+
* A handle to a running or completed workflow. Provides methods to
|
|
115
|
+
* read results, send signals, query state, cancel, or interrupt.
|
|
116
|
+
* Obtained via `client.workflow.start()` or `client.workflow.getHandle()`.
|
|
302
117
|
*/
|
|
303
118
|
static Handle: typeof WorkflowHandleService;
|
|
304
119
|
/**
|
|
305
|
-
*
|
|
306
|
-
*
|
|
120
|
+
* Hosts workflow and activity functions. Call `Worker.create()` with
|
|
121
|
+
* a connection, task queue, and workflow function to start processing.
|
|
307
122
|
*/
|
|
308
123
|
static Worker: typeof WorkerService;
|
|
309
124
|
/**
|
|
@@ -333,7 +148,7 @@ declare class DurableClass {
|
|
|
333
148
|
* sendEmail: (to: string, msg: string) => Promise<void>;
|
|
334
149
|
* }>({
|
|
335
150
|
* taskQueue: 'payment',
|
|
336
|
-
*
|
|
151
|
+
* retry: { maximumAttempts: 3 }
|
|
337
152
|
* });
|
|
338
153
|
*
|
|
339
154
|
* const result = await processPayment(amount);
|
|
@@ -350,23 +165,24 @@ declare class DurableClass {
|
|
|
350
165
|
*/
|
|
351
166
|
static registerActivityWorker: typeof WorkerService.registerActivityWorker;
|
|
352
167
|
/**
|
|
353
|
-
*
|
|
354
|
-
*
|
|
355
|
-
*
|
|
356
|
-
* context passed from the parent workflow.
|
|
168
|
+
* Activity-side context. Call `Durable.activity.getContext()` inside
|
|
169
|
+
* an activity function to access the activity name, arguments,
|
|
170
|
+
* parent workflow ID, and other execution metadata.
|
|
357
171
|
*/
|
|
358
172
|
static activity: typeof ActivityService;
|
|
359
173
|
/**
|
|
360
|
-
* The
|
|
361
|
-
*
|
|
362
|
-
*
|
|
174
|
+
* The workflow-internal API. Every method on this object
|
|
175
|
+
* (`proxyActivities`, `sleep`, `condition`, `signal`, `executeChild`,
|
|
176
|
+
* `continueAsNew`, `patched`, `CancellationScope`, etc.) is designed
|
|
177
|
+
* to be called **inside** a workflow function and participates in
|
|
178
|
+
* deterministic replay.
|
|
363
179
|
*/
|
|
364
180
|
static workflow: typeof WorkflowService;
|
|
365
181
|
/**
|
|
366
|
-
*
|
|
367
|
-
*
|
|
368
|
-
*
|
|
369
|
-
*
|
|
182
|
+
* Returns `true` if the error is an engine control-flow signal (replay
|
|
183
|
+
* suspension) rather than an application error. **Always check this in
|
|
184
|
+
* `catch` blocks inside workflows and interceptors** — swallowing an
|
|
185
|
+
* interruption breaks the replay system.
|
|
370
186
|
*/
|
|
371
187
|
static didInterrupt: typeof didInterrupt;
|
|
372
188
|
private static interceptorService;
|
|
@@ -378,8 +194,8 @@ declare class DurableClass {
|
|
|
378
194
|
* logging, metrics, or tracing.
|
|
379
195
|
*
|
|
380
196
|
* Workflow interceptors run inside the workflow's async local storage context,
|
|
381
|
-
* so all Durable workflow methods (`proxyActivities`, `
|
|
382
|
-
* `
|
|
197
|
+
* so all Durable workflow methods (`proxyActivities`, `sleep`, `condition`,
|
|
198
|
+
* `executeChild`, etc.) are available. When using Durable functions, always check
|
|
383
199
|
* for interruptions with `Durable.didInterrupt(err)` and rethrow them.
|
|
384
200
|
*
|
|
385
201
|
* @param interceptor The interceptor to register
|
|
@@ -387,7 +203,7 @@ declare class DurableClass {
|
|
|
387
203
|
* @example
|
|
388
204
|
* ```typescript
|
|
389
205
|
* // Logging interceptor
|
|
390
|
-
* Durable.
|
|
206
|
+
* Durable.registerInboundInterceptor({
|
|
391
207
|
* async execute(ctx, next) {
|
|
392
208
|
* console.log(`Workflow ${ctx.get('workflowName')} starting`);
|
|
393
209
|
* try {
|
|
@@ -403,28 +219,28 @@ declare class DurableClass {
|
|
|
403
219
|
* });
|
|
404
220
|
* ```
|
|
405
221
|
*/
|
|
406
|
-
static
|
|
222
|
+
static registerInboundInterceptor(interceptor: WorkflowInboundCallsInterceptor): void;
|
|
407
223
|
/**
|
|
408
|
-
* Clear all registered interceptors (both
|
|
224
|
+
* Clear all registered interceptors (both inbound and outbound).
|
|
409
225
|
*/
|
|
410
226
|
static clearInterceptors(): void;
|
|
411
227
|
/**
|
|
412
|
-
* Register an
|
|
228
|
+
* Register an outbound interceptor that wraps individual proxied
|
|
413
229
|
* activity calls within workflows. Interceptors execute in registration
|
|
414
230
|
* order (first registered is outermost) using the onion pattern.
|
|
415
231
|
*
|
|
416
|
-
*
|
|
232
|
+
* Outbound interceptors run inside the workflow's execution context
|
|
417
233
|
* and have access to all Durable workflow methods (`proxyActivities`,
|
|
418
|
-
* `
|
|
234
|
+
* `sleep`, `condition`, `executeChild`, etc.). The `activityCtx` parameter
|
|
419
235
|
* provides `activityName`, `args`, and `options` for the call being
|
|
420
236
|
* intercepted. The `workflowCtx` map provides workflow metadata
|
|
421
237
|
* (`workflowId`, `workflowName`, `namespace`, etc.).
|
|
422
238
|
*
|
|
423
|
-
* @param interceptor The
|
|
239
|
+
* @param interceptor The outbound interceptor to register
|
|
424
240
|
*
|
|
425
241
|
* @example
|
|
426
242
|
* ```typescript
|
|
427
|
-
* Durable.
|
|
243
|
+
* Durable.registerOutboundInterceptor({
|
|
428
244
|
* async execute(activityCtx, workflowCtx, next) {
|
|
429
245
|
* const start = Date.now();
|
|
430
246
|
* try {
|
|
@@ -439,18 +255,64 @@ declare class DurableClass {
|
|
|
439
255
|
* });
|
|
440
256
|
* ```
|
|
441
257
|
*/
|
|
442
|
-
static
|
|
258
|
+
static registerOutboundInterceptor(interceptor: WorkflowOutboundCallsInterceptor): void;
|
|
443
259
|
/**
|
|
444
|
-
* Clear all registered
|
|
260
|
+
* Clear all registered outbound interceptors
|
|
261
|
+
*/
|
|
262
|
+
static clearOutboundInterceptors(): void;
|
|
263
|
+
/**
|
|
264
|
+
* Register an activity inbound interceptor that wraps the actual activity
|
|
265
|
+
* function execution on the activity worker side. This runs inside the
|
|
266
|
+
* activity's `AsyncLocalStorage` context, NOT the workflow context.
|
|
267
|
+
*
|
|
268
|
+
* Use for logging, metrics, auth validation, or error enrichment at
|
|
269
|
+
* the point where the activity actually executes.
|
|
445
270
|
*/
|
|
446
|
-
static
|
|
271
|
+
static registerActivityInboundInterceptor(interceptor: ActivityInboundCallsInterceptor): void;
|
|
272
|
+
/**
|
|
273
|
+
* Clear all registered activity inbound interceptors.
|
|
274
|
+
*/
|
|
275
|
+
static clearActivityInboundInterceptors(): void;
|
|
447
276
|
/**
|
|
448
277
|
* Generate a unique identifier for workflow IDs
|
|
449
278
|
*/
|
|
450
279
|
static guid: typeof guid;
|
|
451
280
|
/**
|
|
452
|
-
*
|
|
453
|
-
*
|
|
281
|
+
* Provision a scoped Postgres role for a worker. The role can only
|
|
282
|
+
* dequeue, ack, and respond on its assigned stream names via stored
|
|
283
|
+
* procedures — zero direct table access.
|
|
284
|
+
*
|
|
285
|
+
* @example
|
|
286
|
+
* ```typescript
|
|
287
|
+
* const cred = await Durable.provisionWorkerRole({
|
|
288
|
+
* connection: { class: Postgres, options: adminOptions },
|
|
289
|
+
* streamNames: ['payment-activity'],
|
|
290
|
+
* });
|
|
291
|
+
*
|
|
292
|
+
* await Worker.create({
|
|
293
|
+
* connection: { class: Postgres, options: pgOptions },
|
|
294
|
+
* taskQueue: 'payment',
|
|
295
|
+
* workflow: paymentWorkflow,
|
|
296
|
+
* workerCredentials: cred,
|
|
297
|
+
* });
|
|
298
|
+
* ```
|
|
299
|
+
*/
|
|
300
|
+
static provisionWorkerRole: typeof import("../worker/credentials").provisionWorkerRole;
|
|
301
|
+
/** Rotate a secured worker role's password. */
|
|
302
|
+
static rotateWorkerPassword: typeof import("../worker/credentials").rotateWorkerPassword;
|
|
303
|
+
/** Revoke a secured worker role (disables login). */
|
|
304
|
+
static revokeWorkerRole: typeof import("../worker/credentials").revokeWorkerRole;
|
|
305
|
+
/** List all provisioned secured worker roles. */
|
|
306
|
+
static listWorkerRoles: typeof import("../worker/credentials").listWorkerRoles;
|
|
307
|
+
/**
|
|
308
|
+
* Register a global payload codec for encrypting/decrypting workflow
|
|
309
|
+
* data at rest. The codec's `encode`/`decode` methods are called
|
|
310
|
+
* automatically on all persisted workflow payloads.
|
|
311
|
+
*/
|
|
312
|
+
static registerCodec: typeof HotMesh.registerCodec;
|
|
313
|
+
/**
|
|
314
|
+
* Gracefully shut down all workers, clients, and connections.
|
|
315
|
+
* Call from your process signal handlers (`SIGTERM`, `SIGINT`).
|
|
454
316
|
*/
|
|
455
317
|
static shutdown(): Promise<void>;
|
|
456
318
|
}
|