@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
|
@@ -3,6 +3,7 @@ var _a;
|
|
|
3
3
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
4
|
exports.WorkerService = void 0;
|
|
5
5
|
const enums_1 = require("../../modules/enums");
|
|
6
|
+
const cancellationScope_1 = require("./workflow/cancellationScope");
|
|
6
7
|
const errors_1 = require("../../modules/errors");
|
|
7
8
|
const storage_1 = require("../../modules/storage");
|
|
8
9
|
const utils_1 = require("../../modules/utils");
|
|
@@ -10,30 +11,95 @@ const hotmesh_1 = require("../hotmesh");
|
|
|
10
11
|
const stream_1 = require("../../types/stream");
|
|
11
12
|
const search_1 = require("./search");
|
|
12
13
|
const factory_1 = require("./schemas/factory");
|
|
14
|
+
const telemetry_1 = require("./telemetry");
|
|
15
|
+
const telemetry_2 = require("../telemetry");
|
|
16
|
+
const telemetry_3 = require("../../types/telemetry");
|
|
13
17
|
const index_1 = require("./index");
|
|
14
18
|
/**
|
|
15
|
-
*
|
|
16
|
-
*
|
|
19
|
+
* Hosts workflow and activity functions, connecting them to Postgres
|
|
20
|
+
* for durable execution, replay, and automatic retry.
|
|
17
21
|
*
|
|
18
|
-
*
|
|
22
|
+
* ## Connection Modes
|
|
23
|
+
*
|
|
24
|
+
* ### Standard (legacy) — full admin access
|
|
25
|
+
*
|
|
26
|
+
* The worker connects with the same Postgres credentials as the engine.
|
|
27
|
+
* Simple to set up; all workers share the same connection pool.
|
|
28
|
+
*
|
|
29
|
+
* ```typescript
|
|
30
|
+
* const worker = await Durable.Worker.create({
|
|
31
|
+
* connection: {
|
|
32
|
+
* class: Postgres,
|
|
33
|
+
* options: { connectionString: 'postgres://user:pass@host:5432/hotmesh' },
|
|
34
|
+
* },
|
|
35
|
+
* taskQueue: 'orders',
|
|
36
|
+
* workflow: orderWorkflow,
|
|
37
|
+
* });
|
|
38
|
+
* ```
|
|
39
|
+
*
|
|
40
|
+
* ### Secured — scoped Postgres role (recommended for production)
|
|
41
|
+
*
|
|
42
|
+
* The worker connects as a restricted Postgres role that can only
|
|
43
|
+
* dequeue/ack/respond on its assigned stream names. All data access
|
|
44
|
+
* goes through SECURITY DEFINER stored procedures that validate the
|
|
45
|
+
* role's `app.allowed_streams` session variable before executing.
|
|
46
|
+
*
|
|
47
|
+
* **Step 1**: Provision a scoped credential (run once, from the engine/admin):
|
|
48
|
+
* ```typescript
|
|
49
|
+
* const cred = await Durable.provisionWorkerRole({
|
|
50
|
+
* connection: { class: Postgres, options: adminPgOptions },
|
|
51
|
+
* namespace: 'durable',
|
|
52
|
+
* streamNames: ['orders-activity'],
|
|
53
|
+
* });
|
|
54
|
+
* // cred = { roleName: 'hmsh_wrk_durable_orders_activity', password: '...' }
|
|
55
|
+
* ```
|
|
56
|
+
*
|
|
57
|
+
* **Step 2**: Pass the credential when creating the worker:
|
|
19
58
|
* ```typescript
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
*
|
|
59
|
+
* const worker = await Durable.Worker.create({
|
|
60
|
+
* connection: {
|
|
61
|
+
* class: Postgres,
|
|
62
|
+
* options: { host: 'pg.prod', port: 5432, database: 'hotmesh' },
|
|
63
|
+
* },
|
|
64
|
+
* taskQueue: 'orders',
|
|
65
|
+
* workflow: orderWorkflow,
|
|
66
|
+
* workerCredentials: { user: cred.roleName, password: cred.password },
|
|
67
|
+
* });
|
|
68
|
+
* ```
|
|
69
|
+
*
|
|
70
|
+
* The worker role **cannot**:
|
|
71
|
+
* - SELECT/INSERT/UPDATE/DELETE any table directly
|
|
72
|
+
* - Access `jobs`, `jobs_attributes`, or any engine tables
|
|
73
|
+
* - Dequeue messages from other workers' streams
|
|
74
|
+
* - LISTEN on other workers' notification channels
|
|
75
|
+
*
|
|
76
|
+
* See {@link Durable.provisionWorkerRole} for credential lifecycle management.
|
|
23
77
|
*
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
*
|
|
27
|
-
*
|
|
28
|
-
*
|
|
29
|
-
*
|
|
30
|
-
*
|
|
31
|
-
*
|
|
32
|
-
*
|
|
78
|
+
* ## Telemetry
|
|
79
|
+
*
|
|
80
|
+
* Workers automatically emit OpenTelemetry spans when an OTel SDK is
|
|
81
|
+
* registered. Initialize the SDK **before** calling `create()`:
|
|
82
|
+
*
|
|
83
|
+
* ```typescript
|
|
84
|
+
* import { NodeSDK } from '@opentelemetry/sdk-node';
|
|
85
|
+
* import { OTLPTraceExporter } from '@opentelemetry/exporter-trace-otlp-proto';
|
|
86
|
+
* import { resourceFromAttributes } from '@opentelemetry/resources';
|
|
87
|
+
* import { ATTR_SERVICE_NAME } from '@opentelemetry/semantic-conventions';
|
|
33
88
|
*
|
|
34
|
-
*
|
|
35
|
-
* }
|
|
89
|
+
* const sdk = new NodeSDK({
|
|
90
|
+
* resource: resourceFromAttributes({ [ATTR_SERVICE_NAME]: 'my-service' }),
|
|
91
|
+
* traceExporter: new OTLPTraceExporter({
|
|
92
|
+
* url: 'https://api.honeycomb.io/v1/traces',
|
|
93
|
+
* headers: { 'x-honeycomb-team': process.env.HONEYCOMB_API_KEY },
|
|
94
|
+
* }),
|
|
95
|
+
* });
|
|
96
|
+
* sdk.start();
|
|
36
97
|
* ```
|
|
98
|
+
*
|
|
99
|
+
* | `HMSH_TELEMETRY` | Spans emitted |
|
|
100
|
+
* |-------|---------------|
|
|
101
|
+
* | `'info'` (default) | `WORKFLOW/START`, `WORKFLOW/COMPLETE`, `WORKFLOW/ERROR`, `ACTIVITY/{name}` |
|
|
102
|
+
* | `'debug'` | All `info` spans + `DISPATCH/RETURN` per operation + engine internals |
|
|
37
103
|
*/
|
|
38
104
|
class WorkerService {
|
|
39
105
|
static hashOptions(connection) {
|
|
@@ -151,7 +217,7 @@ class WorkerService {
|
|
|
151
217
|
* sendEmail: (to: string, subject: string) => Promise<void>;
|
|
152
218
|
* }>({
|
|
153
219
|
* taskQueue: 'payment',
|
|
154
|
-
*
|
|
220
|
+
* retry: { maximumAttempts: 3 }
|
|
155
221
|
* });
|
|
156
222
|
*
|
|
157
223
|
* const result = await processPayment(amount);
|
|
@@ -180,28 +246,47 @@ class WorkerService {
|
|
|
180
246
|
* taskQueue: 'shared'
|
|
181
247
|
* }, { auditLog, collectMetrics }, 'shared');
|
|
182
248
|
*
|
|
183
|
-
* const interceptor:
|
|
249
|
+
* const interceptor: WorkflowInboundCallsInterceptor = {
|
|
184
250
|
* async execute(ctx, next) {
|
|
185
251
|
* const { auditLog } = Durable.workflow.proxyActivities<{
|
|
186
252
|
* auditLog: (id: string, action: string) => Promise<void>;
|
|
187
253
|
* }>({
|
|
188
254
|
* taskQueue: 'shared',
|
|
189
|
-
*
|
|
255
|
+
* retry: { maximumAttempts: 3 }
|
|
190
256
|
* });
|
|
191
257
|
* await auditLog(ctx.get('workflowId'), 'started');
|
|
192
258
|
* return next();
|
|
193
259
|
* }
|
|
194
260
|
* };
|
|
195
261
|
* ```
|
|
262
|
+
*
|
|
263
|
+
* @example
|
|
264
|
+
* ```typescript
|
|
265
|
+
* // Secured worker with scoped Postgres credentials (VNF-style isolation)
|
|
266
|
+
* // Step 1: Admin provisions a credential (one-time)
|
|
267
|
+
* const cred = await Durable.provisionWorkerRole({
|
|
268
|
+
* connection: { class: Postgres, options: adminOptions },
|
|
269
|
+
* streamNames: ['payment-activity'],
|
|
270
|
+
* });
|
|
271
|
+
*
|
|
272
|
+
* // Step 2: Worker connects with scoped role — can only access payment-activity
|
|
273
|
+
* await Durable.registerActivityWorker({
|
|
274
|
+
* connection: { class: Postgres, options: { host: 'pg.prod', database: 'hotmesh' } },
|
|
275
|
+
* taskQueue: 'payment',
|
|
276
|
+
* workerCredentials: { user: cred.roleName, password: cred.password },
|
|
277
|
+
* }, { processPayment, refundPayment });
|
|
278
|
+
* ```
|
|
196
279
|
*/
|
|
197
280
|
static async registerActivityWorker(config, activities, activityTaskQueue) {
|
|
281
|
+
// Register as durable namespace so engine-layer spans are suppressed in 'info' mode
|
|
282
|
+
const targetNamespace = config?.namespace ?? factory_1.APP_ID;
|
|
283
|
+
telemetry_2.TelemetryService.durableNamespaces.add(targetNamespace);
|
|
198
284
|
// Register activities globally in the registry
|
|
199
285
|
WorkerService.registerActivities(activities);
|
|
200
286
|
// Use provided activityTaskQueue or fall back to config.taskQueue
|
|
201
287
|
const taskQueue = activityTaskQueue || config.taskQueue || 'durable-activities';
|
|
202
288
|
// Append '-activity' suffix for the worker topic
|
|
203
289
|
const activityTopic = `${taskQueue}-activity`;
|
|
204
|
-
const targetNamespace = config?.namespace ?? factory_1.APP_ID;
|
|
205
290
|
const optionsHash = WorkerService.hashOptions(config?.connection);
|
|
206
291
|
const targetTopic = `${optionsHash}.${targetNamespace}.${activityTopic}`;
|
|
207
292
|
// Return existing worker if already initialized (idempotent)
|
|
@@ -209,19 +294,21 @@ class WorkerService {
|
|
|
209
294
|
return await WorkerService.instances.get(targetTopic);
|
|
210
295
|
}
|
|
211
296
|
// Create activity worker that listens on '{taskQueue}-activity' topic
|
|
297
|
+
const workerEntry = {
|
|
298
|
+
topic: activityTopic,
|
|
299
|
+
connection: config.connection,
|
|
300
|
+
callback: WorkerService.createActivityCallback(),
|
|
301
|
+
};
|
|
302
|
+
if (config.workerCredentials) {
|
|
303
|
+
workerEntry.workerCredentials = config.workerCredentials;
|
|
304
|
+
}
|
|
212
305
|
const hotMeshWorker = await hotmesh_1.HotMesh.init({
|
|
213
306
|
guid: config.guid ? `${config.guid}XA` : undefined,
|
|
214
307
|
taskQueue,
|
|
215
308
|
logLevel: config.options?.logLevel ?? enums_1.HMSH_LOGLEVEL,
|
|
216
309
|
appId: targetNamespace,
|
|
217
310
|
engine: { connection: config.connection },
|
|
218
|
-
workers: [
|
|
219
|
-
{
|
|
220
|
-
topic: activityTopic,
|
|
221
|
-
connection: config.connection,
|
|
222
|
-
callback: WorkerService.createActivityCallback(),
|
|
223
|
-
},
|
|
224
|
-
],
|
|
311
|
+
workers: [workerEntry],
|
|
225
312
|
});
|
|
226
313
|
WorkerService.instances.set(targetTopic, hotMeshWorker);
|
|
227
314
|
return hotMeshWorker;
|
|
@@ -232,6 +319,7 @@ class WorkerService {
|
|
|
232
319
|
*/
|
|
233
320
|
static createActivityCallback() {
|
|
234
321
|
return async (data) => {
|
|
322
|
+
let activitySpan = null;
|
|
235
323
|
try {
|
|
236
324
|
//always run the activity function when instructed; return the response
|
|
237
325
|
const activityInput = data.data;
|
|
@@ -243,10 +331,28 @@ class WorkerService {
|
|
|
243
331
|
const activityContext = new Map();
|
|
244
332
|
activityContext.set('activityName', activityName);
|
|
245
333
|
activityContext.set('arguments', activityInput.arguments);
|
|
246
|
-
activityContext.set('
|
|
334
|
+
activityContext.set('headers', activityInput.headers ?? {});
|
|
247
335
|
activityContext.set('workflowId', activityInput.workflowId);
|
|
248
336
|
activityContext.set('workflowTopic', activityInput.workflowTopic);
|
|
249
|
-
|
|
337
|
+
// Start an ACTIVITY span if telemetry is enabled
|
|
338
|
+
const trc = data.metadata.trc;
|
|
339
|
+
const spn = data.metadata.spn;
|
|
340
|
+
activitySpan =
|
|
341
|
+
telemetry_1.DurableTelemetryService.isEnabled() && trc && spn
|
|
342
|
+
? telemetry_1.DurableTelemetryService.startSpan(trc, spn, `ACTIVITY/${activityName}`, {
|
|
343
|
+
'durable.activity.name': activityName,
|
|
344
|
+
'durable.workflow.id': activityInput.workflowId,
|
|
345
|
+
})
|
|
346
|
+
: null;
|
|
347
|
+
const interceptorService = index_1.Durable.getInterceptorService();
|
|
348
|
+
const pojoResponse = await storage_1.activityAsyncLocalStorage.run(activityContext, () => {
|
|
349
|
+
const executeFn = () => activityFunction.apply(null, activityInput.arguments);
|
|
350
|
+
if (interceptorService?.activityInbound?.length > 0) {
|
|
351
|
+
return interceptorService.executeActivityInboundChain(activityName, activityInput.arguments, executeFn);
|
|
352
|
+
}
|
|
353
|
+
return executeFn();
|
|
354
|
+
});
|
|
355
|
+
activitySpan?.end();
|
|
250
356
|
return {
|
|
251
357
|
status: stream_1.StreamStatus.SUCCESS,
|
|
252
358
|
metadata: { ...data.metadata },
|
|
@@ -254,6 +360,11 @@ class WorkerService {
|
|
|
254
360
|
};
|
|
255
361
|
}
|
|
256
362
|
catch (err) {
|
|
363
|
+
activitySpan?.setStatus({
|
|
364
|
+
code: telemetry_3.SpanStatusCode.ERROR,
|
|
365
|
+
message: err.message,
|
|
366
|
+
});
|
|
367
|
+
activitySpan?.end();
|
|
257
368
|
// Log error (note: we don't have access to this.activityRunner here)
|
|
258
369
|
console.error('durable-worker-activity-err', {
|
|
259
370
|
name: err.name,
|
|
@@ -324,7 +435,7 @@ class WorkerService {
|
|
|
324
435
|
};
|
|
325
436
|
}
|
|
326
437
|
/**
|
|
327
|
-
*
|
|
438
|
+
* Creates and starts a workflow worker.
|
|
328
439
|
*
|
|
329
440
|
* @example
|
|
330
441
|
* ```typescript
|
|
@@ -349,6 +460,9 @@ class WorkerService {
|
|
|
349
460
|
* ```
|
|
350
461
|
*/
|
|
351
462
|
static async create(config) {
|
|
463
|
+
// Register as durable namespace so engine-layer spans are suppressed in 'info' mode
|
|
464
|
+
const targetNamespace = config?.namespace ?? factory_1.APP_ID;
|
|
465
|
+
telemetry_2.TelemetryService.durableNamespaces.add(targetNamespace);
|
|
352
466
|
const workflow = config.workflow;
|
|
353
467
|
const [workflowFunctionName, workflowFunction] = WorkerService.resolveWorkflowTarget(workflow);
|
|
354
468
|
// Separate taskQueue from workflowName - no concatenation for stream_name
|
|
@@ -356,6 +470,10 @@ class WorkerService {
|
|
|
356
470
|
const activityTopic = `${taskQueue}-activity`;
|
|
357
471
|
// workflowTopic remains concatenated for engine-internal routing (graph.subscribes)
|
|
358
472
|
const workflowTopic = `${taskQueue}-${workflowFunctionName}`;
|
|
473
|
+
// Register activities passed via config
|
|
474
|
+
if (config.activities) {
|
|
475
|
+
WorkerService.registerActivities(config.activities);
|
|
476
|
+
}
|
|
359
477
|
//initialize supporting workflows
|
|
360
478
|
const worker = new WorkerService();
|
|
361
479
|
worker.activityRunner = await worker.initActivityWorker(config, activityTopic);
|
|
@@ -398,19 +516,21 @@ class WorkerService {
|
|
|
398
516
|
if (WorkerService.instances.has(targetTopic)) {
|
|
399
517
|
return await WorkerService.instances.get(targetTopic);
|
|
400
518
|
}
|
|
519
|
+
const workerEntry = {
|
|
520
|
+
topic: activityTopic,
|
|
521
|
+
connection: providerConfig,
|
|
522
|
+
callback: this.wrapActivityFunctions().bind(this),
|
|
523
|
+
};
|
|
524
|
+
if (config.workerCredentials) {
|
|
525
|
+
workerEntry.workerCredentials = config.workerCredentials;
|
|
526
|
+
}
|
|
401
527
|
const hotMeshWorker = await hotmesh_1.HotMesh.init({
|
|
402
528
|
guid: config.guid ? `${config.guid}XA` : undefined,
|
|
403
529
|
taskQueue: config.taskQueue,
|
|
404
530
|
logLevel: config.options?.logLevel ?? enums_1.HMSH_LOGLEVEL,
|
|
405
531
|
appId: targetNamespace,
|
|
406
532
|
engine: { connection: providerConfig },
|
|
407
|
-
workers: [
|
|
408
|
-
{
|
|
409
|
-
topic: activityTopic,
|
|
410
|
-
connection: providerConfig,
|
|
411
|
-
callback: this.wrapActivityFunctions().bind(this),
|
|
412
|
-
},
|
|
413
|
-
],
|
|
533
|
+
workers: [workerEntry],
|
|
414
534
|
});
|
|
415
535
|
WorkerService.instances.set(targetTopic, hotMeshWorker);
|
|
416
536
|
return hotMeshWorker;
|
|
@@ -420,6 +540,7 @@ class WorkerService {
|
|
|
420
540
|
*/
|
|
421
541
|
wrapActivityFunctions() {
|
|
422
542
|
return async (data) => {
|
|
543
|
+
let activitySpan = null;
|
|
423
544
|
try {
|
|
424
545
|
//always run the activity function when instructed; return the response
|
|
425
546
|
const activityInput = data.data;
|
|
@@ -428,10 +549,39 @@ class WorkerService {
|
|
|
428
549
|
const activityContext = new Map();
|
|
429
550
|
activityContext.set('activityName', activityName);
|
|
430
551
|
activityContext.set('arguments', activityInput.arguments);
|
|
431
|
-
activityContext.set('
|
|
552
|
+
activityContext.set('headers', activityInput.headers ?? {});
|
|
432
553
|
activityContext.set('workflowId', activityInput.workflowId);
|
|
433
554
|
activityContext.set('workflowTopic', activityInput.workflowTopic);
|
|
434
|
-
const
|
|
555
|
+
const interceptorService = index_1.Durable.getInterceptorService();
|
|
556
|
+
// Start an ACTIVITY span if telemetry is enabled
|
|
557
|
+
const trc = data.metadata.trc;
|
|
558
|
+
const spn = data.metadata.spn;
|
|
559
|
+
activitySpan =
|
|
560
|
+
telemetry_1.DurableTelemetryService.isEnabled() && trc && spn
|
|
561
|
+
? telemetry_1.DurableTelemetryService.startSpan(trc, spn, `ACTIVITY/${activityName}`, {
|
|
562
|
+
'durable.activity.name': activityName,
|
|
563
|
+
'durable.workflow.id': activityInput.workflowId,
|
|
564
|
+
})
|
|
565
|
+
: null;
|
|
566
|
+
const activityPromise = storage_1.activityAsyncLocalStorage.run(activityContext, () => {
|
|
567
|
+
const executeFn = () => activityFunction.apply(this, activityInput.arguments);
|
|
568
|
+
if (interceptorService?.activityInbound?.length > 0) {
|
|
569
|
+
return interceptorService.executeActivityInboundChain(activityName, activityInput.arguments, executeFn);
|
|
570
|
+
}
|
|
571
|
+
return executeFn();
|
|
572
|
+
});
|
|
573
|
+
let pojoResponse;
|
|
574
|
+
if (activityInput.startToCloseTimeout && activityInput.startToCloseTimeout > 0) {
|
|
575
|
+
const timeoutMs = activityInput.startToCloseTimeout * 1000;
|
|
576
|
+
pojoResponse = await Promise.race([
|
|
577
|
+
activityPromise,
|
|
578
|
+
new Promise((_, reject) => setTimeout(() => reject(new errors_1.DurableTimeoutError(`Activity '${activityName}' exceeded startToCloseTimeout of ${activityInput.startToCloseTimeout}s`)), timeoutMs)),
|
|
579
|
+
]);
|
|
580
|
+
}
|
|
581
|
+
else {
|
|
582
|
+
pojoResponse = await activityPromise;
|
|
583
|
+
}
|
|
584
|
+
activitySpan?.end();
|
|
435
585
|
return {
|
|
436
586
|
status: stream_1.StreamStatus.SUCCESS,
|
|
437
587
|
metadata: { ...data.metadata },
|
|
@@ -439,6 +589,11 @@ class WorkerService {
|
|
|
439
589
|
};
|
|
440
590
|
}
|
|
441
591
|
catch (err) {
|
|
592
|
+
activitySpan?.setStatus({
|
|
593
|
+
code: telemetry_3.SpanStatusCode.ERROR,
|
|
594
|
+
message: err.message,
|
|
595
|
+
});
|
|
596
|
+
activitySpan?.end();
|
|
442
597
|
this.activityRunner.engine.logger.error('durable-worker-activity-err', {
|
|
443
598
|
name: err.name,
|
|
444
599
|
message: err.message,
|
|
@@ -489,20 +644,22 @@ class WorkerService {
|
|
|
489
644
|
const targetNamespace = config?.namespace ?? factory_1.APP_ID;
|
|
490
645
|
const optionsHash = WorkerService.hashOptions(config?.connection);
|
|
491
646
|
const targetTopic = `${optionsHash}.${targetNamespace}.${workflowTopic}`;
|
|
647
|
+
const workerEntry = {
|
|
648
|
+
topic: taskQueue,
|
|
649
|
+
workflowName: workflowFunctionName,
|
|
650
|
+
connection: providerConfig,
|
|
651
|
+
callback: this.wrapWorkflowFunction(workflowFunction, workflowTopic, workflowFunctionName, config).bind(this),
|
|
652
|
+
};
|
|
653
|
+
if (config.workerCredentials) {
|
|
654
|
+
workerEntry.workerCredentials = config.workerCredentials;
|
|
655
|
+
}
|
|
492
656
|
const hotMeshWorker = await hotmesh_1.HotMesh.init({
|
|
493
657
|
guid: config.guid,
|
|
494
658
|
taskQueue: config.taskQueue,
|
|
495
659
|
logLevel: config.options?.logLevel ?? enums_1.HMSH_LOGLEVEL,
|
|
496
660
|
appId: config.namespace ?? factory_1.APP_ID,
|
|
497
661
|
engine: { connection: providerConfig },
|
|
498
|
-
workers: [
|
|
499
|
-
{
|
|
500
|
-
topic: taskQueue,
|
|
501
|
-
workflowName: workflowFunctionName,
|
|
502
|
-
connection: providerConfig,
|
|
503
|
-
callback: this.wrapWorkflowFunction(workflowFunction, workflowTopic, workflowFunctionName, config).bind(this),
|
|
504
|
-
},
|
|
505
|
-
],
|
|
662
|
+
workers: [workerEntry],
|
|
506
663
|
});
|
|
507
664
|
WorkerService.instances.set(targetTopic, hotMeshWorker);
|
|
508
665
|
return hotMeshWorker;
|
|
@@ -514,7 +671,19 @@ class WorkerService {
|
|
|
514
671
|
return async (data) => {
|
|
515
672
|
const counter = { counter: 0 };
|
|
516
673
|
const interruptionRegistry = [];
|
|
674
|
+
const patchMarkers = {};
|
|
517
675
|
let isProcessing = false;
|
|
676
|
+
// Injects accumulated patch markers into any worker response so the
|
|
677
|
+
// engine can persist them via the YAML schema's job.maps mechanism.
|
|
678
|
+
// Include patchMarkers only when non-empty. The schema's
|
|
679
|
+
// job.maps patch-marker[-] is a no-op when the reference is absent.
|
|
680
|
+
const withPatchMarkers = (response) => {
|
|
681
|
+
if (Object.keys(patchMarkers).length > 0) {
|
|
682
|
+
response.data = response.data || {};
|
|
683
|
+
response.data.patchMarkers = patchMarkers;
|
|
684
|
+
}
|
|
685
|
+
return response;
|
|
686
|
+
};
|
|
518
687
|
try {
|
|
519
688
|
//incoming data payload has arguments and workflowId
|
|
520
689
|
const workflowInput = data.data;
|
|
@@ -523,6 +692,7 @@ class WorkerService {
|
|
|
523
692
|
context.set('expire', workflowInput.expire);
|
|
524
693
|
context.set('counter', counter);
|
|
525
694
|
context.set('interruptionRegistry', interruptionRegistry);
|
|
695
|
+
context.set('patchMarkers', patchMarkers);
|
|
526
696
|
context.set('connection', config.connection);
|
|
527
697
|
context.set('namespace', config.namespace ?? factory_1.APP_ID);
|
|
528
698
|
context.set('raw', data);
|
|
@@ -542,6 +712,13 @@ class WorkerService {
|
|
|
542
712
|
context.set('workflowDimension', workflowInput.workflowDimension);
|
|
543
713
|
replayQuery = `-*${workflowInput.workflowDimension}-*`;
|
|
544
714
|
}
|
|
715
|
+
else if (workflowInput.continueGeneration) {
|
|
716
|
+
//continueAsNew: use generation prefix for replay isolation;
|
|
717
|
+
//old generation keys remain but are invisible to the new execution
|
|
718
|
+
const genPrefix = `$${workflowInput.continueGeneration}`;
|
|
719
|
+
context.set('workflowDimension', genPrefix);
|
|
720
|
+
replayQuery = `-*${genPrefix}-*`;
|
|
721
|
+
}
|
|
545
722
|
else {
|
|
546
723
|
//last letter of words like 'hook', 'sleep', 'wait', 'signal', 'search', 'start', 'proxy', 'child', 'collator', 'trace', 'enrich', 'publish'
|
|
547
724
|
replayQuery = '-*[ehklptydr]-*';
|
|
@@ -558,6 +735,15 @@ class WorkerService {
|
|
|
558
735
|
context.set('activityInterceptorService', index_1.Durable.getInterceptorService());
|
|
559
736
|
// Execute workflow with interceptors
|
|
560
737
|
const workflowResponse = await storage_1.asyncLocalStorage.run(context, async () => {
|
|
738
|
+
// Emit WORKFLOW/START on first execution (not replay)
|
|
739
|
+
if (telemetry_1.DurableTelemetryService.isEnabled() &&
|
|
740
|
+
Object.keys(replay).length === 0) {
|
|
741
|
+
telemetry_1.DurableTelemetryService.emitPointSpan(data.metadata.trc, data.metadata.spn, `WORKFLOW/START/${workflowFunctionName}`, {
|
|
742
|
+
'durable.workflow.id': workflowInput.workflowId,
|
|
743
|
+
'durable.workflow.name': workflowFunctionName,
|
|
744
|
+
'durable.workflow.topic': workflowTopic,
|
|
745
|
+
});
|
|
746
|
+
}
|
|
561
747
|
// Get the interceptor service
|
|
562
748
|
const interceptorService = index_1.Durable.getInterceptorService();
|
|
563
749
|
// Create the workflow execution function
|
|
@@ -565,8 +751,16 @@ class WorkerService {
|
|
|
565
751
|
return await workflowFunction.apply(this, workflowInput.arguments);
|
|
566
752
|
};
|
|
567
753
|
// Execute the workflow through the interceptor chain
|
|
568
|
-
return await interceptorService.
|
|
754
|
+
return await interceptorService.executeInboundChain(context, execWorkflow);
|
|
569
755
|
});
|
|
756
|
+
// Emit WORKFLOW/COMPLETE when the workflow finishes successfully
|
|
757
|
+
if (telemetry_1.DurableTelemetryService.isEnabled()) {
|
|
758
|
+
telemetry_1.DurableTelemetryService.emitPointSpan(data.metadata.trc, data.metadata.spn, `WORKFLOW/COMPLETE/${workflowFunctionName}`, {
|
|
759
|
+
'durable.workflow.id': workflowInput.workflowId,
|
|
760
|
+
'durable.workflow.name': workflowFunctionName,
|
|
761
|
+
'durable.workflow.topic': workflowTopic,
|
|
762
|
+
});
|
|
763
|
+
}
|
|
570
764
|
//if the embedded function has a try/catch, it can interrup the throw
|
|
571
765
|
// throw here to interrupt the workflow if the embedded function caught and suppressed
|
|
572
766
|
if (interruptionRegistry.length > 0) {
|
|
@@ -580,6 +774,8 @@ class WorkerService {
|
|
|
580
774
|
throw new errors_1.DurableChildError(payload);
|
|
581
775
|
case 'DurableSleepError':
|
|
582
776
|
throw new errors_1.DurableSleepError(payload);
|
|
777
|
+
case 'DurableContinueAsNewError':
|
|
778
|
+
throw new errors_1.DurableContinueAsNewError(payload);
|
|
583
779
|
case 'DurableTimeoutError':
|
|
584
780
|
throw new errors_1.DurableTimeoutError(payload.message, payload.stack);
|
|
585
781
|
case 'DurableMaxedError':
|
|
@@ -592,12 +788,12 @@ class WorkerService {
|
|
|
592
788
|
throw new errors_1.DurableRetryError(`Unknown interruption type: ${payload.type}`);
|
|
593
789
|
}
|
|
594
790
|
}
|
|
595
|
-
return {
|
|
791
|
+
return withPatchMarkers({
|
|
596
792
|
code: 200,
|
|
597
793
|
status: stream_1.StreamStatus.SUCCESS,
|
|
598
794
|
metadata: { ...data.metadata },
|
|
599
795
|
data: { response: workflowResponse, done: true },
|
|
600
|
-
};
|
|
796
|
+
});
|
|
601
797
|
}
|
|
602
798
|
catch (err) {
|
|
603
799
|
if (isProcessing) {
|
|
@@ -606,12 +802,12 @@ class WorkerService {
|
|
|
606
802
|
if (err instanceof errors_1.DurableWaitForError ||
|
|
607
803
|
interruptionRegistry.length > 1) {
|
|
608
804
|
isProcessing = true;
|
|
609
|
-
//NOTE: this type is spawned when `Promise.all` is used OR if the interruption is a `
|
|
805
|
+
//NOTE: this type is spawned when `Promise.all` is used OR if the interruption is a `condition`
|
|
610
806
|
const workflowInput = data.data;
|
|
611
807
|
const execIndex = counter.counter - interruptionRegistry.length + 1;
|
|
612
808
|
const { workflowId, workflowTopic, workflowDimension, originJobId, expire, } = workflowInput;
|
|
613
809
|
const collatorFlowId = `${(0, utils_1.guid)()}$C`;
|
|
614
|
-
return {
|
|
810
|
+
return withPatchMarkers({
|
|
615
811
|
status: stream_1.StreamStatus.SUCCESS,
|
|
616
812
|
code: enums_1.HMSH_CODE_DURABLE_ALL,
|
|
617
813
|
metadata: { ...data.metadata },
|
|
@@ -627,12 +823,12 @@ class WorkerService {
|
|
|
627
823
|
workflowTopic: workflowTopic,
|
|
628
824
|
expire,
|
|
629
825
|
},
|
|
630
|
-
};
|
|
826
|
+
});
|
|
631
827
|
}
|
|
632
828
|
else if (err instanceof errors_1.DurableSleepError) {
|
|
633
829
|
//return the sleep interruption
|
|
634
830
|
isProcessing = true;
|
|
635
|
-
return {
|
|
831
|
+
return withPatchMarkers({
|
|
636
832
|
status: stream_1.StreamStatus.SUCCESS,
|
|
637
833
|
code: err.code,
|
|
638
834
|
metadata: { ...data.metadata },
|
|
@@ -647,12 +843,12 @@ class WorkerService {
|
|
|
647
843
|
index: err.index,
|
|
648
844
|
workflowDimension: err.workflowDimension,
|
|
649
845
|
},
|
|
650
|
-
};
|
|
846
|
+
});
|
|
651
847
|
}
|
|
652
848
|
else if (err instanceof errors_1.DurableProxyError) {
|
|
653
849
|
//return the proxyActivity interruption
|
|
654
850
|
isProcessing = true;
|
|
655
|
-
return {
|
|
851
|
+
return withPatchMarkers({
|
|
656
852
|
status: stream_1.StreamStatus.SUCCESS,
|
|
657
853
|
code: err.code,
|
|
658
854
|
metadata: { ...data.metadata },
|
|
@@ -665,7 +861,7 @@ class WorkerService {
|
|
|
665
861
|
dimension: err.workflowDimension,
|
|
666
862
|
}),
|
|
667
863
|
arguments: err.arguments,
|
|
668
|
-
|
|
864
|
+
headers: err.headers,
|
|
669
865
|
workflowDimension: err.workflowDimension,
|
|
670
866
|
index: err.index,
|
|
671
867
|
originJobId: err.originJobId,
|
|
@@ -675,10 +871,12 @@ class WorkerService {
|
|
|
675
871
|
workflowTopic: err.workflowTopic,
|
|
676
872
|
activityName: err.activityName,
|
|
677
873
|
backoffCoefficient: err.backoffCoefficient,
|
|
874
|
+
initialInterval: err.initialInterval,
|
|
678
875
|
maximumAttempts: err.maximumAttempts,
|
|
679
876
|
maximumInterval: err.maximumInterval,
|
|
877
|
+
startToCloseTimeout: err.startToCloseTimeout,
|
|
680
878
|
},
|
|
681
|
-
};
|
|
879
|
+
});
|
|
682
880
|
}
|
|
683
881
|
else if (err instanceof errors_1.DurableChildError) {
|
|
684
882
|
//return the child interruption
|
|
@@ -688,7 +886,7 @@ class WorkerService {
|
|
|
688
886
|
workflowId: err.workflowId,
|
|
689
887
|
dimension: err.workflowDimension,
|
|
690
888
|
};
|
|
691
|
-
return {
|
|
889
|
+
return withPatchMarkers({
|
|
692
890
|
status: stream_1.StreamStatus.SUCCESS,
|
|
693
891
|
code: err.code,
|
|
694
892
|
metadata: { ...data.metadata },
|
|
@@ -698,6 +896,7 @@ class WorkerService {
|
|
|
698
896
|
backoffCoefficient: err.backoffCoefficient || enums_1.HMSH_DURABLE_EXP_BACKOFF,
|
|
699
897
|
code: err.code,
|
|
700
898
|
index: err.index,
|
|
899
|
+
initialInterval: err.initialInterval,
|
|
701
900
|
message: JSON.stringify(msg),
|
|
702
901
|
maximumAttempts: err.maximumAttempts || enums_1.HMSH_DURABLE_MAX_ATTEMPTS,
|
|
703
902
|
maximumInterval: err.maximumInterval || (0, utils_1.s)(enums_1.HMSH_DURABLE_MAX_INTERVAL),
|
|
@@ -713,12 +912,54 @@ class WorkerService {
|
|
|
713
912
|
taskQueue: err.taskQueue,
|
|
714
913
|
workflowName: err.workflowName,
|
|
715
914
|
},
|
|
716
|
-
};
|
|
915
|
+
});
|
|
916
|
+
}
|
|
917
|
+
else if (err instanceof errors_1.DurableContinueAsNewError) {
|
|
918
|
+
//return the continueAsNew interruption
|
|
919
|
+
isProcessing = true;
|
|
920
|
+
return withPatchMarkers({
|
|
921
|
+
status: stream_1.StreamStatus.SUCCESS,
|
|
922
|
+
code: err.code,
|
|
923
|
+
metadata: { ...data.metadata },
|
|
924
|
+
data: {
|
|
925
|
+
code: err.code,
|
|
926
|
+
arguments: err.arguments,
|
|
927
|
+
index: err.index,
|
|
928
|
+
workflowDimension: err.workflowDimension,
|
|
929
|
+
},
|
|
930
|
+
});
|
|
931
|
+
}
|
|
932
|
+
if (err instanceof cancellationScope_1.CancelledFailure) {
|
|
933
|
+
// CancelledFailure that wasn't caught by the workflow:
|
|
934
|
+
// treat as fatal (no retry) so the workflow terminates.
|
|
935
|
+
isProcessing = true;
|
|
936
|
+
return withPatchMarkers({
|
|
937
|
+
status: stream_1.StreamStatus.SUCCESS,
|
|
938
|
+
code: enums_1.HMSH_CODE_DURABLE_FATAL,
|
|
939
|
+
metadata: { ...data.metadata },
|
|
940
|
+
data: {
|
|
941
|
+
$error: {
|
|
942
|
+
message: err.message,
|
|
943
|
+
type: 'CancelledFailure',
|
|
944
|
+
name: 'CancelledFailure',
|
|
945
|
+
stack: err.stack,
|
|
946
|
+
code: enums_1.HMSH_CODE_DURABLE_FATAL,
|
|
947
|
+
},
|
|
948
|
+
},
|
|
949
|
+
});
|
|
717
950
|
}
|
|
718
951
|
// ALL other errors are actual fatal errors (598, 597, 596)
|
|
719
952
|
// OR will be retried (599)
|
|
953
|
+
if (telemetry_1.DurableTelemetryService.isEnabled()) {
|
|
954
|
+
telemetry_1.DurableTelemetryService.emitPointSpan(data.metadata.trc, data.metadata.spn, `WORKFLOW/ERROR/${workflowFunctionName}`, {
|
|
955
|
+
'durable.workflow.id': data.data.workflowId,
|
|
956
|
+
'durable.workflow.name': workflowFunctionName,
|
|
957
|
+
'error.message': err.message,
|
|
958
|
+
'error.type': err.name || 'Error',
|
|
959
|
+
}, telemetry_3.SpanStatusCode.ERROR, err.message);
|
|
960
|
+
}
|
|
720
961
|
isProcessing = true;
|
|
721
|
-
return {
|
|
962
|
+
return withPatchMarkers({
|
|
722
963
|
status: stream_1.StreamStatus.SUCCESS,
|
|
723
964
|
code: err.code || new errors_1.DurableRetryError(err.message).code,
|
|
724
965
|
metadata: { ...data.metadata },
|
|
@@ -731,7 +972,7 @@ class WorkerService {
|
|
|
731
972
|
code: err.code || new errors_1.DurableRetryError(err.message).code,
|
|
732
973
|
},
|
|
733
974
|
},
|
|
734
|
-
};
|
|
975
|
+
});
|
|
735
976
|
}
|
|
736
977
|
};
|
|
737
978
|
}
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* multiple durable operations concurrently within a workflow function.
|
|
6
6
|
*
|
|
7
7
|
* In most cases, standard `Promise.all` works correctly for Durable
|
|
8
|
-
* operations (e.g., parallel `
|
|
8
|
+
* operations (e.g., parallel `condition` calls). Use `Durable.workflow.all`
|
|
9
9
|
* when you observe counter-sequencing issues with complex parallel
|
|
10
10
|
* patterns.
|
|
11
11
|
*
|
|
@@ -8,7 +8,7 @@ exports.all = void 0;
|
|
|
8
8
|
* multiple durable operations concurrently within a workflow function.
|
|
9
9
|
*
|
|
10
10
|
* In most cases, standard `Promise.all` works correctly for Durable
|
|
11
|
-
* operations (e.g., parallel `
|
|
11
|
+
* operations (e.g., parallel `condition` calls). Use `Durable.workflow.all`
|
|
12
12
|
* when you observe counter-sequencing issues with complex parallel
|
|
13
13
|
* patterns.
|
|
14
14
|
*
|