@hatchet-dev/typescript-sdk 1.31.1 → 1.32.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 +46 -0
- package/clients/dispatcher/action-listener.d.ts +3 -8
- package/clients/dispatcher/action-listener.js +7 -25
- package/clients/dispatcher/action.d.ts +19 -0
- package/clients/dispatcher/action.js +35 -0
- package/clients/dispatcher/dispatcher-client.d.ts +2 -2
- package/clients/dispatcher/heartbeat/heartbeat-controller.d.ts +1 -1
- package/clients/listeners/durable-listener/durable-events.d.ts +56 -0
- package/clients/listeners/durable-listener/durable-events.js +2 -0
- package/clients/listeners/durable-listener/durable-listener-client.d.ts +3 -52
- package/clients/listeners/durable-listener/durable-listener-client.js +3 -2
- package/clients/listeners/durable-listener/pooled-durable-listener-client.js +2 -1
- package/clients/listeners/run-listener/pooled-child-listener-client.js +2 -1
- package/clients/rest/generated/Api.d.ts +1 -62
- package/clients/rest/generated/Api.js +0 -50
- package/clients/rest/generated/data-contracts.d.ts +0 -52
- package/dist/check-edge-entry.mjs +84 -0
- package/edge/declarations.d.ts +49 -0
- package/edge/declarations.js +21 -0
- package/edge/index.d.ts +49 -0
- package/edge/index.js +115 -0
- package/package.json +7 -2
- package/scripts/check-edge-entry.mjs +84 -0
- package/util/abort-error.d.ts +0 -10
- package/util/abort-error.js +0 -15
- package/util/abort-signal.d.ts +12 -0
- package/util/abort-signal.js +19 -0
- package/util/logger/logger.d.ts +1 -1
- package/v1/client/worker/context.d.ts +58 -12
- package/v1/client/worker/context.js +79 -51
- package/v1/client/worker/deprecated/pre-eviction.d.ts +5 -2
- package/v1/client/worker/deprecated/pre-eviction.js +5 -0
- package/v1/client/worker/runtime.d.ts +118 -0
- package/v1/client/worker/runtime.js +9 -0
- package/v1/client/worker/worker-internal.d.ts +3 -39
- package/v1/client/worker/worker-internal.js +22 -393
- package/v1/client/worker/worker-runtime.d.ts +8 -0
- package/v1/client/worker/worker-runtime.js +67 -0
- package/v1/client/worker/workflow-proto.d.ts +76 -0
- package/v1/client/worker/workflow-proto.js +482 -0
- package/v1/parent-run-context-storage.d.ts +11 -0
- package/v1/parent-run-context-storage.js +28 -0
- package/v1/parent-run-context-vars.d.ts +15 -1
- package/v1/parent-run-context-vars.js +13 -4
- package/version.d.ts +1 -1
- package/version.js +1 -1
|
@@ -1,17 +1,15 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { ActionListener } from '../../../clients/dispatcher/action-listener';
|
|
2
|
+
import { Action, ActionKey } from '../../../clients/dispatcher/action';
|
|
2
3
|
import { StepActionEvent, StepActionEventType, GroupKeyActionEvent, GroupKeyActionEventType, BatchActionEvent } from '../../../protoc/dispatcher';
|
|
3
4
|
import HatchetPromise from '../../../util/hatchet-promise/hatchet-promise';
|
|
4
|
-
import { CreateStepRateLimit } from '../../../protoc/workflows';
|
|
5
5
|
import { Logger } from '../../../util/logger';
|
|
6
6
|
import { BaseWorkflowDeclaration, WorkflowDefinition, HatchetClient } from '../..';
|
|
7
|
-
import { TaskBatchConfig } from '../../../protoc/v1/workflows';
|
|
8
|
-
import { Concurrency, CreateWorkflowTaskOpts } from '../../task';
|
|
9
7
|
import { WorkerLabels } from '../../../clients/dispatcher/dispatcher-client';
|
|
10
|
-
import { Duration } from '../duration';
|
|
11
8
|
import { Context } from './context';
|
|
12
9
|
import { SlotConfig } from '../../slot-types';
|
|
13
10
|
import { DurableEvictionManager } from './eviction/eviction-manager';
|
|
14
11
|
import { EvictionPolicy } from './eviction/eviction-policy';
|
|
12
|
+
export { assertValidConcurrencyArr, mapBatchConfigPb, mapConcurrencyPb, mapRateLimitPb, mapSlotRequestsPb, resolveExecutionTimeout, resolveScheduleTimeout, taskConcurrencyArr, } from './workflow-proto';
|
|
15
13
|
export type ActionRegistry = Record<Action['actionId'], Function>;
|
|
16
14
|
export interface WorkerOpts {
|
|
17
15
|
name: string;
|
|
@@ -107,37 +105,3 @@ export declare class InternalWorker {
|
|
|
107
105
|
handleAction(action: Action): Promise<void | Error>;
|
|
108
106
|
upsertLabels(labels: WorkerLabels): Promise<WorkerLabels>;
|
|
109
107
|
}
|
|
110
|
-
/** Durable tasks stay on the durable pool; slotCost applies only to the default pool. */
|
|
111
|
-
export declare function mapSlotRequestsPb(task: {
|
|
112
|
-
slotRequests?: Record<string, number>;
|
|
113
|
-
slotCost?: number;
|
|
114
|
-
}, isDurable: boolean): Record<string, number>;
|
|
115
|
-
export declare function mapRateLimitPb(limits: CreateWorkflowTaskOpts<any, any>['rateLimits']): CreateStepRateLimit[];
|
|
116
|
-
export declare function mapConcurrencyPb(entries: Concurrency[]): {
|
|
117
|
-
expression: string;
|
|
118
|
-
maxRuns: number | undefined;
|
|
119
|
-
limitStrategy: import("../..").ConcurrencyLimitStrategy | undefined;
|
|
120
|
-
name: string | undefined;
|
|
121
|
-
isTenantScoped: boolean | undefined;
|
|
122
|
-
maxRunsExpression: string | undefined;
|
|
123
|
-
}[];
|
|
124
|
-
export declare function taskConcurrencyArr(task: {
|
|
125
|
-
concurrency?: Concurrency | Concurrency[];
|
|
126
|
-
}, workflow: {
|
|
127
|
-
taskDefaults?: {
|
|
128
|
-
concurrency?: Concurrency | Concurrency[];
|
|
129
|
-
};
|
|
130
|
-
}): Concurrency[];
|
|
131
|
-
export declare function assertValidConcurrencyArr(concurrency: Concurrency[] | undefined): void;
|
|
132
|
-
export declare function mapBatchConfigPb(batch: CreateWorkflowTaskOpts<any, any>['batch']): TaskBatchConfig | undefined;
|
|
133
|
-
export declare function resolveExecutionTimeout(task: {
|
|
134
|
-
executionTimeout?: Duration;
|
|
135
|
-
timeout?: Duration;
|
|
136
|
-
}, workflowDefaults?: {
|
|
137
|
-
executionTimeout?: Duration;
|
|
138
|
-
}): string;
|
|
139
|
-
export declare function resolveScheduleTimeout(task: {
|
|
140
|
-
scheduleTimeout?: Duration;
|
|
141
|
-
}, workflowDefaults?: {
|
|
142
|
-
scheduleTimeout?: Duration;
|
|
143
|
-
}): string | undefined;
|
|
@@ -52,35 +52,37 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
52
52
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
53
53
|
};
|
|
54
54
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
55
|
-
exports.InternalWorker = void 0;
|
|
56
|
-
exports.mapSlotRequestsPb = mapSlotRequestsPb;
|
|
57
|
-
exports.mapRateLimitPb = mapRateLimitPb;
|
|
58
|
-
exports.mapConcurrencyPb = mapConcurrencyPb;
|
|
59
|
-
exports.taskConcurrencyArr = taskConcurrencyArr;
|
|
60
|
-
exports.assertValidConcurrencyArr = assertValidConcurrencyArr;
|
|
61
|
-
exports.mapBatchConfigPb = mapBatchConfigPb;
|
|
62
|
-
exports.resolveExecutionTimeout = resolveExecutionTimeout;
|
|
63
|
-
exports.resolveScheduleTimeout = resolveScheduleTimeout;
|
|
55
|
+
exports.InternalWorker = exports.taskConcurrencyArr = exports.resolveScheduleTimeout = exports.resolveExecutionTimeout = exports.mapSlotRequestsPb = exports.mapRateLimitPb = exports.mapConcurrencyPb = exports.mapBatchConfigPb = exports.assertValidConcurrencyArr = void 0;
|
|
64
56
|
const hatchet_error_1 = __importDefault(require("../../../util/errors/hatchet-error"));
|
|
65
57
|
const task_run_terminated_error_1 = require("../../../util/errors/task-run-terminated-error");
|
|
58
|
+
const action_1 = require("../../../clients/dispatcher/action");
|
|
66
59
|
const dispatcher_1 = require("../../../protoc/dispatcher");
|
|
67
60
|
const hatchet_promise_1 = __importStar(require("../../../util/hatchet-promise/hatchet-promise"));
|
|
68
|
-
const workflows_1 = require("../../../protoc/workflows");
|
|
69
61
|
const logger_1 = require("../../../util/logger");
|
|
70
|
-
const workflows_2 = require("../../../protoc/v1/workflows");
|
|
71
62
|
const task_1 = require("../../task");
|
|
72
|
-
const transformer_1 = require("../../conditions/transformer");
|
|
73
|
-
const z = __importStar(require("zod/v4"));
|
|
74
63
|
const apply_namespace_1 = require("../../../util/apply-namespace");
|
|
75
64
|
const sleep_1 = __importDefault(require("../../../util/sleep"));
|
|
76
65
|
const abort_error_1 = require("../../../util/abort-error");
|
|
77
|
-
const duration_1 = require("../duration");
|
|
78
66
|
const context_1 = require("./context");
|
|
79
67
|
const parent_run_context_vars_1 = require("../../parent-run-context-vars");
|
|
68
|
+
const parent_run_context_storage_1 = require("../../parent-run-context-storage");
|
|
69
|
+
const workflow_proto_1 = require("./workflow-proto");
|
|
80
70
|
const health_server_1 = require("./health-server");
|
|
81
71
|
const eviction_manager_1 = require("./eviction/eviction-manager");
|
|
82
72
|
const eviction_policy_1 = require("./eviction/eviction-policy");
|
|
83
73
|
const engine_version_1 = require("./engine-version");
|
|
74
|
+
var workflow_proto_2 = require("./workflow-proto");
|
|
75
|
+
Object.defineProperty(exports, "assertValidConcurrencyArr", { enumerable: true, get: function () { return workflow_proto_2.assertValidConcurrencyArr; } });
|
|
76
|
+
Object.defineProperty(exports, "mapBatchConfigPb", { enumerable: true, get: function () { return workflow_proto_2.mapBatchConfigPb; } });
|
|
77
|
+
Object.defineProperty(exports, "mapConcurrencyPb", { enumerable: true, get: function () { return workflow_proto_2.mapConcurrencyPb; } });
|
|
78
|
+
Object.defineProperty(exports, "mapRateLimitPb", { enumerable: true, get: function () { return workflow_proto_2.mapRateLimitPb; } });
|
|
79
|
+
Object.defineProperty(exports, "mapSlotRequestsPb", { enumerable: true, get: function () { return workflow_proto_2.mapSlotRequestsPb; } });
|
|
80
|
+
Object.defineProperty(exports, "resolveExecutionTimeout", { enumerable: true, get: function () { return workflow_proto_2.resolveExecutionTimeout; } });
|
|
81
|
+
Object.defineProperty(exports, "resolveScheduleTimeout", { enumerable: true, get: function () { return workflow_proto_2.resolveScheduleTimeout; } });
|
|
82
|
+
Object.defineProperty(exports, "taskConcurrencyArr", { enumerable: true, get: function () { return workflow_proto_2.taskConcurrencyArr; } });
|
|
83
|
+
// Tasks read the parent run context across awaits; the worker is the only place that
|
|
84
|
+
// enters it, so it installs the AsyncLocalStorage store before any task can run.
|
|
85
|
+
(0, parent_run_context_storage_1.installAsyncLocalParentRunContext)();
|
|
84
86
|
class InternalWorker {
|
|
85
87
|
constructor(client, options) {
|
|
86
88
|
var _a, _b, _c, _d;
|
|
@@ -143,7 +145,7 @@ class InternalWorker {
|
|
|
143
145
|
const newActions = workflow._durableTasks
|
|
144
146
|
.filter((task) => !!task.fn)
|
|
145
147
|
.reduce((acc, task) => {
|
|
146
|
-
const actionId =
|
|
148
|
+
const actionId = (0, action_1.createActionId)((0, apply_namespace_1.applyNamespace)(workflow.name, this.client.config.namespace), task.name);
|
|
147
149
|
acc[actionId] = (ctx) => task.fn(ctx.input, ctx);
|
|
148
150
|
this.durable_action_set.add(actionId);
|
|
149
151
|
this.eviction_policies.set(actionId, task.evictionPolicy !== undefined
|
|
@@ -157,7 +159,7 @@ class InternalWorker {
|
|
|
157
159
|
const newActions = workflow._tasks
|
|
158
160
|
.filter((task) => !!task.fn)
|
|
159
161
|
.reduce((acc, task) => {
|
|
160
|
-
const actionId =
|
|
162
|
+
const actionId = (0, action_1.createActionId)(workflow.name, task.name);
|
|
161
163
|
if (task.batch) {
|
|
162
164
|
acc[actionId] = (ctx) => task.fn(decodeBatchItems(ctx.action.actionPayload), ctx);
|
|
163
165
|
}
|
|
@@ -173,192 +175,17 @@ class InternalWorker {
|
|
|
173
175
|
: undefined;
|
|
174
176
|
const onFailureAction = onFailureFn
|
|
175
177
|
? {
|
|
176
|
-
[onFailureTaskName(workflow)]: (ctx) => onFailureFn(ctx.input, ctx),
|
|
178
|
+
[(0, workflow_proto_1.onFailureTaskName)(workflow)]: (ctx) => onFailureFn(ctx.input, ctx),
|
|
177
179
|
}
|
|
178
180
|
: {};
|
|
179
181
|
this.action_registry = Object.assign(Object.assign(Object.assign({}, this.action_registry), newActions), onFailureAction);
|
|
180
182
|
}
|
|
181
183
|
registerWorkflow(initWorkflow_1) {
|
|
182
184
|
return __awaiter(this, arguments, void 0, function* (initWorkflow, durable = false) {
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
const workflow = Object.assign(Object.assign({}, initWorkflow.definition), { name: (0, apply_namespace_1.applyNamespace)(initWorkflow.definition.name, this.client.config.namespace).toLowerCase() });
|
|
185
|
+
const { namespace } = this.client.config;
|
|
186
|
+
const workflow = (0, workflow_proto_1.normalizeWorkflowDefinition)(initWorkflow, { namespace, durable });
|
|
186
187
|
try {
|
|
187
|
-
const {
|
|
188
|
-
let onFailureTask;
|
|
189
|
-
if (workflow.onFailure && typeof workflow.onFailure === 'function') {
|
|
190
|
-
onFailureTask = {
|
|
191
|
-
readableId: 'on-failure-task',
|
|
192
|
-
action: onFailureTaskName(workflow),
|
|
193
|
-
timeout: '60s',
|
|
194
|
-
inputs: '{}',
|
|
195
|
-
parents: [],
|
|
196
|
-
retries: 0,
|
|
197
|
-
rateLimits: [],
|
|
198
|
-
workerLabels: {},
|
|
199
|
-
concurrency: [],
|
|
200
|
-
isDurable: false,
|
|
201
|
-
slotRequests: { default: 1 },
|
|
202
|
-
};
|
|
203
|
-
}
|
|
204
|
-
if (workflow.onFailure && typeof workflow.onFailure === 'object') {
|
|
205
|
-
const onFailure = workflow.onFailure;
|
|
206
|
-
const scheduleTimeout = (_a = onFailure.scheduleTimeout) !== null && _a !== void 0 ? _a : (_b = workflow.taskDefaults) === null || _b === void 0 ? void 0 : _b.scheduleTimeout;
|
|
207
|
-
onFailureTask = {
|
|
208
|
-
readableId: 'on-failure-task',
|
|
209
|
-
action: onFailureTaskName(workflow),
|
|
210
|
-
timeout: (0, duration_1.durationToString)(onFailure.executionTimeout || ((_c = workflow.taskDefaults) === null || _c === void 0 ? void 0 : _c.executionTimeout) || '60s'),
|
|
211
|
-
scheduleTimeout: scheduleTimeout ? (0, duration_1.durationToString)(scheduleTimeout) : undefined,
|
|
212
|
-
inputs: '{}',
|
|
213
|
-
parents: [],
|
|
214
|
-
retries: onFailure.retries || ((_d = workflow.taskDefaults) === null || _d === void 0 ? void 0 : _d.retries) || 0,
|
|
215
|
-
rateLimits: mapRateLimitPb(onFailure.rateLimits || ((_e = workflow.taskDefaults) === null || _e === void 0 ? void 0 : _e.rateLimits)),
|
|
216
|
-
workerLabels: mapWorkerLabelPb(onFailure.desiredWorkerLabels || ((_f = workflow.taskDefaults) === null || _f === void 0 ? void 0 : _f.workerLabels)),
|
|
217
|
-
concurrency: [],
|
|
218
|
-
backoffFactor: ((_g = onFailure.backoff) === null || _g === void 0 ? void 0 : _g.factor) || ((_j = (_h = workflow.taskDefaults) === null || _h === void 0 ? void 0 : _h.backoff) === null || _j === void 0 ? void 0 : _j.factor),
|
|
219
|
-
backoffMaxSeconds: ((_k = onFailure.backoff) === null || _k === void 0 ? void 0 : _k.maxSeconds) || ((_m = (_l = workflow.taskDefaults) === null || _l === void 0 ? void 0 : _l.backoff) === null || _m === void 0 ? void 0 : _m.maxSeconds),
|
|
220
|
-
isDurable: false,
|
|
221
|
-
slotRequests: mapSlotRequestsPb(onFailure, false),
|
|
222
|
-
};
|
|
223
|
-
}
|
|
224
|
-
let onSuccessTask;
|
|
225
|
-
if (!durable && workflow.onSuccess && typeof workflow.onSuccess === 'function') {
|
|
226
|
-
const parents = getLeaves([...workflow._tasks, ...workflow._durableTasks]);
|
|
227
|
-
onSuccessTask = {
|
|
228
|
-
name: 'on-success-task',
|
|
229
|
-
fn: workflow.onSuccess,
|
|
230
|
-
executionTimeout: '60s',
|
|
231
|
-
parents,
|
|
232
|
-
retries: 0,
|
|
233
|
-
rateLimits: [],
|
|
234
|
-
desiredWorkerLabels: undefined,
|
|
235
|
-
concurrency: [],
|
|
236
|
-
};
|
|
237
|
-
}
|
|
238
|
-
if (!durable && workflow.onSuccess && typeof workflow.onSuccess === 'object') {
|
|
239
|
-
const onSuccess = workflow.onSuccess;
|
|
240
|
-
const parents = getLeaves([...workflow._tasks, ...workflow._durableTasks]);
|
|
241
|
-
onSuccessTask = {
|
|
242
|
-
name: 'on-success-task',
|
|
243
|
-
fn: onSuccess.fn,
|
|
244
|
-
executionTimeout: onSuccess.executionTimeout || ((_o = workflow.taskDefaults) === null || _o === void 0 ? void 0 : _o.executionTimeout) || '60s',
|
|
245
|
-
scheduleTimeout: onSuccess.scheduleTimeout || ((_p = workflow.taskDefaults) === null || _p === void 0 ? void 0 : _p.scheduleTimeout),
|
|
246
|
-
parents,
|
|
247
|
-
retries: onSuccess.retries || ((_q = workflow.taskDefaults) === null || _q === void 0 ? void 0 : _q.retries) || 0,
|
|
248
|
-
rateLimits: onSuccess.rateLimits || ((_r = workflow.taskDefaults) === null || _r === void 0 ? void 0 : _r.rateLimits),
|
|
249
|
-
desiredWorkerLabels: onSuccess.desiredWorkerLabels || ((_s = workflow.taskDefaults) === null || _s === void 0 ? void 0 : _s.workerLabels),
|
|
250
|
-
concurrency: onSuccess.concurrency || ((_t = workflow.taskDefaults) === null || _t === void 0 ? void 0 : _t.concurrency),
|
|
251
|
-
backoff: onSuccess.backoff || ((_u = workflow.taskDefaults) === null || _u === void 0 ? void 0 : _u.backoff),
|
|
252
|
-
};
|
|
253
|
-
}
|
|
254
|
-
if (onSuccessTask) {
|
|
255
|
-
workflow._tasks.push(onSuccessTask);
|
|
256
|
-
}
|
|
257
|
-
const eventTriggers = [
|
|
258
|
-
...(workflow.onEvents || []).map((event) => (0, apply_namespace_1.applyNamespace)(event, this.client.config.namespace)),
|
|
259
|
-
...(workflow.on && 'event' in workflow.on && workflow.on.event
|
|
260
|
-
? Array.isArray(workflow.on.event)
|
|
261
|
-
? workflow.on.event.map((event) => (0, apply_namespace_1.applyNamespace)(event, this.client.config.namespace))
|
|
262
|
-
: [(0, apply_namespace_1.applyNamespace)(workflow.on.event, this.client.config.namespace)]
|
|
263
|
-
: []),
|
|
264
|
-
];
|
|
265
|
-
const cronTriggers = [
|
|
266
|
-
...(workflow.onCrons || []),
|
|
267
|
-
...(workflow.on && 'cron' in workflow.on && workflow.on.cron
|
|
268
|
-
? Array.isArray(workflow.on.cron)
|
|
269
|
-
? workflow.on.cron
|
|
270
|
-
: [workflow.on.cron]
|
|
271
|
-
: []),
|
|
272
|
-
];
|
|
273
|
-
const concurrencyArr = Array.isArray(concurrency) ? concurrency : [];
|
|
274
|
-
const concurrencySolo = !Array.isArray(concurrency) ? concurrency : undefined;
|
|
275
|
-
assertValidConcurrencyArr(concurrencyArr);
|
|
276
|
-
assertValidConcurrencyArr(concurrencySolo ? [concurrencySolo] : undefined);
|
|
277
|
-
// Convert Zod schema to JSON Schema if provided
|
|
278
|
-
let inputJsonSchema;
|
|
279
|
-
if (workflow.inputValidator) {
|
|
280
|
-
const jsonSchema = z.toJSONSchema(workflow.inputValidator);
|
|
281
|
-
inputJsonSchema = new TextEncoder().encode(JSON.stringify(jsonSchema));
|
|
282
|
-
}
|
|
283
|
-
const durableTaskSet = new Set(workflow._durableTasks);
|
|
284
|
-
let stickyStrategy;
|
|
285
|
-
// `workflow.sticky` is optional. When omitted, we don't set any sticky strategy.
|
|
286
|
-
//
|
|
287
|
-
// When provided, `workflow.sticky` is a v1 (non-protobuf) config which may also include
|
|
288
|
-
// legacy protobuf enum values for backwards compatibility.
|
|
289
|
-
if (workflow.sticky != null) {
|
|
290
|
-
switch (workflow.sticky) {
|
|
291
|
-
case 'soft':
|
|
292
|
-
case 'SOFT':
|
|
293
|
-
case 0:
|
|
294
|
-
stickyStrategy = workflows_1.StickyStrategy.SOFT;
|
|
295
|
-
break;
|
|
296
|
-
case 'hard':
|
|
297
|
-
case 'HARD':
|
|
298
|
-
case 1:
|
|
299
|
-
stickyStrategy = workflows_1.StickyStrategy.HARD;
|
|
300
|
-
break;
|
|
301
|
-
default:
|
|
302
|
-
throw new hatchet_error_1.default(`Invalid sticky strategy: ${workflow.sticky}`);
|
|
303
|
-
}
|
|
304
|
-
}
|
|
305
|
-
const registeredWorkflow = this.client.admin.putWorkflow({
|
|
306
|
-
name: workflow.name,
|
|
307
|
-
description: workflow.description || '',
|
|
308
|
-
version: workflow.version || '',
|
|
309
|
-
eventTriggers,
|
|
310
|
-
cronTriggers,
|
|
311
|
-
sticky: stickyStrategy,
|
|
312
|
-
concurrencyArr: mapConcurrencyPb(concurrencyArr),
|
|
313
|
-
onFailureTask,
|
|
314
|
-
defaultPriority: workflow.defaultPriority,
|
|
315
|
-
inputJsonSchema,
|
|
316
|
-
tasks: [...workflow._tasks, ...workflow._durableTasks].map((task) => {
|
|
317
|
-
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l;
|
|
318
|
-
return ({
|
|
319
|
-
readableId: task.name,
|
|
320
|
-
action: `${workflow.name}:${task.name}`,
|
|
321
|
-
timeout: resolveExecutionTimeout(task, workflow.taskDefaults),
|
|
322
|
-
scheduleTimeout: resolveScheduleTimeout(task, workflow.taskDefaults),
|
|
323
|
-
inputs: '{}',
|
|
324
|
-
parents: (_b = (_a = task.parents) === null || _a === void 0 ? void 0 : _a.map((p) => p.name)) !== null && _b !== void 0 ? _b : [],
|
|
325
|
-
userData: '{}',
|
|
326
|
-
// Batch tasks buffer many concurrent runs into a single execution; per-item retry
|
|
327
|
-
// semantics don't apply, so retries is always forced to 0.
|
|
328
|
-
retries: batchOf(task) ? 0 : task.retries || ((_c = workflow.taskDefaults) === null || _c === void 0 ? void 0 : _c.retries) || 0,
|
|
329
|
-
rateLimits: mapRateLimitPb(task.rateLimits || ((_d = workflow.taskDefaults) === null || _d === void 0 ? void 0 : _d.rateLimits)),
|
|
330
|
-
workerLabels: mapWorkerLabelPb(task.desiredWorkerLabels || ((_e = workflow.taskDefaults) === null || _e === void 0 ? void 0 : _e.workerLabels)),
|
|
331
|
-
backoffFactor: ((_f = task.backoff) === null || _f === void 0 ? void 0 : _f.factor) || ((_h = (_g = workflow.taskDefaults) === null || _g === void 0 ? void 0 : _g.backoff) === null || _h === void 0 ? void 0 : _h.factor),
|
|
332
|
-
backoffMaxSeconds: ((_j = task.backoff) === null || _j === void 0 ? void 0 : _j.maxSeconds) || ((_l = (_k = workflow.taskDefaults) === null || _k === void 0 ? void 0 : _k.backoff) === null || _l === void 0 ? void 0 : _l.maxSeconds),
|
|
333
|
-
conditions: (0, transformer_1.taskConditionsToPb)(task, this.client.config.namespace),
|
|
334
|
-
isDurable: durableTaskSet.has(task),
|
|
335
|
-
slotRequests: mapSlotRequestsPb(task, durableTaskSet.has(task)),
|
|
336
|
-
batch: mapBatchConfigPb(batchOf(task)),
|
|
337
|
-
concurrency: (() => {
|
|
338
|
-
const taskConcurrency = taskConcurrencyArr(task, workflow);
|
|
339
|
-
assertValidConcurrencyArr(taskConcurrency);
|
|
340
|
-
return mapConcurrencyPb(taskConcurrency);
|
|
341
|
-
})(),
|
|
342
|
-
});
|
|
343
|
-
}),
|
|
344
|
-
concurrency: concurrencySolo ? mapConcurrencyPb([concurrencySolo])[0] : undefined,
|
|
345
|
-
defaultFilters: (_w = (_v = workflow.defaultFilters) === null || _v === void 0 ? void 0 : _v.map((f) => ({
|
|
346
|
-
scope: f.scope,
|
|
347
|
-
expression: f.expression,
|
|
348
|
-
payload: f.payload ? new TextEncoder().encode(JSON.stringify(f.payload)) : undefined,
|
|
349
|
-
}))) !== null && _w !== void 0 ? _w : [],
|
|
350
|
-
idempotency: workflow.idempotency
|
|
351
|
-
? {
|
|
352
|
-
expression: workflow.idempotency.expression,
|
|
353
|
-
ttlMs: workflow.idempotency.strategy === 'status'
|
|
354
|
-
? workflow.idempotency.fallbackTtlMs
|
|
355
|
-
: workflow.idempotency.ttlMs,
|
|
356
|
-
method: workflow.idempotency.strategy === 'status'
|
|
357
|
-
? workflows_2.IdempotencyMethod.STATUS
|
|
358
|
-
: workflows_2.IdempotencyMethod.TTL,
|
|
359
|
-
}
|
|
360
|
-
: undefined,
|
|
361
|
-
});
|
|
188
|
+
const registeredWorkflow = this.client.admin.putWorkflow((0, workflow_proto_1.workflowToProto)(workflow, { namespace, durable }));
|
|
362
189
|
this.registeredWorkflowPromises.push(registeredWorkflow);
|
|
363
190
|
yield registeredWorkflow;
|
|
364
191
|
this.workflow_registry.push(workflow);
|
|
@@ -960,125 +787,6 @@ class InternalWorker {
|
|
|
960
787
|
}
|
|
961
788
|
}
|
|
962
789
|
exports.InternalWorker = InternalWorker;
|
|
963
|
-
function mapWorkerLabelPb(in_) {
|
|
964
|
-
if (!in_) {
|
|
965
|
-
return {};
|
|
966
|
-
}
|
|
967
|
-
return Object.entries(in_).reduce((acc, [key, label]) => {
|
|
968
|
-
if (!label) {
|
|
969
|
-
return Object.assign(Object.assign({}, acc), { [key]: {
|
|
970
|
-
strValue: undefined,
|
|
971
|
-
intValue: undefined,
|
|
972
|
-
} });
|
|
973
|
-
}
|
|
974
|
-
if (typeof label === 'string') {
|
|
975
|
-
return Object.assign(Object.assign({}, acc), { [key]: {
|
|
976
|
-
strValue: label,
|
|
977
|
-
intValue: undefined,
|
|
978
|
-
} });
|
|
979
|
-
}
|
|
980
|
-
if (typeof label === 'number') {
|
|
981
|
-
return Object.assign(Object.assign({}, acc), { [key]: {
|
|
982
|
-
strValue: undefined,
|
|
983
|
-
intValue: label,
|
|
984
|
-
} });
|
|
985
|
-
}
|
|
986
|
-
return Object.assign(Object.assign({}, acc), { [key]: {
|
|
987
|
-
strValue: typeof label.value === 'string' ? label.value : undefined,
|
|
988
|
-
intValue: typeof label.value === 'number' ? label.value : undefined,
|
|
989
|
-
required: label.required,
|
|
990
|
-
weight: label.weight,
|
|
991
|
-
comparator: label.comparator,
|
|
992
|
-
} });
|
|
993
|
-
}, {});
|
|
994
|
-
}
|
|
995
|
-
function onFailureTaskName(workflow) {
|
|
996
|
-
return `${workflow.name}:on-failure-task`;
|
|
997
|
-
}
|
|
998
|
-
function getLeaves(tasks) {
|
|
999
|
-
return tasks.filter((task) => isLeafTask(task, tasks));
|
|
1000
|
-
}
|
|
1001
|
-
function isLeafTask(task, allTasks) {
|
|
1002
|
-
return !allTasks.some((t) => { var _a; return (_a = t.parents) === null || _a === void 0 ? void 0 : _a.some((p) => p.name === task.name); });
|
|
1003
|
-
}
|
|
1004
|
-
/** Durable tasks stay on the durable pool; slotCost applies only to the default pool. */
|
|
1005
|
-
function mapSlotRequestsPb(task, isDurable) {
|
|
1006
|
-
if (task.slotRequests) {
|
|
1007
|
-
return task.slotRequests;
|
|
1008
|
-
}
|
|
1009
|
-
if (isDurable) {
|
|
1010
|
-
return { durable: 1 };
|
|
1011
|
-
}
|
|
1012
|
-
if (task.slotCost !== undefined) {
|
|
1013
|
-
if (!Number.isInteger(task.slotCost) || task.slotCost <= 0) {
|
|
1014
|
-
throw new Error(`slotCost must be a positive integer, got: ${task.slotCost}`);
|
|
1015
|
-
}
|
|
1016
|
-
return { default: task.slotCost };
|
|
1017
|
-
}
|
|
1018
|
-
return { default: 1 };
|
|
1019
|
-
}
|
|
1020
|
-
function mapRateLimitPb(limits) {
|
|
1021
|
-
if (!limits) {
|
|
1022
|
-
return [];
|
|
1023
|
-
}
|
|
1024
|
-
return limits.map((l) => {
|
|
1025
|
-
let key = l.staticKey;
|
|
1026
|
-
const keyExpression = l.dynamicKey;
|
|
1027
|
-
if (l.key !== undefined) {
|
|
1028
|
-
console.warn('key is deprecated and will be removed in a future release, please use staticKey instead');
|
|
1029
|
-
({ key } = l);
|
|
1030
|
-
}
|
|
1031
|
-
if (keyExpression !== undefined) {
|
|
1032
|
-
if (key !== undefined) {
|
|
1033
|
-
throw new Error('Cannot have both static key and dynamic key set');
|
|
1034
|
-
}
|
|
1035
|
-
key = keyExpression;
|
|
1036
|
-
if (!validateCelExpression(keyExpression)) {
|
|
1037
|
-
throw new Error(`Invalid CEL expression: ${keyExpression}`);
|
|
1038
|
-
}
|
|
1039
|
-
}
|
|
1040
|
-
if (key === undefined) {
|
|
1041
|
-
throw new Error(`Invalid key`);
|
|
1042
|
-
}
|
|
1043
|
-
let units;
|
|
1044
|
-
let unitsExpression;
|
|
1045
|
-
if (typeof l.units === 'number') {
|
|
1046
|
-
({ units } = l);
|
|
1047
|
-
}
|
|
1048
|
-
else {
|
|
1049
|
-
if (!validateCelExpression(l.units)) {
|
|
1050
|
-
throw new Error(`Invalid CEL expression: ${l.units}`);
|
|
1051
|
-
}
|
|
1052
|
-
unitsExpression = l.units;
|
|
1053
|
-
}
|
|
1054
|
-
let limitExpression;
|
|
1055
|
-
if (l.limit !== undefined) {
|
|
1056
|
-
if (typeof l.limit === 'number') {
|
|
1057
|
-
limitExpression = `${l.limit}`;
|
|
1058
|
-
}
|
|
1059
|
-
else {
|
|
1060
|
-
if (!validateCelExpression(l.limit)) {
|
|
1061
|
-
throw new Error(`Invalid CEL expression: ${l.limit}`);
|
|
1062
|
-
}
|
|
1063
|
-
limitExpression = l.limit;
|
|
1064
|
-
}
|
|
1065
|
-
}
|
|
1066
|
-
if (keyExpression !== undefined && limitExpression === undefined) {
|
|
1067
|
-
throw new Error('CEL based keys requires limit to be set');
|
|
1068
|
-
}
|
|
1069
|
-
if (limitExpression === undefined) {
|
|
1070
|
-
limitExpression = `-1`;
|
|
1071
|
-
}
|
|
1072
|
-
return {
|
|
1073
|
-
key,
|
|
1074
|
-
keyExpr: keyExpression,
|
|
1075
|
-
units,
|
|
1076
|
-
unitsExpr: unitsExpression,
|
|
1077
|
-
limitValuesExpr: limitExpression,
|
|
1078
|
-
duration: l.duration,
|
|
1079
|
-
};
|
|
1080
|
-
});
|
|
1081
|
-
}
|
|
1082
790
|
/**
|
|
1083
791
|
* Decodes the buffered items of a batch task's START_BATCH action into a Record keyed by
|
|
1084
792
|
* each buffered item's task-run external id, mapping to that item's input. The wire shape
|
|
@@ -1105,82 +813,3 @@ function parseBatchPayload(actionPayload) {
|
|
|
1105
813
|
return {};
|
|
1106
814
|
}
|
|
1107
815
|
}
|
|
1108
|
-
/** Batch tasks are only available on non-durable tasks; durable tasks never carry `batch`. */
|
|
1109
|
-
function batchOf(task) {
|
|
1110
|
-
return 'batch' in task ? task.batch : undefined;
|
|
1111
|
-
}
|
|
1112
|
-
// mapConcurrencyPb maps SDK concurrency entries onto the proto shape; entries keep their
|
|
1113
|
-
// declared order, which is the chain order.
|
|
1114
|
-
function mapConcurrencyPb(entries) {
|
|
1115
|
-
return entries.map((c) => ({
|
|
1116
|
-
expression: c.expression,
|
|
1117
|
-
// a string maxRuns is a CEL expression; the static field then carries the default
|
|
1118
|
-
// of 1, which only governs slots created before the expression existed
|
|
1119
|
-
maxRuns: typeof c.maxRuns === 'string' ? 1 : c.maxRuns,
|
|
1120
|
-
limitStrategy: c.limitStrategy,
|
|
1121
|
-
name: c.name,
|
|
1122
|
-
isTenantScoped: c.isTenantScoped,
|
|
1123
|
-
maxRunsExpression: typeof c.maxRuns === 'string' ? c.maxRuns : undefined,
|
|
1124
|
-
}));
|
|
1125
|
-
}
|
|
1126
|
-
function taskConcurrencyArr(task, workflow) {
|
|
1127
|
-
var _a;
|
|
1128
|
-
if (task.concurrency) {
|
|
1129
|
-
return Array.isArray(task.concurrency) ? task.concurrency : [task.concurrency];
|
|
1130
|
-
}
|
|
1131
|
-
if ((_a = workflow.taskDefaults) === null || _a === void 0 ? void 0 : _a.concurrency) {
|
|
1132
|
-
return Array.isArray(workflow.taskDefaults.concurrency)
|
|
1133
|
-
? workflow.taskDefaults.concurrency
|
|
1134
|
-
: [workflow.taskDefaults.concurrency];
|
|
1135
|
-
}
|
|
1136
|
-
return [];
|
|
1137
|
-
}
|
|
1138
|
-
function assertValidConcurrencyArr(concurrency) {
|
|
1139
|
-
concurrency === null || concurrency === void 0 ? void 0 : concurrency.forEach((c) => {
|
|
1140
|
-
if (typeof c.maxRuns === 'string') {
|
|
1141
|
-
if (!c.maxRuns.trim()) {
|
|
1142
|
-
throw new Error('concurrency.maxRuns expression must be non-empty');
|
|
1143
|
-
}
|
|
1144
|
-
return;
|
|
1145
|
-
}
|
|
1146
|
-
if (c.maxRuns !== undefined && (!Number.isInteger(c.maxRuns) || c.maxRuns <= 0)) {
|
|
1147
|
-
throw new Error(`concurrency.maxRuns must be a positive integer or a CEL expression, got: ${c.maxRuns}`);
|
|
1148
|
-
}
|
|
1149
|
-
});
|
|
1150
|
-
}
|
|
1151
|
-
function mapBatchConfigPb(batch) {
|
|
1152
|
-
if (!batch) {
|
|
1153
|
-
return undefined;
|
|
1154
|
-
}
|
|
1155
|
-
if (!Number.isInteger(batch.maxSize) || batch.maxSize <= 0) {
|
|
1156
|
-
throw new Error(`batch.maxSize must be a positive integer, got: ${batch.maxSize}`);
|
|
1157
|
-
}
|
|
1158
|
-
const batchMaxIntervalMs = batch.maxInterval !== undefined ? (0, duration_1.durationToMs)(batch.maxInterval) : undefined;
|
|
1159
|
-
if (batchMaxIntervalMs !== undefined && batchMaxIntervalMs <= 0) {
|
|
1160
|
-
throw new Error('batch.maxInterval must be positive when provided');
|
|
1161
|
-
}
|
|
1162
|
-
if (batch.groupMaxRuns !== undefined &&
|
|
1163
|
-
(!Number.isInteger(batch.groupMaxRuns) || batch.groupMaxRuns <= 0)) {
|
|
1164
|
-
throw new Error(`batch.groupMaxRuns must be a positive integer when provided, got: ${batch.groupMaxRuns}`);
|
|
1165
|
-
}
|
|
1166
|
-
return {
|
|
1167
|
-
batchMaxSize: batch.maxSize,
|
|
1168
|
-
batchMaxIntervalMs,
|
|
1169
|
-
batchGroupKey: batch.groupKey,
|
|
1170
|
-
batchGroupMaxRuns: batch.groupMaxRuns,
|
|
1171
|
-
broadcastOutput: batch.broadcastOutput,
|
|
1172
|
-
};
|
|
1173
|
-
}
|
|
1174
|
-
// Helper function to validate CEL expressions
|
|
1175
|
-
function validateCelExpression(_expr) {
|
|
1176
|
-
// FIXME: this is a placeholder. In a real implementation, you'd need to use a CEL parser or validator.
|
|
1177
|
-
// For now, we'll just return true to mimic the behavior.
|
|
1178
|
-
return true;
|
|
1179
|
-
}
|
|
1180
|
-
function resolveExecutionTimeout(task, workflowDefaults) {
|
|
1181
|
-
return (0, duration_1.durationToString)(task.executionTimeout || task.timeout || (workflowDefaults === null || workflowDefaults === void 0 ? void 0 : workflowDefaults.executionTimeout) || '60s');
|
|
1182
|
-
}
|
|
1183
|
-
function resolveScheduleTimeout(task, workflowDefaults) {
|
|
1184
|
-
const value = task.scheduleTimeout || (workflowDefaults === null || workflowDefaults === void 0 ? void 0 : workflowDefaults.scheduleTimeout);
|
|
1185
|
-
return value ? (0, duration_1.durationToString)(value) : undefined;
|
|
1186
|
-
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { HatchetClient } from '../client';
|
|
2
|
+
import type { InternalWorker } from './worker-internal';
|
|
3
|
+
import type { ContextRuntime } from './runtime';
|
|
4
|
+
/** A `ContextRuntime` that also exposes the client it wraps, for `ctx.v1`. */
|
|
5
|
+
export interface WorkerContextRuntime extends ContextRuntime {
|
|
6
|
+
readonly client: HatchetClient;
|
|
7
|
+
}
|
|
8
|
+
export declare function createWorkerContextRuntime(client: HatchetClient, worker: InternalWorker): WorkerContextRuntime;
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.createWorkerContextRuntime = createWorkerContextRuntime;
|
|
13
|
+
/**
|
|
14
|
+
* `ContextRuntime` for a worker process: adapts the `HatchetClient` and `InternalWorker`
|
|
15
|
+
* a task runs on to the seam `Context` consumes.
|
|
16
|
+
*/
|
|
17
|
+
const dispatcher_1 = require("../../../protoc/dispatcher");
|
|
18
|
+
// The event client's LogLevel enum has the same string values as the logger's LogLevel
|
|
19
|
+
// union; casting keeps the event client (and its gRPC imports) out of this module's
|
|
20
|
+
// runtime graph.
|
|
21
|
+
function toEventLogLevel(level) {
|
|
22
|
+
if (level === undefined || level === 'OFF') {
|
|
23
|
+
return undefined;
|
|
24
|
+
}
|
|
25
|
+
return level;
|
|
26
|
+
}
|
|
27
|
+
function createWorkerContextRuntime(client, worker) {
|
|
28
|
+
return {
|
|
29
|
+
client,
|
|
30
|
+
get namespace() {
|
|
31
|
+
return client.config.namespace;
|
|
32
|
+
},
|
|
33
|
+
logger: (name) => client.config.logger(name, client.config.log_level),
|
|
34
|
+
cancelRun: (taskRunExternalId) => __awaiter(this, void 0, void 0, function* () {
|
|
35
|
+
yield client.runs.cancel({ ids: [taskRunExternalId] });
|
|
36
|
+
}),
|
|
37
|
+
cancelBatch: (_a) => __awaiter(this, [_a], void 0, function* ({ workerId, jobId, actionId, batchId, memberIds }) {
|
|
38
|
+
yield client.dispatcher.sendBatchActionEvent({
|
|
39
|
+
workerId,
|
|
40
|
+
jobId,
|
|
41
|
+
actionId,
|
|
42
|
+
batchId,
|
|
43
|
+
eventTimestamp: new Date(),
|
|
44
|
+
eventType: dispatcher_1.StepActionEventType.STEP_EVENT_TYPE_CANCELLED,
|
|
45
|
+
items: memberIds.map((id) => ({ taskRunExternalId: id, eventPayload: '' })),
|
|
46
|
+
});
|
|
47
|
+
}),
|
|
48
|
+
putLog: (taskRunExternalId, message, level, retryCount, extra) => __awaiter(this, void 0, void 0, function* () {
|
|
49
|
+
yield client.events.putLog(taskRunExternalId, message, toEventLogLevel(level), retryCount, extra);
|
|
50
|
+
}),
|
|
51
|
+
refreshTimeout: (taskRunExternalId, incrementBy) => __awaiter(this, void 0, void 0, function* () {
|
|
52
|
+
yield client.dispatcher.refreshTimeout(incrementBy, taskRunExternalId);
|
|
53
|
+
}),
|
|
54
|
+
releaseSlot: (taskRunExternalId) => __awaiter(this, void 0, void 0, function* () {
|
|
55
|
+
yield client.dispatcher.client.releaseSlot({ taskRunExternalId });
|
|
56
|
+
}),
|
|
57
|
+
putStream: (taskRunExternalId, data, index) => __awaiter(this, void 0, void 0, function* () {
|
|
58
|
+
yield client.events.putStream(taskRunExternalId, data, index);
|
|
59
|
+
}),
|
|
60
|
+
runWorkflow: (workflowName, input, options) => client.admin.runWorkflow(workflowName, input, options),
|
|
61
|
+
runWorkflows: (runs) => client.admin.runWorkflows(runs),
|
|
62
|
+
workerId: () => worker.workerId,
|
|
63
|
+
hasWorkflow: (workflowName) => !!worker.workflow_registry.find((workflow) => 'id' in workflow ? workflow.id === workflowName : workflow.name === workflowName),
|
|
64
|
+
workerLabels: () => worker.labels,
|
|
65
|
+
upsertWorkerLabels: (labels) => worker.upsertLabels(labels),
|
|
66
|
+
};
|
|
67
|
+
}
|