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