@hatchet-dev/typescript-sdk 1.20.1 → 1.21.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/clients/listeners/durable-listener/durable-listener-client.d.ts +1 -0
- package/clients/listeners/durable-listener/durable-listener-client.js +1 -0
- package/package.json +1 -1
- package/protoc/v1/dispatcher.d.ts +5 -0
- package/protoc/v1/dispatcher.js +22 -2
- package/util/errors/non-determinism-error.js +1 -1
- package/v1/client/worker/context.d.ts +13 -3
- package/v1/client/worker/context.js +9 -11
- package/v1/declaration.d.ts +30 -0
- package/v1/declaration.js +128 -0
- package/v1/examples/__e2e__/harness.js +8 -3
- package/v1/examples/durable/workflow.d.ts +5 -2
- package/v1/examples/durable/workflow.js +9 -2
- package/v1/examples/durable_event/workflow.d.ts +4 -0
- package/v1/examples/durable_event/workflow.js +15 -1
- package/v1/examples/runtime_affinity/workflow.d.ts +10 -3
- package/v1/examples/runtime_affinity/workflow.js +12 -2
- package/v1/examples/simple/bulk.js +19 -0
- package/version.d.ts +1 -1
- package/version.js +1 -1
package/package.json
CHANGED
|
@@ -113,6 +113,11 @@ export interface DurableTaskWaitForRequest {
|
|
|
113
113
|
durableTaskExternalId: string;
|
|
114
114
|
/** Fields for DURABLE_TASK_TRIGGER_KIND_WAIT_FOR */
|
|
115
115
|
waitForConditions?: DurableEventListenerConditions | undefined;
|
|
116
|
+
/**
|
|
117
|
+
* An optional human-readable label for this wait, displayed in the dashboard.
|
|
118
|
+
* Example: "Waiting for payment confirmation"
|
|
119
|
+
*/
|
|
120
|
+
label?: string | undefined;
|
|
116
121
|
}
|
|
117
122
|
export interface DurableTaskRequest {
|
|
118
123
|
registerWorker?: DurableTaskRequestRegisterWorker | undefined;
|
package/protoc/v1/dispatcher.js
CHANGED
|
@@ -1447,7 +1447,12 @@ exports.DurableTaskTriggerRunsRequest = {
|
|
|
1447
1447
|
},
|
|
1448
1448
|
};
|
|
1449
1449
|
function createBaseDurableTaskWaitForRequest() {
|
|
1450
|
-
return {
|
|
1450
|
+
return {
|
|
1451
|
+
invocationCount: 0,
|
|
1452
|
+
durableTaskExternalId: '',
|
|
1453
|
+
waitForConditions: undefined,
|
|
1454
|
+
label: undefined,
|
|
1455
|
+
};
|
|
1451
1456
|
}
|
|
1452
1457
|
exports.DurableTaskWaitForRequest = {
|
|
1453
1458
|
encode(message, writer = new wire_1.BinaryWriter()) {
|
|
@@ -1460,6 +1465,9 @@ exports.DurableTaskWaitForRequest = {
|
|
|
1460
1465
|
if (message.waitForConditions !== undefined) {
|
|
1461
1466
|
condition_1.DurableEventListenerConditions.encode(message.waitForConditions, writer.uint32(26).fork()).join();
|
|
1462
1467
|
}
|
|
1468
|
+
if (message.label !== undefined) {
|
|
1469
|
+
writer.uint32(34).string(message.label);
|
|
1470
|
+
}
|
|
1463
1471
|
return writer;
|
|
1464
1472
|
},
|
|
1465
1473
|
decode(input, length) {
|
|
@@ -1490,6 +1498,13 @@ exports.DurableTaskWaitForRequest = {
|
|
|
1490
1498
|
message.waitForConditions = condition_1.DurableEventListenerConditions.decode(reader, reader.uint32());
|
|
1491
1499
|
continue;
|
|
1492
1500
|
}
|
|
1501
|
+
case 4: {
|
|
1502
|
+
if (tag !== 34) {
|
|
1503
|
+
break;
|
|
1504
|
+
}
|
|
1505
|
+
message.label = reader.string();
|
|
1506
|
+
continue;
|
|
1507
|
+
}
|
|
1493
1508
|
}
|
|
1494
1509
|
if ((tag & 7) === 4 || tag === 0) {
|
|
1495
1510
|
break;
|
|
@@ -1515,6 +1530,7 @@ exports.DurableTaskWaitForRequest = {
|
|
|
1515
1530
|
: isSet(object.wait_for_conditions)
|
|
1516
1531
|
? condition_1.DurableEventListenerConditions.fromJSON(object.wait_for_conditions)
|
|
1517
1532
|
: undefined,
|
|
1533
|
+
label: isSet(object.label) ? globalThis.String(object.label) : undefined,
|
|
1518
1534
|
};
|
|
1519
1535
|
},
|
|
1520
1536
|
toJSON(message) {
|
|
@@ -1528,13 +1544,16 @@ exports.DurableTaskWaitForRequest = {
|
|
|
1528
1544
|
if (message.waitForConditions !== undefined) {
|
|
1529
1545
|
obj.waitForConditions = condition_1.DurableEventListenerConditions.toJSON(message.waitForConditions);
|
|
1530
1546
|
}
|
|
1547
|
+
if (message.label !== undefined) {
|
|
1548
|
+
obj.label = message.label;
|
|
1549
|
+
}
|
|
1531
1550
|
return obj;
|
|
1532
1551
|
},
|
|
1533
1552
|
create(base) {
|
|
1534
1553
|
return exports.DurableTaskWaitForRequest.fromPartial(base !== null && base !== void 0 ? base : {});
|
|
1535
1554
|
},
|
|
1536
1555
|
fromPartial(object) {
|
|
1537
|
-
var _a, _b;
|
|
1556
|
+
var _a, _b, _c;
|
|
1538
1557
|
const message = createBaseDurableTaskWaitForRequest();
|
|
1539
1558
|
message.invocationCount = (_a = object.invocationCount) !== null && _a !== void 0 ? _a : 0;
|
|
1540
1559
|
message.durableTaskExternalId = (_b = object.durableTaskExternalId) !== null && _b !== void 0 ? _b : '';
|
|
@@ -1542,6 +1561,7 @@ exports.DurableTaskWaitForRequest = {
|
|
|
1542
1561
|
object.waitForConditions !== undefined && object.waitForConditions !== null
|
|
1543
1562
|
? condition_1.DurableEventListenerConditions.fromPartial(object.waitForConditions)
|
|
1544
1563
|
: undefined;
|
|
1564
|
+
message.label = (_c = object.label) !== null && _c !== void 0 ? _c : undefined;
|
|
1545
1565
|
return message;
|
|
1546
1566
|
},
|
|
1547
1567
|
};
|
|
@@ -11,7 +11,7 @@ class NonDeterminismError extends hatchet_error_1.default {
|
|
|
11
11
|
? message
|
|
12
12
|
: `Non-determinism detected in task ${taskExternalId} on invocation ${invocationCount} at node ${nodeId}`;
|
|
13
13
|
super(`${detail}\n` +
|
|
14
|
-
`Check out our documentation for more details on expectations of durable tasks: https://docs.hatchet.run/v1/patterns
|
|
14
|
+
`Check out our documentation for more details on expectations of durable tasks: https://docs.hatchet.run/v1/patterns`);
|
|
15
15
|
this.name = 'NonDeterminismError';
|
|
16
16
|
this.taskExternalId = taskExternalId;
|
|
17
17
|
this.invocationCount = invocationCount;
|
|
@@ -31,6 +31,12 @@ export interface SleepResult {
|
|
|
31
31
|
/** The sleep duration in milliseconds. */
|
|
32
32
|
durationMs: number;
|
|
33
33
|
}
|
|
34
|
+
export interface SleepForOptions {
|
|
35
|
+
/** Optional key used for condition result indexing. */
|
|
36
|
+
readableDataKey?: string;
|
|
37
|
+
/** Optional human-readable wait label shown in dashboard run details. */
|
|
38
|
+
label?: string;
|
|
39
|
+
}
|
|
34
40
|
type LogExtra = {
|
|
35
41
|
extra?: any;
|
|
36
42
|
error?: Error;
|
|
@@ -371,16 +377,20 @@ export declare class DurableContext<T, K = {}> extends Context<T, K> {
|
|
|
371
377
|
* Pauses execution for the specified duration.
|
|
372
378
|
* Duration is "global" meaning it will wait in real time regardless of transient failures like worker restarts.
|
|
373
379
|
* @param duration - The duration to sleep for.
|
|
380
|
+
* @param readableDataKeyOrOptions - Optional readable key string or options object containing readableDataKey and label.
|
|
381
|
+
* @param label - Optional wait label used when readableDataKey is passed as the second argument.
|
|
374
382
|
* @returns A promise that resolves with a SleepResult when the sleep duration has elapsed.
|
|
375
383
|
*/
|
|
384
|
+
sleepFor(duration: Duration, options?: SleepForOptions): Promise<SleepResult>;
|
|
376
385
|
sleepFor(duration: Duration, readableDataKey?: string): Promise<SleepResult>;
|
|
386
|
+
sleepFor(duration: Duration, readableDataKey?: string, label?: string): Promise<SleepResult>;
|
|
377
387
|
/**
|
|
378
388
|
* Pauses execution until the specified conditions are met.
|
|
379
389
|
* Conditions are "global" meaning they will wait in real time regardless of transient failures like worker restarts.
|
|
380
390
|
* @param conditions - The conditions to wait for.
|
|
381
391
|
* @returns A promise that resolves with the event that satisfied the conditions.
|
|
382
392
|
*/
|
|
383
|
-
waitFor(conditions: Conditions | Conditions[]): Promise<Record<string, any>>;
|
|
393
|
+
waitFor(conditions: Conditions | Conditions[], label?: string): Promise<Record<string, any>>;
|
|
384
394
|
/**
|
|
385
395
|
* Lightweight wrapper for waiting for a user event. Allows for shorthand usage of
|
|
386
396
|
* `ctx.waitFor` when specifying a user event condition.
|
|
@@ -392,8 +402,8 @@ export declare class DurableContext<T, K = {}> extends Context<T, K> {
|
|
|
392
402
|
* @param payloadSchema - An optional Zod schema to validate and parse the event payload.
|
|
393
403
|
* @returns The event payload, validated against the schema if provided.
|
|
394
404
|
*/
|
|
395
|
-
waitForEvent<T extends z.ZodTypeAny>(key: string, expression?: string, payloadSchema?: T, scope?: string, lookbackWindow?: Duration): Promise<z.infer<T>>;
|
|
396
|
-
waitForEvent(key: string, expression?: string, payloadSchema?: undefined, scope?: string, lookbackWindow?: Duration): Promise<Record<string, any>>;
|
|
405
|
+
waitForEvent<T extends z.ZodTypeAny>(key: string, expression?: string, payloadSchema?: T, scope?: string, lookbackWindow?: Duration, label?: string): Promise<z.infer<T>>;
|
|
406
|
+
waitForEvent(key: string, expression?: string, payloadSchema?: undefined, scope?: string, lookbackWindow?: Duration, label?: string): Promise<Record<string, any>>;
|
|
397
407
|
/**
|
|
398
408
|
* Durably sleep until a specific timestamp.
|
|
399
409
|
* Uses the memoized `now()` to compute the remaining duration, then delegates to `sleepFor`.
|
|
@@ -683,15 +683,12 @@ class DurableContext extends Context {
|
|
|
683
683
|
}
|
|
684
684
|
});
|
|
685
685
|
}
|
|
686
|
-
|
|
687
|
-
* Pauses execution for the specified duration.
|
|
688
|
-
* Duration is "global" meaning it will wait in real time regardless of transient failures like worker restarts.
|
|
689
|
-
* @param duration - The duration to sleep for.
|
|
690
|
-
* @returns A promise that resolves with a SleepResult when the sleep duration has elapsed.
|
|
691
|
-
*/
|
|
692
|
-
sleepFor(duration, readableDataKey) {
|
|
686
|
+
sleepFor(duration, readableDataKeyOrOptions, label) {
|
|
693
687
|
return __awaiter(this, void 0, void 0, function* () {
|
|
694
|
-
const
|
|
688
|
+
const opts = typeof readableDataKeyOrOptions === 'string'
|
|
689
|
+
? { readableDataKey: readableDataKeyOrOptions, label }
|
|
690
|
+
: (readableDataKeyOrOptions !== null && readableDataKeyOrOptions !== void 0 ? readableDataKeyOrOptions : {});
|
|
691
|
+
const res = yield this.waitFor({ sleepFor: duration, readableDataKey: opts.readableDataKey }, opts.label);
|
|
695
692
|
const matches = res['CREATE'] || {};
|
|
696
693
|
const [firstMatch] = Object.values(matches);
|
|
697
694
|
if (!firstMatch || firstMatch.length === 0) {
|
|
@@ -718,7 +715,7 @@ class DurableContext extends Context {
|
|
|
718
715
|
* @param conditions - The conditions to wait for.
|
|
719
716
|
* @returns A promise that resolves with the event that satisfied the conditions.
|
|
720
717
|
*/
|
|
721
|
-
waitFor(conditions) {
|
|
718
|
+
waitFor(conditions, label) {
|
|
722
719
|
return __awaiter(this, void 0, void 0, function* () {
|
|
723
720
|
this.throwIfCancelled();
|
|
724
721
|
if (!this.supportsEviction) {
|
|
@@ -732,6 +729,7 @@ class DurableContext extends Context {
|
|
|
732
729
|
sleepConditions: pbConditions.sleepConditions,
|
|
733
730
|
userEventConditions: pbConditions.userEventConditions,
|
|
734
731
|
},
|
|
732
|
+
label,
|
|
735
733
|
});
|
|
736
734
|
const resourceId = rendered
|
|
737
735
|
.map((c) => c.base.readableDataKey)
|
|
@@ -743,7 +741,7 @@ class DurableContext extends Context {
|
|
|
743
741
|
}));
|
|
744
742
|
});
|
|
745
743
|
}
|
|
746
|
-
waitForEvent(key, expression, payloadSchema, scope, lookbackWindow) {
|
|
744
|
+
waitForEvent(key, expression, payloadSchema, scope, lookbackWindow, label) {
|
|
747
745
|
return __awaiter(this, void 0, void 0, function* () {
|
|
748
746
|
const now = yield this.now();
|
|
749
747
|
const considerEventsSince = lookbackWindow
|
|
@@ -754,7 +752,7 @@ class DurableContext extends Context {
|
|
|
754
752
|
expression,
|
|
755
753
|
scope,
|
|
756
754
|
considerEventsSince,
|
|
757
|
-
});
|
|
755
|
+
}, label);
|
|
758
756
|
// The engine returns an object like:
|
|
759
757
|
// {"CREATE": {"signal_key_1": [{"id": ..., "data": {...}}]}}
|
|
760
758
|
// Since we have a single match, the list will only have one item.
|
package/v1/declaration.d.ts
CHANGED
|
@@ -65,6 +65,10 @@ export type RunOpts = {
|
|
|
65
65
|
comparator?: WorkerLabelComparator;
|
|
66
66
|
}>;
|
|
67
67
|
};
|
|
68
|
+
export type RunManyOpt<I extends InputType = UnknownInputType> = {
|
|
69
|
+
input: I;
|
|
70
|
+
opts?: RunOpts;
|
|
71
|
+
};
|
|
68
72
|
/**
|
|
69
73
|
* Helper type to safely extract output types from task results
|
|
70
74
|
* @hidden
|
|
@@ -263,6 +267,13 @@ export declare class BaseWorkflowDeclaration<I extends InputType = UnknownInputT
|
|
|
263
267
|
*/
|
|
264
268
|
runNoWait(input: I, options?: RunOpts, _standaloneTaskName?: string): Promise<WorkflowRunRef<O>>;
|
|
265
269
|
runNoWait(input: I[], options?: RunOpts, _standaloneTaskName?: string): Promise<WorkflowRunRef<O>[]>;
|
|
270
|
+
/**
|
|
271
|
+
* Synchronously trigger multiple workflow runs without waiting for completion.
|
|
272
|
+
* @param runs A list of run requests containing input and per-run options.
|
|
273
|
+
* @returns WorkflowRunRef values in the same order as input runs.
|
|
274
|
+
* @throws Error if the workflow is not bound to a Hatchet client.
|
|
275
|
+
*/
|
|
276
|
+
runManyNoWait(runs: RunManyOpt<I>[], _standaloneTaskName?: string): Promise<WorkflowRunRef<O>[]>;
|
|
266
277
|
/**
|
|
267
278
|
* @alias run
|
|
268
279
|
* Triggers a workflow run and waits for the result.
|
|
@@ -283,6 +294,12 @@ export declare class BaseWorkflowDeclaration<I extends InputType = UnknownInputT
|
|
|
283
294
|
*/
|
|
284
295
|
run(input: I, options?: RunOpts, _standaloneTaskName?: string): Promise<O>;
|
|
285
296
|
run(input: I[], options?: RunOpts, _standaloneTaskName?: string): Promise<O[]>;
|
|
297
|
+
/**
|
|
298
|
+
* Executes many workflow runs and waits for all results.
|
|
299
|
+
* @param runs A list of run requests containing input and per-run options.
|
|
300
|
+
* @returns Results in the same order as input runs.
|
|
301
|
+
*/
|
|
302
|
+
runMany(runs: RunManyOpt<I>[], _standaloneTaskName?: string): Promise<O[]>;
|
|
286
303
|
/**
|
|
287
304
|
* Schedules a workflow to run at a specific date and time in the future.
|
|
288
305
|
* @param enqueueAt The date when the workflow should be triggered.
|
|
@@ -376,6 +393,7 @@ export declare class BaseWorkflowDeclaration<I extends InputType = UnknownInputT
|
|
|
376
393
|
* - Scheduled execution with `schedule()`
|
|
377
394
|
* - Cron-based recurring execution with `cron()`
|
|
378
395
|
* - Bulk execution by passing an array input to `run()` and `runNoWait()`
|
|
396
|
+
* - Per-run bulk execution options with `runMany()` and `runManyNoWait()`
|
|
379
397
|
*
|
|
380
398
|
* Tasks within workflows can be defined with `workflow.task()` or
|
|
381
399
|
* `workflow.durableTask()` and arranged into complex dependency patterns.
|
|
@@ -484,6 +502,18 @@ export declare class TaskWorkflowDeclaration<I extends InputType = UnknownInputT
|
|
|
484
502
|
*/
|
|
485
503
|
runNoWait(input: I & GlobalInput, options?: RunOpts): Promise<WorkflowRunRef<O & Resolved<GlobalOutput, MiddlewareAfter>>>;
|
|
486
504
|
runNoWait(input: (I & GlobalInput)[], options?: RunOpts): Promise<WorkflowRunRef<O & Resolved<GlobalOutput, MiddlewareAfter>>[]>;
|
|
505
|
+
/**
|
|
506
|
+
* Triggers many task runs and waits for all results.
|
|
507
|
+
* @param runs - The list of inputs and optional per-run options.
|
|
508
|
+
* @returns A promise that resolves with ordered task outputs.
|
|
509
|
+
*/
|
|
510
|
+
runMany(runs: RunManyOpt<I & GlobalInput>[]): Promise<(O & Resolved<GlobalOutput, MiddlewareAfter>)[]>;
|
|
511
|
+
/**
|
|
512
|
+
* Triggers many task runs without waiting for completion.
|
|
513
|
+
* @param runs - The list of inputs and optional per-run options.
|
|
514
|
+
* @returns WorkflowRunRef values for each scheduled run.
|
|
515
|
+
*/
|
|
516
|
+
runManyNoWait(runs: RunManyOpt<I & GlobalInput>[]): Promise<WorkflowRunRef<O & Resolved<GlobalOutput, MiddlewareAfter>>[]>;
|
|
487
517
|
/**
|
|
488
518
|
* Schedules the task to run at a specific date and time.
|
|
489
519
|
* @param enqueueAt - The date when the task should be triggered.
|
package/v1/declaration.js
CHANGED
|
@@ -15,6 +15,17 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
15
15
|
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
16
16
|
});
|
|
17
17
|
};
|
|
18
|
+
var __rest = (this && this.__rest) || function (s, e) {
|
|
19
|
+
var t = {};
|
|
20
|
+
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
|
|
21
|
+
t[p] = s[p];
|
|
22
|
+
if (s != null && typeof Object.getOwnPropertySymbols === "function")
|
|
23
|
+
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
|
|
24
|
+
if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
|
|
25
|
+
t[p[i]] = s[p[i]];
|
|
26
|
+
}
|
|
27
|
+
return t;
|
|
28
|
+
};
|
|
18
29
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
19
30
|
exports.TaskWorkflowDeclaration = exports.WorkflowDeclaration = exports.BaseWorkflowDeclaration = exports.StickyStrategy = exports.Priority = void 0;
|
|
20
31
|
exports.CreateTaskWorkflow = CreateTaskWorkflow;
|
|
@@ -117,6 +128,59 @@ class BaseWorkflowDeclaration {
|
|
|
117
128
|
return res;
|
|
118
129
|
});
|
|
119
130
|
}
|
|
131
|
+
/**
|
|
132
|
+
* Synchronously trigger multiple workflow runs without waiting for completion.
|
|
133
|
+
* @param runs A list of run requests containing input and per-run options.
|
|
134
|
+
* @returns WorkflowRunRef values in the same order as input runs.
|
|
135
|
+
* @throws Error if the workflow is not bound to a Hatchet client.
|
|
136
|
+
*/
|
|
137
|
+
runManyNoWait(runs, _standaloneTaskName) {
|
|
138
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
139
|
+
if (!this.client) {
|
|
140
|
+
throw UNBOUND_ERR;
|
|
141
|
+
}
|
|
142
|
+
const parentRunContext = parent_run_context_vars_1.parentRunContextManager.getContext();
|
|
143
|
+
const hasChildKeyOrSticky = runs.some((run) => { var _a, _b; return ((_a = run.opts) === null || _a === void 0 ? void 0 : _a.childKey) || ((_b = run.opts) === null || _b === void 0 ? void 0 : _b.sticky); });
|
|
144
|
+
if (!parentRunContext && hasChildKeyOrSticky) {
|
|
145
|
+
this.client.admin.logger.warn('ignoring childKey or sticky because run is not being spawned from a parent task');
|
|
146
|
+
}
|
|
147
|
+
const inheritedSignal = parentRunContext === null || parentRunContext === void 0 ? void 0 : parentRunContext.signal;
|
|
148
|
+
(0, abort_error_1.throwIfAborted)(inheritedSignal, {
|
|
149
|
+
isTrigger: true,
|
|
150
|
+
context: (parentRunContext === null || parentRunContext === void 0 ? void 0 : parentRunContext.parentTaskRunExternalId)
|
|
151
|
+
? `task run ${parentRunContext.parentTaskRunExternalId}`
|
|
152
|
+
: undefined,
|
|
153
|
+
warn: (message) => this.client.admin.logger.warn(message),
|
|
154
|
+
});
|
|
155
|
+
parent_run_context_vars_1.parentRunContextManager.incrementChildIndex(runs.length);
|
|
156
|
+
const baseOpts = {
|
|
157
|
+
parentId: parentRunContext === null || parentRunContext === void 0 ? void 0 : parentRunContext.parentId,
|
|
158
|
+
parentTaskRunExternalId: parentRunContext === null || parentRunContext === void 0 ? void 0 : parentRunContext.parentTaskRunExternalId,
|
|
159
|
+
childIndex: parentRunContext === null || parentRunContext === void 0 ? void 0 : parentRunContext.childIndex,
|
|
160
|
+
};
|
|
161
|
+
let resp = [];
|
|
162
|
+
for (let i = 0; i < runs.length; i += 500) {
|
|
163
|
+
const batch = runs.slice(i, i + 500);
|
|
164
|
+
const batchResp = yield this.client.admin.runWorkflows(batch.map((run, batchIndex) => {
|
|
165
|
+
var _a, _b, _c;
|
|
166
|
+
const _d = (_a = run.opts) !== null && _a !== void 0 ? _a : {}, { sticky } = _d, restOpts = __rest(_d, ["sticky"]);
|
|
167
|
+
return {
|
|
168
|
+
workflowName: this.definition.name,
|
|
169
|
+
input: run.input,
|
|
170
|
+
options: Object.assign(Object.assign(Object.assign({}, baseOpts), restOpts), { childIndex: ((_b = baseOpts.childIndex) !== null && _b !== void 0 ? _b : 0) + i + batchIndex, desiredWorkerId: sticky ? parentRunContext === null || parentRunContext === void 0 ? void 0 : parentRunContext.desiredWorkerId : undefined, childKey: (_c = run.opts) === null || _c === void 0 ? void 0 : _c.childKey }),
|
|
171
|
+
};
|
|
172
|
+
}));
|
|
173
|
+
resp = resp.concat(batchResp);
|
|
174
|
+
}
|
|
175
|
+
resp.forEach((ref) => {
|
|
176
|
+
if (_standaloneTaskName) {
|
|
177
|
+
ref._standaloneTaskName = _standaloneTaskName;
|
|
178
|
+
}
|
|
179
|
+
ref.defaultSignal = inheritedSignal;
|
|
180
|
+
});
|
|
181
|
+
return resp;
|
|
182
|
+
});
|
|
183
|
+
}
|
|
120
184
|
runAndWait(input, options, _standaloneTaskName) {
|
|
121
185
|
return __awaiter(this, void 0, void 0, function* () {
|
|
122
186
|
if (!this.client) {
|
|
@@ -162,6 +226,43 @@ class BaseWorkflowDeclaration {
|
|
|
162
226
|
return res.result();
|
|
163
227
|
});
|
|
164
228
|
}
|
|
229
|
+
/**
|
|
230
|
+
* Executes many workflow runs and waits for all results.
|
|
231
|
+
* @param runs A list of run requests containing input and per-run options.
|
|
232
|
+
* @returns Results in the same order as input runs.
|
|
233
|
+
*/
|
|
234
|
+
runMany(runs, _standaloneTaskName) {
|
|
235
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
236
|
+
var _a;
|
|
237
|
+
if (!this.client) {
|
|
238
|
+
throw UNBOUND_ERR;
|
|
239
|
+
}
|
|
240
|
+
const durableCtx = (_a = parent_run_context_vars_1.parentRunContextManager.getContext()) === null || _a === void 0 ? void 0 : _a.durableContext;
|
|
241
|
+
if (durableCtx) {
|
|
242
|
+
return durableCtx.spawnChildren(runs.map((run) => ({
|
|
243
|
+
workflow: this,
|
|
244
|
+
input: run.input,
|
|
245
|
+
options: run.opts,
|
|
246
|
+
})));
|
|
247
|
+
}
|
|
248
|
+
const refs = yield this.runManyNoWait(runs, _standaloneTaskName);
|
|
249
|
+
const returnExceptions = runs.some((run) => { var _a; return (_a = run.opts) === null || _a === void 0 ? void 0 : _a.returnExceptions; });
|
|
250
|
+
if (returnExceptions) {
|
|
251
|
+
const settled = yield Promise.allSettled(refs.map((ref) => ref.result()));
|
|
252
|
+
return settled.map((s) => {
|
|
253
|
+
if (s.status === 'fulfilled') {
|
|
254
|
+
return s.value;
|
|
255
|
+
}
|
|
256
|
+
const { reason } = s;
|
|
257
|
+
if (reason instanceof Error) {
|
|
258
|
+
return reason;
|
|
259
|
+
}
|
|
260
|
+
return new Error(Array.isArray(reason) ? reason.join('; ') : String(reason));
|
|
261
|
+
});
|
|
262
|
+
}
|
|
263
|
+
return Promise.all(refs.map((ref) => ref.result()));
|
|
264
|
+
});
|
|
265
|
+
}
|
|
165
266
|
/**
|
|
166
267
|
* Schedules a workflow to run at a specific date and time in the future.
|
|
167
268
|
* @param enqueueAt The date when the workflow should be triggered.
|
|
@@ -344,6 +445,7 @@ exports.BaseWorkflowDeclaration = BaseWorkflowDeclaration;
|
|
|
344
445
|
* - Scheduled execution with `schedule()`
|
|
345
446
|
* - Cron-based recurring execution with `cron()`
|
|
346
447
|
* - Bulk execution by passing an array input to `run()` and `runNoWait()`
|
|
448
|
+
* - Per-run bulk execution options with `runMany()` and `runManyNoWait()`
|
|
347
449
|
*
|
|
348
450
|
* Tasks within workflows can be defined with `workflow.task()` or
|
|
349
451
|
* `workflow.durableTask()` and arranged into complex dependency patterns.
|
|
@@ -492,6 +594,32 @@ class TaskWorkflowDeclaration extends BaseWorkflowDeclaration {
|
|
|
492
594
|
: _super.runNoWait.call(this, input, options, this._standalone_task_name);
|
|
493
595
|
});
|
|
494
596
|
}
|
|
597
|
+
/**
|
|
598
|
+
* Triggers many task runs and waits for all results.
|
|
599
|
+
* @param runs - The list of inputs and optional per-run options.
|
|
600
|
+
* @returns A promise that resolves with ordered task outputs.
|
|
601
|
+
*/
|
|
602
|
+
runMany(runs) {
|
|
603
|
+
const _super = Object.create(null, {
|
|
604
|
+
runMany: { get: () => super.runMany }
|
|
605
|
+
});
|
|
606
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
607
|
+
return _super.runMany.call(this, runs, this._standalone_task_name);
|
|
608
|
+
});
|
|
609
|
+
}
|
|
610
|
+
/**
|
|
611
|
+
* Triggers many task runs without waiting for completion.
|
|
612
|
+
* @param runs - The list of inputs and optional per-run options.
|
|
613
|
+
* @returns WorkflowRunRef values for each scheduled run.
|
|
614
|
+
*/
|
|
615
|
+
runManyNoWait(runs) {
|
|
616
|
+
const _super = Object.create(null, {
|
|
617
|
+
runManyNoWait: { get: () => super.runManyNoWait }
|
|
618
|
+
});
|
|
619
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
620
|
+
return _super.runManyNoWait.call(this, runs, this._standalone_task_name);
|
|
621
|
+
});
|
|
622
|
+
}
|
|
495
623
|
/**
|
|
496
624
|
* Schedules the task to run at a specific date and time.
|
|
497
625
|
* @param enqueueAt - The date when the task should be triggered.
|
|
@@ -71,9 +71,14 @@ function poll(fn_1, _a) {
|
|
|
71
71
|
return __awaiter(this, arguments, void 0, function* (fn, { timeoutMs = 30000, intervalMs = 100, shouldStop, label = 'poll', }) {
|
|
72
72
|
const start = Date.now();
|
|
73
73
|
while (true) {
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
74
|
+
try {
|
|
75
|
+
const value = yield fn();
|
|
76
|
+
if (shouldStop(value)) {
|
|
77
|
+
return value;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
catch (_b) {
|
|
81
|
+
// retry on transient errors
|
|
77
82
|
}
|
|
78
83
|
if (Date.now() - start > timeoutMs) {
|
|
79
84
|
throw new Error(`Timed out waiting for ${label} after ${timeoutMs}ms`);
|
|
@@ -54,10 +54,13 @@ export declare const durableReplayReset: import("../..").TaskWorkflowDeclaration
|
|
|
54
54
|
}, {}, {}, {}, {}>;
|
|
55
55
|
export declare const LOOKBACK_WINDOW: "1m";
|
|
56
56
|
export declare const waitForEventLookback: import("../..").TaskWorkflowDeclaration<{
|
|
57
|
-
|
|
57
|
+
userId: number;
|
|
58
58
|
}, {
|
|
59
59
|
elapsed: number;
|
|
60
|
-
event:
|
|
60
|
+
event: {
|
|
61
|
+
order: string;
|
|
62
|
+
user_id: number;
|
|
63
|
+
};
|
|
61
64
|
}, {}, {}, {}, {}>;
|
|
62
65
|
export declare const waitForOrEventLookback: import("../..").TaskWorkflowDeclaration<{
|
|
63
66
|
scope: string;
|
|
@@ -13,6 +13,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
13
13
|
};
|
|
14
14
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
15
|
exports.durableSpawnDag = exports.dagChildWorkflow = exports.memoNowCaching = exports.waitForTwoEventsSecondPushedFirst = exports.waitForOrEventLookback = exports.waitForEventLookback = exports.LOOKBACK_WINDOW = exports.durableReplayReset = exports.REPLAY_RESET_MEMOIZED_MAX_SECONDS = exports.REPLAY_RESET_SLEEP_SECONDS = exports.durableNonDeterminism = exports.durableWithExplicitSpawn = exports.durableSleepEventSpawn = exports.durableWithBulkSpawn = exports.durableWithSpawn = exports.spawnChildTask = exports.waitForSleepTwice = exports.durableWorkflow = exports.SLEEP_TIME = exports.SLEEP_TIME_SECONDS = exports.EVENT_KEY = void 0;
|
|
16
|
+
const zod_1 = require("zod");
|
|
16
17
|
const conditions_1 = require("../../conditions");
|
|
17
18
|
const non_determinism_error_1 = require("../../../util/errors/non-determinism-error");
|
|
18
19
|
const sleep_1 = __importDefault(require("../../../util/sleep"));
|
|
@@ -37,7 +38,7 @@ exports.durableWorkflow.durableTask({
|
|
|
37
38
|
executionTimeout: '10m',
|
|
38
39
|
fn: (_input, ctx) => __awaiter(void 0, void 0, void 0, function* () {
|
|
39
40
|
console.log('Waiting for sleep');
|
|
40
|
-
const sleepResult = yield ctx.sleepFor(exports.SLEEP_TIME);
|
|
41
|
+
const sleepResult = yield ctx.sleepFor(exports.SLEEP_TIME, { label: 'waiting for sleep' });
|
|
41
42
|
console.log('Sleep finished');
|
|
42
43
|
console.log('Waiting for event');
|
|
43
44
|
const event = yield ctx.waitForEvent(exports.EVENT_KEY, 'true');
|
|
@@ -225,12 +226,18 @@ exports.durableReplayReset = hatchet_client_1.hatchet.durableTask({
|
|
|
225
226
|
}),
|
|
226
227
|
});
|
|
227
228
|
exports.LOOKBACK_WINDOW = '1m';
|
|
229
|
+
const lookbackEventPayloadSchema = zod_1.z.object({
|
|
230
|
+
order: zod_1.z.string(),
|
|
231
|
+
user_id: zod_1.z.number(),
|
|
232
|
+
});
|
|
228
233
|
exports.waitForEventLookback = hatchet_client_1.hatchet.durableTask({
|
|
229
234
|
name: 'wait-for-event-lookback',
|
|
230
235
|
executionTimeout: '10m',
|
|
231
236
|
fn: (input, ctx) => __awaiter(void 0, void 0, void 0, function* () {
|
|
232
237
|
const start = Date.now();
|
|
233
|
-
|
|
238
|
+
// > Wait for event with lookback
|
|
239
|
+
const event = yield ctx.waitForEvent('user:create', `input.user_id == ${input.userId}`, lookbackEventPayloadSchema, `user_id:${input.userId}`, '1m');
|
|
240
|
+
// !!
|
|
234
241
|
return {
|
|
235
242
|
elapsed: (Date.now() - start) / 1000,
|
|
236
243
|
event,
|
|
@@ -1,7 +1,11 @@
|
|
|
1
1
|
export declare const EVENT_KEY = "user:update";
|
|
2
|
+
export declare const SCOPE = "user-1234";
|
|
2
3
|
export declare const durableEvent: import("../..").TaskWorkflowDeclaration<import("../..").JsonObject, {
|
|
3
4
|
Value: string;
|
|
4
5
|
}, {}, {}, {}, {}>;
|
|
5
6
|
export declare const durableEventWithFilter: import("../..").TaskWorkflowDeclaration<import("../..").JsonObject, {
|
|
6
7
|
Value: string;
|
|
7
8
|
}, {}, {}, {}, {}>;
|
|
9
|
+
export declare const durableEventWithLookback: import("../..").TaskWorkflowDeclaration<import("../..").JsonObject, {
|
|
10
|
+
Value: string;
|
|
11
|
+
}, {}, {}, {}, {}>;
|
|
@@ -9,9 +9,10 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
9
9
|
});
|
|
10
10
|
};
|
|
11
11
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
-
exports.durableEventWithFilter = exports.durableEvent = exports.EVENT_KEY = void 0;
|
|
12
|
+
exports.durableEventWithLookback = exports.durableEventWithFilter = exports.durableEvent = exports.SCOPE = exports.EVENT_KEY = void 0;
|
|
13
13
|
const hatchet_client_1 = require("../hatchet-client");
|
|
14
14
|
exports.EVENT_KEY = 'user:update';
|
|
15
|
+
exports.SCOPE = 'user-1234';
|
|
15
16
|
// > Durable Event
|
|
16
17
|
exports.durableEvent = hatchet_client_1.hatchet.durableTask({
|
|
17
18
|
name: 'durable-event',
|
|
@@ -39,3 +40,16 @@ exports.durableEventWithFilter = hatchet_client_1.hatchet.durableTask({
|
|
|
39
40
|
}),
|
|
40
41
|
});
|
|
41
42
|
// !!
|
|
43
|
+
// > Durable Event With Lookback
|
|
44
|
+
exports.durableEventWithLookback = hatchet_client_1.hatchet.durableTask({
|
|
45
|
+
name: 'durable-event-with-lookback',
|
|
46
|
+
executionTimeout: '10m',
|
|
47
|
+
fn: (_, ctx) => __awaiter(void 0, void 0, void 0, function* () {
|
|
48
|
+
const res = yield ctx.waitForEvent(exports.EVENT_KEY, undefined, undefined, exports.SCOPE, '1m');
|
|
49
|
+
console.log('res', res);
|
|
50
|
+
return {
|
|
51
|
+
Value: 'done',
|
|
52
|
+
};
|
|
53
|
+
}),
|
|
54
|
+
});
|
|
55
|
+
// !!
|
|
@@ -1,3 +1,10 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
type AffinityOutput = {
|
|
2
|
+
affinity_t1: {
|
|
3
|
+
worker_id: string | undefined;
|
|
4
|
+
};
|
|
5
|
+
affinity_t2: {
|
|
6
|
+
worker_id: string | undefined;
|
|
7
|
+
};
|
|
8
|
+
};
|
|
9
|
+
export declare const affinityExampleTask: import("../..").WorkflowDeclaration<{}, AffinityOutput, {}>;
|
|
10
|
+
export {};
|
|
@@ -11,8 +11,18 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
11
11
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
12
|
exports.affinityExampleTask = void 0;
|
|
13
13
|
const hatchet_client_1 = require("../hatchet-client");
|
|
14
|
-
exports.affinityExampleTask = hatchet_client_1.hatchet.
|
|
15
|
-
name: '
|
|
14
|
+
exports.affinityExampleTask = hatchet_client_1.hatchet.workflow({
|
|
15
|
+
name: 'runtime_affinity_workflow',
|
|
16
|
+
});
|
|
17
|
+
const affinityT1 = exports.affinityExampleTask.task({
|
|
18
|
+
name: 'affinity_t1',
|
|
19
|
+
fn: (input, ctx) => __awaiter(void 0, void 0, void 0, function* () {
|
|
20
|
+
return { worker_id: ctx.worker.id() };
|
|
21
|
+
}),
|
|
22
|
+
});
|
|
23
|
+
exports.affinityExampleTask.task({
|
|
24
|
+
name: 'affinity_t2',
|
|
25
|
+
parents: [affinityT1],
|
|
16
26
|
fn: (input, ctx) => __awaiter(void 0, void 0, void 0, function* () {
|
|
17
27
|
return { worker_id: ctx.worker.id() };
|
|
18
28
|
}),
|
|
@@ -26,6 +26,25 @@ function main() {
|
|
|
26
26
|
console.log(res[0].TransformedMessage);
|
|
27
27
|
console.log(res[1].TransformedMessage);
|
|
28
28
|
// !!
|
|
29
|
+
// > Bulk Run a Task with runMany
|
|
30
|
+
const runManyRes = yield workflow_1.simple.runMany([
|
|
31
|
+
{
|
|
32
|
+
input: {
|
|
33
|
+
Message: 'HeLlO WoRlD',
|
|
34
|
+
},
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
input: {
|
|
38
|
+
Message: 'Hello MoOn',
|
|
39
|
+
},
|
|
40
|
+
opts: {
|
|
41
|
+
priority: 3,
|
|
42
|
+
},
|
|
43
|
+
},
|
|
44
|
+
]);
|
|
45
|
+
console.log(runManyRes[0].TransformedMessage);
|
|
46
|
+
console.log(runManyRes[1].TransformedMessage);
|
|
47
|
+
// !!
|
|
29
48
|
// > Bulk Run Tasks from within a Task
|
|
30
49
|
const parent = hatchet_client_1.hatchet.task({
|
|
31
50
|
name: 'simple',
|
package/version.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const HATCHET_VERSION = "1.
|
|
1
|
+
export declare const HATCHET_VERSION = "1.21.1";
|
package/version.js
CHANGED