@hatchet-dev/typescript-sdk 1.11.0 → 1.12.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/admin/admin-client.d.ts +38 -0
- package/clients/admin/admin-client.js +19 -6
- package/clients/dispatcher/action-listener.d.ts +6 -2
- package/clients/dispatcher/action-listener.js +2 -2
- package/clients/dispatcher/dispatcher-client.d.ts +22 -3
- package/clients/dispatcher/dispatcher-client.js +41 -4
- package/clients/event/event-client.d.ts +2 -2
- package/clients/event/event-client.js +4 -4
- package/clients/hatchet-client/hatchet-logger.js +2 -2
- package/clients/rest/generated/Api.d.ts +9 -1
- package/clients/rest/generated/data-contracts.d.ts +44 -8
- package/clients/rest/generated/data-contracts.js +13 -2
- package/clients/worker/worker.js +11 -11
- package/examples/webhooks.d.ts +1 -0
- package/examples/webhooks.js +45 -0
- package/package.json +1 -1
- package/protoc/dispatcher/dispatcher.d.ts +70 -25
- package/protoc/dispatcher/dispatcher.js +323 -97
- package/protoc/events/events.d.ts +4 -4
- package/protoc/events/events.js +20 -16
- package/protoc/v1/workflows.d.ts +18 -7
- package/protoc/v1/workflows.js +122 -2
- package/protoc/workflows/workflows.d.ts +22 -22
- package/protoc/workflows/workflows.js +18 -18
- package/step.d.ts +6 -0
- package/step.js +27 -19
- package/util/workflow-run-ref.js +1 -1
- package/v1/client/admin.d.ts +30 -0
- package/v1/client/admin.js +21 -6
- package/v1/client/client.d.ts +8 -1
- package/v1/client/client.js +13 -2
- package/v1/client/features/runs.d.ts +9 -1
- package/v1/client/features/runs.js +4 -2
- package/v1/client/features/webhooks.d.ts +28 -0
- package/v1/client/features/webhooks.js +97 -0
- package/v1/client/worker/context.d.ts +6 -0
- package/v1/client/worker/context.js +30 -22
- package/v1/client/worker/deprecated/deprecation.d.ts +44 -0
- package/v1/client/worker/deprecated/deprecation.js +95 -0
- package/v1/client/worker/deprecated/index.d.ts +4 -0
- package/v1/client/worker/deprecated/index.js +15 -0
- package/v1/client/worker/deprecated/legacy-registration.d.ts +18 -0
- package/v1/client/worker/deprecated/legacy-registration.js +35 -0
- package/v1/client/worker/deprecated/legacy-v1-worker.d.ts +15 -0
- package/v1/client/worker/deprecated/legacy-v1-worker.js +39 -0
- package/v1/client/worker/deprecated/legacy-worker.d.ts +41 -0
- package/v1/client/worker/deprecated/legacy-worker.js +148 -0
- package/v1/client/worker/slot-utils.d.ts +21 -0
- package/v1/client/worker/slot-utils.js +73 -0
- package/v1/client/worker/worker-internal.d.ts +16 -5
- package/v1/client/worker/worker-internal.js +54 -37
- package/v1/client/worker/worker.d.ts +12 -15
- package/v1/client/worker/worker.js +45 -49
- package/v1/declaration.js +1 -1
- package/v1/index.d.ts +1 -0
- package/v1/index.js +1 -0
- package/v1/parent-run-context-vars.d.ts +4 -1
- package/v1/parent-run-context-vars.js +1 -0
- package/v1/slot-types.d.ts +5 -0
- package/v1/slot-types.js +9 -0
- package/v1/task.d.ts +2 -0
- package/version.d.ts +1 -1
- package/version.js +1 -1
- package/workflow.d.ts +2 -2
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.testingExports = void 0;
|
|
4
|
+
exports.resolveWorkerOptions = resolveWorkerOptions;
|
|
5
|
+
const declaration_1 = require("../../declaration");
|
|
6
|
+
const slot_types_1 = require("../../slot-types");
|
|
7
|
+
const DEFAULT_DEFAULT_SLOTS = 100;
|
|
8
|
+
const DEFAULT_DURABLE_SLOTS = 1000;
|
|
9
|
+
function resolveWorkerOptions(options) {
|
|
10
|
+
const requiredSlotTypes = options.workflows
|
|
11
|
+
? getRequiredSlotTypes(options.workflows)
|
|
12
|
+
: new Set();
|
|
13
|
+
const slotConfig = options.slots || options.durableSlots || options.maxRuns
|
|
14
|
+
? Object.assign(Object.assign({}, (options.slots || options.maxRuns
|
|
15
|
+
? { [slot_types_1.SlotType.Default]: options.slots || options.maxRuns || 0 }
|
|
16
|
+
: {})), (options.durableSlots ? { [slot_types_1.SlotType.Durable]: options.durableSlots } : {})) : {};
|
|
17
|
+
if (requiredSlotTypes.has(slot_types_1.SlotType.Default) && slotConfig[slot_types_1.SlotType.Default] == null) {
|
|
18
|
+
slotConfig[slot_types_1.SlotType.Default] = DEFAULT_DEFAULT_SLOTS;
|
|
19
|
+
}
|
|
20
|
+
if (requiredSlotTypes.has(slot_types_1.SlotType.Durable) && slotConfig[slot_types_1.SlotType.Durable] == null) {
|
|
21
|
+
slotConfig[slot_types_1.SlotType.Durable] = DEFAULT_DURABLE_SLOTS;
|
|
22
|
+
}
|
|
23
|
+
if (Object.keys(slotConfig).length === 0) {
|
|
24
|
+
slotConfig[slot_types_1.SlotType.Default] = DEFAULT_DEFAULT_SLOTS;
|
|
25
|
+
}
|
|
26
|
+
return Object.assign(Object.assign({}, options), { slots: options.slots ||
|
|
27
|
+
options.maxRuns ||
|
|
28
|
+
(slotConfig[slot_types_1.SlotType.Default] != null ? slotConfig[slot_types_1.SlotType.Default] : undefined), durableSlots: options.durableSlots ||
|
|
29
|
+
(slotConfig[slot_types_1.SlotType.Durable] != null ? slotConfig[slot_types_1.SlotType.Durable] : undefined), slotConfig });
|
|
30
|
+
}
|
|
31
|
+
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
32
|
+
exports.testingExports = {
|
|
33
|
+
resolveWorkerOptions,
|
|
34
|
+
};
|
|
35
|
+
function getRequiredSlotTypes(workflows) {
|
|
36
|
+
const required = new Set();
|
|
37
|
+
const addFromRequests = (requests, fallbackType) => {
|
|
38
|
+
if (requests && Object.keys(requests).length > 0) {
|
|
39
|
+
if (requests[slot_types_1.SlotType.Default] !== undefined) {
|
|
40
|
+
required.add(slot_types_1.SlotType.Default);
|
|
41
|
+
}
|
|
42
|
+
if (requests[slot_types_1.SlotType.Durable] !== undefined) {
|
|
43
|
+
required.add(slot_types_1.SlotType.Durable);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
else {
|
|
47
|
+
required.add(fallbackType);
|
|
48
|
+
}
|
|
49
|
+
};
|
|
50
|
+
for (const wf of workflows) {
|
|
51
|
+
if (wf instanceof declaration_1.BaseWorkflowDeclaration) {
|
|
52
|
+
// eslint-disable-next-line dot-notation
|
|
53
|
+
const tasks = wf.definition['_tasks'];
|
|
54
|
+
for (const task of tasks) {
|
|
55
|
+
addFromRequests(task.slotRequests, slot_types_1.SlotType.Default);
|
|
56
|
+
}
|
|
57
|
+
// eslint-disable-next-line dot-notation
|
|
58
|
+
const durableTasks = wf.definition['_durableTasks'];
|
|
59
|
+
if (durableTasks.length > 0) {
|
|
60
|
+
required.add(slot_types_1.SlotType.Durable);
|
|
61
|
+
}
|
|
62
|
+
if (wf.definition.onFailure) {
|
|
63
|
+
const opts = typeof wf.definition.onFailure === 'object' ? wf.definition.onFailure : undefined;
|
|
64
|
+
addFromRequests(opts === null || opts === void 0 ? void 0 : opts.slotRequests, slot_types_1.SlotType.Default);
|
|
65
|
+
}
|
|
66
|
+
if (wf.definition.onSuccess) {
|
|
67
|
+
const opts = typeof wf.definition.onSuccess === 'object' ? wf.definition.onSuccess : undefined;
|
|
68
|
+
addFromRequests(opts === null || opts === void 0 ? void 0 : opts.slotRequests, slot_types_1.SlotType.Default);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
return required;
|
|
73
|
+
}
|
|
@@ -8,11 +8,13 @@ import { BaseWorkflowDeclaration, WorkflowDefinition, HatchetClient } from '../.
|
|
|
8
8
|
import { WorkerLabels } from '../../../clients/dispatcher/dispatcher-client';
|
|
9
9
|
import { StepRunFunction } from '../../../step';
|
|
10
10
|
import { Context } from './context';
|
|
11
|
+
import { SlotConfig } from '../../slot-types';
|
|
11
12
|
export type ActionRegistry = Record<Action['actionId'], Function>;
|
|
12
13
|
export interface WorkerOpts {
|
|
13
14
|
name: string;
|
|
14
15
|
handleKill?: boolean;
|
|
15
|
-
|
|
16
|
+
slots?: number;
|
|
17
|
+
durableSlots?: number;
|
|
16
18
|
labels?: WorkerLabels;
|
|
17
19
|
healthPort?: number;
|
|
18
20
|
enableHealthServer?: boolean;
|
|
@@ -26,9 +28,11 @@ export declare class V1Worker {
|
|
|
26
28
|
action_registry: ActionRegistry;
|
|
27
29
|
workflow_registry: Array<WorkflowDefinition | Workflow>;
|
|
28
30
|
listener: ActionListener | undefined;
|
|
29
|
-
futures: Record<Action['
|
|
30
|
-
contexts: Record<Action['
|
|
31
|
-
|
|
31
|
+
futures: Record<Action['taskRunExternalId'], HatchetPromise<any>>;
|
|
32
|
+
contexts: Record<Action['taskRunExternalId'], Context<any, any>>;
|
|
33
|
+
slots?: number;
|
|
34
|
+
durableSlots?: number;
|
|
35
|
+
slotConfig: SlotConfig;
|
|
32
36
|
logger: Logger;
|
|
33
37
|
registeredWorkflowPromises: Array<Promise<any>>;
|
|
34
38
|
labels: WorkerLabels;
|
|
@@ -39,7 +43,9 @@ export declare class V1Worker {
|
|
|
39
43
|
constructor(client: HatchetClient, options: {
|
|
40
44
|
name: string;
|
|
41
45
|
handleKill?: boolean;
|
|
42
|
-
|
|
46
|
+
slots?: number;
|
|
47
|
+
durableSlots?: number;
|
|
48
|
+
slotConfig?: SlotConfig;
|
|
43
49
|
labels?: WorkerLabels;
|
|
44
50
|
});
|
|
45
51
|
private initializeHealthServer;
|
|
@@ -66,6 +72,11 @@ export declare class V1Worker {
|
|
|
66
72
|
handleCancelStepRun(action: Action): Promise<void>;
|
|
67
73
|
stop(): Promise<void>;
|
|
68
74
|
exitGracefully(handleKill: boolean): Promise<void>;
|
|
75
|
+
/**
|
|
76
|
+
* Creates an action listener by registering the worker with the dispatcher.
|
|
77
|
+
* Override in subclasses to change registration behavior (e.g. legacy engines).
|
|
78
|
+
*/
|
|
79
|
+
protected createListener(): Promise<ActionListener>;
|
|
69
80
|
start(): Promise<void>;
|
|
70
81
|
handleAction(action: Action): Promise<void>;
|
|
71
82
|
upsertLabels(labels: WorkerLabels): Promise<WorkerLabels>;
|
|
@@ -46,7 +46,9 @@ class V1Worker {
|
|
|
46
46
|
this.client = client;
|
|
47
47
|
this.name = (0, apply_namespace_1.applyNamespace)(options.name, this.client.config.namespace);
|
|
48
48
|
this.action_registry = {};
|
|
49
|
-
this.
|
|
49
|
+
this.slots = options.slots;
|
|
50
|
+
this.durableSlots = options.durableSlots;
|
|
51
|
+
this.slotConfig = options.slotConfig || {};
|
|
50
52
|
this.labels = options.labels || {};
|
|
51
53
|
this.enableHealthServer = (_b = (_a = client.config.healthcheck) === null || _a === void 0 ? void 0 : _a.enabled) !== null && _b !== void 0 ? _b : false;
|
|
52
54
|
this.healthPort = (_d = (_c = client.config.healthcheck) === null || _c === void 0 ? void 0 : _c.port) !== null && _d !== void 0 ? _d : 8001;
|
|
@@ -67,11 +69,10 @@ class V1Worker {
|
|
|
67
69
|
this.healthServer = new health_server_1.HealthServer(this.healthPort, () => this.status, this.name, () => this.getAvailableSlots(), () => this.getRegisteredActions(), () => this.getFilteredLabels(), this.logger);
|
|
68
70
|
}
|
|
69
71
|
getAvailableSlots() {
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
}
|
|
72
|
+
// sum all the slots in the slot config
|
|
73
|
+
const totalSlots = Object.values(this.slotConfig).reduce((acc, curr) => acc + curr, 0);
|
|
73
74
|
const currentRuns = Object.keys(this.futures).length;
|
|
74
|
-
return Math.max(0,
|
|
75
|
+
return Math.max(0, totalSlots - currentRuns);
|
|
75
76
|
}
|
|
76
77
|
getRegisteredActions() {
|
|
77
78
|
return Object.keys(this.action_registry);
|
|
@@ -177,6 +178,8 @@ class V1Worker {
|
|
|
177
178
|
rateLimits: [],
|
|
178
179
|
workerLabels: {},
|
|
179
180
|
concurrency: [],
|
|
181
|
+
isDurable: false,
|
|
182
|
+
slotRequests: { default: 1 },
|
|
180
183
|
};
|
|
181
184
|
}
|
|
182
185
|
if (workflow.onFailure && typeof workflow.onFailure === 'object') {
|
|
@@ -194,6 +197,8 @@ class V1Worker {
|
|
|
194
197
|
concurrency: [],
|
|
195
198
|
backoffFactor: ((_f = onFailure.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),
|
|
196
199
|
backoffMaxSeconds: ((_j = onFailure.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),
|
|
200
|
+
isDurable: false,
|
|
201
|
+
slotRequests: { default: 1 },
|
|
197
202
|
};
|
|
198
203
|
}
|
|
199
204
|
let onSuccessTask;
|
|
@@ -252,6 +257,7 @@ class V1Worker {
|
|
|
252
257
|
const jsonSchema = (0, zod_to_json_schema_1.zodToJsonSchema)(workflow.inputValidator);
|
|
253
258
|
inputJsonSchema = new TextEncoder().encode(JSON.stringify(jsonSchema));
|
|
254
259
|
}
|
|
260
|
+
const durableTaskSet = new Set(workflow._durableTasks);
|
|
255
261
|
const registeredWorkflow = this.client._v0.admin.putWorkflowV1({
|
|
256
262
|
name: workflow.name,
|
|
257
263
|
description: workflow.description || '',
|
|
@@ -282,6 +288,8 @@ class V1Worker {
|
|
|
282
288
|
backoffFactor: ((_h = task.backoff) === null || _h === void 0 ? void 0 : _h.factor) || ((_k = (_j = workflow.taskDefaults) === null || _j === void 0 ? void 0 : _j.backoff) === null || _k === void 0 ? void 0 : _k.factor),
|
|
283
289
|
backoffMaxSeconds: ((_l = task.backoff) === null || _l === void 0 ? void 0 : _l.maxSeconds) || ((_o = (_m = workflow.taskDefaults) === null || _m === void 0 ? void 0 : _m.backoff) === null || _o === void 0 ? void 0 : _o.maxSeconds),
|
|
284
290
|
conditions: (0, transformer_1.taskConditionsToPb)(task),
|
|
291
|
+
isDurable: durableTaskSet.has(task),
|
|
292
|
+
slotRequests: task.slotRequests || (durableTaskSet.has(task) ? { durable: 1 } : { default: 1 }),
|
|
285
293
|
concurrency: task.concurrency
|
|
286
294
|
? Array.isArray(task.concurrency)
|
|
287
295
|
? task.concurrency
|
|
@@ -398,11 +406,11 @@ class V1Worker {
|
|
|
398
406
|
}
|
|
399
407
|
handleStartStepRun(action) {
|
|
400
408
|
return __awaiter(this, void 0, void 0, function* () {
|
|
401
|
-
const { actionId } = action;
|
|
409
|
+
const { actionId, taskRunExternalId } = action;
|
|
402
410
|
try {
|
|
403
411
|
// Note: we always use a DurableContext since its a superset of the Context class
|
|
404
412
|
const context = new context_1.DurableContext(action, this.client, this);
|
|
405
|
-
this.contexts[
|
|
413
|
+
this.contexts[taskRunExternalId] = context;
|
|
406
414
|
const step = this.action_registry[actionId];
|
|
407
415
|
if (!step) {
|
|
408
416
|
this.logger.error(`Registered actions: '${Object.keys(this.action_registry).join(', ')}'`);
|
|
@@ -412,7 +420,7 @@ class V1Worker {
|
|
|
412
420
|
const run = () => __awaiter(this, void 0, void 0, function* () {
|
|
413
421
|
parent_run_context_vars_1.parentRunContextManager.setContext({
|
|
414
422
|
parentId: action.workflowRunId,
|
|
415
|
-
|
|
423
|
+
parentTaskRunExternalId: taskRunExternalId,
|
|
416
424
|
childIndex: 0,
|
|
417
425
|
desiredWorkerId: this.workerId || '',
|
|
418
426
|
});
|
|
@@ -423,7 +431,7 @@ class V1Worker {
|
|
|
423
431
|
if (context.cancelled) {
|
|
424
432
|
return;
|
|
425
433
|
}
|
|
426
|
-
this.logger.info(`Task run ${
|
|
434
|
+
this.logger.info(`Task run ${taskRunExternalId} succeeded`);
|
|
427
435
|
// Send the action event to the dispatcher
|
|
428
436
|
const event = this.getStepActionEvent(action, dispatcher_1.StepActionEventType.STEP_EVENT_TYPE_COMPLETED, false, result || null, action.retryCount);
|
|
429
437
|
yield this.client._v0.dispatcher.sendStepActionEvent(event);
|
|
@@ -442,8 +450,8 @@ class V1Worker {
|
|
|
442
450
|
}
|
|
443
451
|
finally {
|
|
444
452
|
// delete the run from the futures
|
|
445
|
-
delete this.futures[
|
|
446
|
-
delete this.contexts[
|
|
453
|
+
delete this.futures[taskRunExternalId];
|
|
454
|
+
delete this.contexts[taskRunExternalId];
|
|
447
455
|
}
|
|
448
456
|
});
|
|
449
457
|
const failure = (error) => __awaiter(this, void 0, void 0, function* () {
|
|
@@ -452,7 +460,7 @@ class V1Worker {
|
|
|
452
460
|
if (context.cancelled) {
|
|
453
461
|
return;
|
|
454
462
|
}
|
|
455
|
-
this.logger.error(`Task run ${
|
|
463
|
+
this.logger.error(`Task run ${taskRunExternalId} failed: ${error.message}`);
|
|
456
464
|
if (error.stack) {
|
|
457
465
|
this.logger.error(error.stack);
|
|
458
466
|
}
|
|
@@ -468,8 +476,8 @@ class V1Worker {
|
|
|
468
476
|
}
|
|
469
477
|
finally {
|
|
470
478
|
// delete the run from the futures
|
|
471
|
-
delete this.futures[
|
|
472
|
-
delete this.contexts[
|
|
479
|
+
delete this.futures[taskRunExternalId];
|
|
480
|
+
delete this.contexts[taskRunExternalId];
|
|
473
481
|
}
|
|
474
482
|
});
|
|
475
483
|
const future = new hatchet_promise_1.default((() => __awaiter(this, void 0, void 0, function* () {
|
|
@@ -483,7 +491,7 @@ class V1Worker {
|
|
|
483
491
|
}
|
|
484
492
|
yield success(result);
|
|
485
493
|
}))());
|
|
486
|
-
this.futures[
|
|
494
|
+
this.futures[taskRunExternalId] = future;
|
|
487
495
|
// Send the action event to the dispatcher
|
|
488
496
|
const event = this.getStepActionEvent(action, dispatcher_1.StepActionEventType.STEP_EVENT_TYPE_STARTED, false, undefined, action.retryCount);
|
|
489
497
|
this.client._v0.dispatcher.sendStepActionEvent(event).catch((e) => {
|
|
@@ -495,10 +503,10 @@ class V1Worker {
|
|
|
495
503
|
catch (e) {
|
|
496
504
|
const message = (e === null || e === void 0 ? void 0 : e.message) || String(e);
|
|
497
505
|
if (message.includes('Cancelled')) {
|
|
498
|
-
this.logger.debug(`Task run ${
|
|
506
|
+
this.logger.debug(`Task run ${taskRunExternalId} was cancelled`);
|
|
499
507
|
}
|
|
500
508
|
else {
|
|
501
|
-
this.logger.error(`Could not wait for task run ${
|
|
509
|
+
this.logger.error(`Could not wait for task run ${taskRunExternalId} to finish. ` +
|
|
502
510
|
`See https://docs.hatchet.run/home/cancellation for best practices on handling cancellation: `, e);
|
|
503
511
|
}
|
|
504
512
|
}
|
|
@@ -510,11 +518,11 @@ class V1Worker {
|
|
|
510
518
|
}
|
|
511
519
|
handleStartGroupKeyRun(action) {
|
|
512
520
|
return __awaiter(this, void 0, void 0, function* () {
|
|
513
|
-
const { actionId } = action;
|
|
521
|
+
const { actionId, getGroupKeyRunId, taskRunExternalId } = action;
|
|
514
522
|
this.logger.error('Concurrency Key Functions have been deprecated and will be removed in a future release. Use Concurrency Expressions instead.');
|
|
515
523
|
try {
|
|
516
524
|
const context = new context_1.Context(action, this.client, this);
|
|
517
|
-
const key =
|
|
525
|
+
const key = getGroupKeyRunId;
|
|
518
526
|
if (!key) {
|
|
519
527
|
this.logger.error(`No group key run id provided for action ${actionId}`);
|
|
520
528
|
return;
|
|
@@ -530,7 +538,7 @@ class V1Worker {
|
|
|
530
538
|
return step(context);
|
|
531
539
|
});
|
|
532
540
|
const success = (result) => {
|
|
533
|
-
this.logger.info(`Task run ${
|
|
541
|
+
this.logger.info(`Task run ${taskRunExternalId} succeeded`);
|
|
534
542
|
try {
|
|
535
543
|
// Send the action event to the dispatcher
|
|
536
544
|
const event = this.getGroupKeyActionEvent(action, dispatcher_1.GroupKeyActionEventType.GROUP_KEY_EVENT_TYPE_COMPLETED, result);
|
|
@@ -584,8 +592,8 @@ class V1Worker {
|
|
|
584
592
|
workerId: this.name,
|
|
585
593
|
jobId: action.jobId,
|
|
586
594
|
jobRunId: action.jobRunId,
|
|
587
|
-
|
|
588
|
-
|
|
595
|
+
taskId: action.taskId,
|
|
596
|
+
taskRunExternalId: action.taskRunExternalId,
|
|
589
597
|
actionId: action.actionId,
|
|
590
598
|
eventTimestamp: new Date(),
|
|
591
599
|
eventType,
|
|
@@ -610,17 +618,17 @@ class V1Worker {
|
|
|
610
618
|
}
|
|
611
619
|
handleCancelStepRun(action) {
|
|
612
620
|
return __awaiter(this, void 0, void 0, function* () {
|
|
613
|
-
const {
|
|
621
|
+
const { taskRunExternalId } = action;
|
|
614
622
|
try {
|
|
615
|
-
this.logger.info(`Cancelling task run ${
|
|
616
|
-
const future = this.futures[
|
|
617
|
-
const context = this.contexts[
|
|
623
|
+
this.logger.info(`Cancelling task run ${taskRunExternalId}`);
|
|
624
|
+
const future = this.futures[taskRunExternalId];
|
|
625
|
+
const context = this.contexts[taskRunExternalId];
|
|
618
626
|
if (context && context.abortController) {
|
|
619
627
|
context.abortController.abort('Cancelled by worker');
|
|
620
628
|
}
|
|
621
629
|
if (future) {
|
|
622
630
|
future.promise.catch(() => {
|
|
623
|
-
this.logger.info(`Cancelled task run ${
|
|
631
|
+
this.logger.info(`Cancelled task run ${taskRunExternalId}`);
|
|
624
632
|
});
|
|
625
633
|
future.cancel('Cancelled by worker');
|
|
626
634
|
yield future.promise;
|
|
@@ -628,11 +636,11 @@ class V1Worker {
|
|
|
628
636
|
}
|
|
629
637
|
catch (e) {
|
|
630
638
|
// Expected: the promise rejects when cancelled
|
|
631
|
-
this.logger.debug(`Task run ${
|
|
639
|
+
this.logger.debug(`Task run ${taskRunExternalId} cancellation completed`);
|
|
632
640
|
}
|
|
633
641
|
finally {
|
|
634
|
-
delete this.futures[
|
|
635
|
-
delete this.contexts[
|
|
642
|
+
delete this.futures[taskRunExternalId];
|
|
643
|
+
delete this.contexts[taskRunExternalId];
|
|
636
644
|
}
|
|
637
645
|
});
|
|
638
646
|
}
|
|
@@ -671,6 +679,21 @@ class V1Worker {
|
|
|
671
679
|
}
|
|
672
680
|
});
|
|
673
681
|
}
|
|
682
|
+
/**
|
|
683
|
+
* Creates an action listener by registering the worker with the dispatcher.
|
|
684
|
+
* Override in subclasses to change registration behavior (e.g. legacy engines).
|
|
685
|
+
*/
|
|
686
|
+
createListener() {
|
|
687
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
688
|
+
return this.client._v0.dispatcher.getActionListener({
|
|
689
|
+
workerName: this.name,
|
|
690
|
+
services: ['default'],
|
|
691
|
+
actions: Object.keys(this.action_registry),
|
|
692
|
+
slotConfig: this.slotConfig,
|
|
693
|
+
labels: this.labels,
|
|
694
|
+
});
|
|
695
|
+
});
|
|
696
|
+
}
|
|
674
697
|
start() {
|
|
675
698
|
return __awaiter(this, void 0, void 0, function* () {
|
|
676
699
|
var _a, e_1, _b, _c;
|
|
@@ -691,13 +714,7 @@ class V1Worker {
|
|
|
691
714
|
return;
|
|
692
715
|
}
|
|
693
716
|
try {
|
|
694
|
-
this.listener = yield this.
|
|
695
|
-
workerName: this.name,
|
|
696
|
-
services: ['default'],
|
|
697
|
-
actions: Object.keys(this.action_registry),
|
|
698
|
-
maxRuns: this.maxRuns,
|
|
699
|
-
labels: this.labels,
|
|
700
|
-
});
|
|
717
|
+
this.listener = yield this.createListener();
|
|
701
718
|
this.workerId = this.listener.workerId;
|
|
702
719
|
this.setStatus(health_server_1.workerStatus.HEALTHY);
|
|
703
720
|
const generator = this.listener.actions();
|
|
@@ -5,23 +5,16 @@ import { WebhookWorkerCreateRequest } from '../../../clients/rest/generated/data
|
|
|
5
5
|
import { BaseWorkflowDeclaration } from '../../declaration';
|
|
6
6
|
import { HatchetClient } from '../..';
|
|
7
7
|
import { V1Worker } from './worker-internal';
|
|
8
|
+
import { type WorkerSlotOptions } from './slot-utils';
|
|
8
9
|
/**
|
|
9
10
|
* Options for creating a new hatchet worker
|
|
10
11
|
* @interface CreateWorkerOpts
|
|
11
12
|
*/
|
|
12
|
-
export interface CreateWorkerOpts {
|
|
13
|
-
/** (optional) Maximum number of concurrent runs on this worker, defaults to 100 */
|
|
14
|
-
slots?: number;
|
|
15
|
-
/** (optional) Array of workflows to register */
|
|
16
|
-
workflows?: BaseWorkflowDeclaration<any, any>[] | V0Workflow[];
|
|
13
|
+
export interface CreateWorkerOpts extends WorkerSlotOptions {
|
|
17
14
|
/** (optional) Worker labels for affinity-based assignment */
|
|
18
15
|
labels?: WorkerLabels;
|
|
19
16
|
/** (optional) Whether to handle kill signals */
|
|
20
17
|
handleKill?: boolean;
|
|
21
|
-
/** @deprecated Use slots instead */
|
|
22
|
-
maxRuns?: number;
|
|
23
|
-
/** (optional) Maximum number of concurrent runs on the durable worker, defaults to 1,000 */
|
|
24
|
-
durableSlots?: number;
|
|
25
18
|
}
|
|
26
19
|
/**
|
|
27
20
|
* HatchetWorker class for workflow execution runtime
|
|
@@ -32,8 +25,11 @@ export declare class Worker {
|
|
|
32
25
|
_v1: HatchetClient;
|
|
33
26
|
_v0: LegacyHatchetClient;
|
|
34
27
|
/** Internal reference to the underlying V0 worker implementation */
|
|
35
|
-
|
|
36
|
-
|
|
28
|
+
_internal: V1Worker;
|
|
29
|
+
/** Set when connected to a legacy engine that needs dual-worker architecture */
|
|
30
|
+
private _legacyWorker;
|
|
31
|
+
/** Tracks all workflows registered after construction (via registerWorkflow/registerWorkflows) */
|
|
32
|
+
private _registeredWorkflows;
|
|
37
33
|
/**
|
|
38
34
|
* Creates a new HatchetWorker instance
|
|
39
35
|
* @param nonDurable - The V0 worker implementation
|
|
@@ -63,12 +59,12 @@ export declare class Worker {
|
|
|
63
59
|
* Starts the worker
|
|
64
60
|
* @returns Promise that resolves when the worker is stopped or killed
|
|
65
61
|
*/
|
|
66
|
-
start(): Promise<void
|
|
62
|
+
start(): Promise<void>;
|
|
67
63
|
/**
|
|
68
64
|
* Stops the worker
|
|
69
65
|
* @returns Promise that resolves when the worker stops
|
|
70
66
|
*/
|
|
71
|
-
stop(): Promise<void
|
|
67
|
+
stop(): Promise<void>;
|
|
72
68
|
/**
|
|
73
69
|
* Updates or inserts worker labels
|
|
74
70
|
* @param labels - Worker labels to update
|
|
@@ -87,6 +83,7 @@ export declare class Worker {
|
|
|
87
83
|
*/
|
|
88
84
|
registerWebhook(webhook: WebhookWorkerCreateRequest): Promise<import("axios").AxiosResponse<import("../../../clients/rest/generated/data-contracts").WebhookWorkerCreated, any, {}>>;
|
|
89
85
|
isPaused(): Promise<boolean>;
|
|
90
|
-
pause(): Promise<
|
|
91
|
-
unpause(): Promise<
|
|
86
|
+
pause(): Promise<void> | Promise<import("../../../clients/rest/generated/data-contracts").Worker>;
|
|
87
|
+
unpause(): Promise<void> | Promise<import("../../../clients/rest/generated/data-contracts").Worker>;
|
|
92
88
|
}
|
|
89
|
+
export { testingExports as __testing } from './slot-utils';
|
|
@@ -9,10 +9,11 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
9
9
|
});
|
|
10
10
|
};
|
|
11
11
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
-
exports.Worker = void 0;
|
|
12
|
+
exports.__testing = exports.Worker = void 0;
|
|
13
13
|
const declaration_1 = require("../../declaration");
|
|
14
14
|
const worker_internal_1 = require("./worker-internal");
|
|
15
|
-
const
|
|
15
|
+
const slot_utils_1 = require("./slot-utils");
|
|
16
|
+
const deprecated_1 = require("./deprecated");
|
|
16
17
|
/**
|
|
17
18
|
* HatchetWorker class for workflow execution runtime
|
|
18
19
|
*/
|
|
@@ -22,9 +23,11 @@ class Worker {
|
|
|
22
23
|
* @param nonDurable - The V0 worker implementation
|
|
23
24
|
*/
|
|
24
25
|
constructor(v1, v0, nonDurable, config, name) {
|
|
26
|
+
/** Tracks all workflows registered after construction (via registerWorkflow/registerWorkflows) */
|
|
27
|
+
this._registeredWorkflows = [];
|
|
25
28
|
this._v1 = v1;
|
|
26
29
|
this._v0 = v0;
|
|
27
|
-
this.
|
|
30
|
+
this._internal = nonDurable;
|
|
28
31
|
this.config = config;
|
|
29
32
|
this.name = name;
|
|
30
33
|
}
|
|
@@ -36,7 +39,8 @@ class Worker {
|
|
|
36
39
|
*/
|
|
37
40
|
static create(v1, v0, name, options) {
|
|
38
41
|
return __awaiter(this, void 0, void 0, function* () {
|
|
39
|
-
const
|
|
42
|
+
const resolvedOptions = (0, slot_utils_1.resolveWorkerOptions)(options);
|
|
43
|
+
const opts = Object.assign({ name }, resolvedOptions);
|
|
40
44
|
const internalWorker = new worker_internal_1.V1Worker(v1, opts);
|
|
41
45
|
const worker = new Worker(v1, v0, internalWorker, options, name);
|
|
42
46
|
yield worker.registerWorkflows(options.workflows);
|
|
@@ -51,21 +55,17 @@ class Worker {
|
|
|
51
55
|
registerWorkflows(workflows) {
|
|
52
56
|
return __awaiter(this, void 0, void 0, function* () {
|
|
53
57
|
for (const wf of workflows || []) {
|
|
58
|
+
this._registeredWorkflows.push(wf);
|
|
54
59
|
if (wf instanceof declaration_1.BaseWorkflowDeclaration) {
|
|
55
60
|
// TODO check if tenant is V1
|
|
56
|
-
yield this.
|
|
61
|
+
yield this._internal.registerWorkflowV1(wf);
|
|
57
62
|
if (wf.definition._durableTasks.length > 0) {
|
|
58
|
-
|
|
59
|
-
const opts = Object.assign(Object.assign({ name: `${this.name}-durable` }, this.config), { maxRuns: this.config.durableSlots || DEFAULT_DURABLE_SLOTS });
|
|
60
|
-
this.durable = new worker_internal_1.V1Worker(this._v1, opts);
|
|
61
|
-
yield this.durable.registerWorkflowV1(wf, true);
|
|
62
|
-
}
|
|
63
|
-
this.durable.registerDurableActionsV1(wf.definition);
|
|
63
|
+
this._internal.registerDurableActionsV1(wf.definition);
|
|
64
64
|
}
|
|
65
65
|
}
|
|
66
66
|
else {
|
|
67
67
|
// fallback to v0 client for backwards compatibility
|
|
68
|
-
yield this.
|
|
68
|
+
yield this._internal.registerWorkflow(wf);
|
|
69
69
|
}
|
|
70
70
|
}
|
|
71
71
|
});
|
|
@@ -84,22 +84,29 @@ class Worker {
|
|
|
84
84
|
* @returns Promise that resolves when the worker is stopped or killed
|
|
85
85
|
*/
|
|
86
86
|
start() {
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
87
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
88
|
+
// Check engine version and fall back to legacy dual-worker mode if needed
|
|
89
|
+
if (yield (0, deprecated_1.isLegacyEngine)(this._v1)) {
|
|
90
|
+
// Include workflows registered after construction (via registerWorkflow/registerWorkflows)
|
|
91
|
+
// so the legacy worker picks them up.
|
|
92
|
+
const legacyConfig = Object.assign(Object.assign({}, this.config), { workflows: this._registeredWorkflows.length
|
|
93
|
+
? this._registeredWorkflows
|
|
94
|
+
: this.config.workflows });
|
|
95
|
+
this._legacyWorker = yield deprecated_1.LegacyDualWorker.create(this._v1, this.name, legacyConfig);
|
|
96
|
+
return this._legacyWorker.start();
|
|
97
|
+
}
|
|
98
|
+
return this._internal.start();
|
|
99
|
+
});
|
|
92
100
|
}
|
|
93
101
|
/**
|
|
94
102
|
* Stops the worker
|
|
95
103
|
* @returns Promise that resolves when the worker stops
|
|
96
104
|
*/
|
|
97
105
|
stop() {
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
workers.push(this.durable);
|
|
106
|
+
if (this._legacyWorker) {
|
|
107
|
+
return this._legacyWorker.stop();
|
|
101
108
|
}
|
|
102
|
-
return
|
|
109
|
+
return this._internal.stop();
|
|
103
110
|
}
|
|
104
111
|
/**
|
|
105
112
|
* Updates or inserts worker labels
|
|
@@ -107,14 +114,14 @@ class Worker {
|
|
|
107
114
|
* @returns Promise that resolves when labels are updated
|
|
108
115
|
*/
|
|
109
116
|
upsertLabels(labels) {
|
|
110
|
-
return this.
|
|
117
|
+
return this._internal.upsertLabels(labels);
|
|
111
118
|
}
|
|
112
119
|
/**
|
|
113
120
|
* Get the labels for the worker
|
|
114
121
|
* @returns The labels for the worker
|
|
115
122
|
*/
|
|
116
123
|
getLabels() {
|
|
117
|
-
return this.
|
|
124
|
+
return this._internal.labels;
|
|
118
125
|
}
|
|
119
126
|
/**
|
|
120
127
|
* Register a webhook with the worker
|
|
@@ -122,44 +129,33 @@ class Worker {
|
|
|
122
129
|
* @returns A promise that resolves when the webhook is registered
|
|
123
130
|
*/
|
|
124
131
|
registerWebhook(webhook) {
|
|
125
|
-
return this.
|
|
132
|
+
return this._internal.registerWebhook(webhook);
|
|
126
133
|
}
|
|
127
134
|
isPaused() {
|
|
128
135
|
return __awaiter(this, void 0, void 0, function* () {
|
|
129
|
-
var _a
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
promises.push(this._v1.workers.isPaused(this.nonDurable.workerId));
|
|
136
|
+
var _a;
|
|
137
|
+
if (!((_a = this._internal) === null || _a === void 0 ? void 0 : _a.workerId)) {
|
|
138
|
+
return false;
|
|
133
139
|
}
|
|
134
|
-
|
|
135
|
-
promises.push(this._v1.workers.isPaused(this.durable.workerId));
|
|
136
|
-
}
|
|
137
|
-
const res = yield Promise.all(promises);
|
|
138
|
-
return !res.includes(false);
|
|
140
|
+
return this._v1.workers.isPaused(this._internal.workerId);
|
|
139
141
|
});
|
|
140
142
|
}
|
|
141
143
|
// TODO docstrings
|
|
142
144
|
pause() {
|
|
143
|
-
var _a
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
promises.push(this._v1.workers.pause(this.nonDurable.workerId));
|
|
147
|
-
}
|
|
148
|
-
if ((_b = this.durable) === null || _b === void 0 ? void 0 : _b.workerId) {
|
|
149
|
-
promises.push(this._v1.workers.pause(this.durable.workerId));
|
|
145
|
+
var _a;
|
|
146
|
+
if (!((_a = this._internal) === null || _a === void 0 ? void 0 : _a.workerId)) {
|
|
147
|
+
return Promise.resolve();
|
|
150
148
|
}
|
|
151
|
-
return
|
|
149
|
+
return this._v1.workers.pause(this._internal.workerId);
|
|
152
150
|
}
|
|
153
151
|
unpause() {
|
|
154
|
-
var _a
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
promises.push(this._v1.workers.unpause(this.nonDurable.workerId));
|
|
158
|
-
}
|
|
159
|
-
if ((_b = this.durable) === null || _b === void 0 ? void 0 : _b.workerId) {
|
|
160
|
-
promises.push(this._v1.workers.unpause(this.durable.workerId));
|
|
152
|
+
var _a;
|
|
153
|
+
if (!((_a = this._internal) === null || _a === void 0 ? void 0 : _a.workerId)) {
|
|
154
|
+
return Promise.resolve();
|
|
161
155
|
}
|
|
162
|
-
return
|
|
156
|
+
return this._v1.workers.unpause(this._internal.workerId);
|
|
163
157
|
}
|
|
164
158
|
}
|
|
165
159
|
exports.Worker = Worker;
|
|
160
|
+
var slot_utils_2 = require("./slot-utils");
|
|
161
|
+
Object.defineProperty(exports, "__testing", { enumerable: true, get: function () { return slot_utils_2.testingExports; } });
|
package/v1/declaration.js
CHANGED
|
@@ -48,7 +48,7 @@ class BaseWorkflowDeclaration {
|
|
|
48
48
|
if (!parentRunContext && ((options === null || options === void 0 ? void 0 : options.childKey) || (options === null || options === void 0 ? void 0 : options.sticky))) {
|
|
49
49
|
this.client.admin.logger.warn('ignoring childKey or sticky because run is not being spawned from a parent task');
|
|
50
50
|
}
|
|
51
|
-
const runOpts = Object.assign(Object.assign({}, options), { parentId: parentRunContext === null || parentRunContext === void 0 ? void 0 : parentRunContext.parentId,
|
|
51
|
+
const runOpts = Object.assign(Object.assign({}, options), { parentId: parentRunContext === null || parentRunContext === void 0 ? void 0 : parentRunContext.parentId, parentTaskRunExternalId: parentRunContext === null || parentRunContext === void 0 ? void 0 : parentRunContext.parentTaskRunExternalId, childIndex: parentRunContext === null || parentRunContext === void 0 ? void 0 : parentRunContext.childIndex, sticky: (options === null || options === void 0 ? void 0 : options.sticky) ? parentRunContext === null || parentRunContext === void 0 ? void 0 : parentRunContext.desiredWorkerId : undefined, childKey: options === null || options === void 0 ? void 0 : options.childKey });
|
|
52
52
|
if (Array.isArray(input)) {
|
|
53
53
|
let resp = [];
|
|
54
54
|
for (let i = 0; i < input.length; i += 500) {
|
package/v1/index.d.ts
CHANGED
package/v1/index.js
CHANGED