@hatchet-dev/typescript-sdk 1.3.2 → 1.4.0-alpha.2

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.
Files changed (42) hide show
  1. package/clients/dispatcher/heartbeat/heartbeat-worker.js +3 -2
  2. package/clients/hatchet-client/hatchet-client.d.ts +3 -5
  3. package/clients/hatchet-client/hatchet-client.js +11 -72
  4. package/clients/worker/worker.d.ts +6 -9
  5. package/clients/worker/worker.js +2 -164
  6. package/examples/fanout-worker.js +1 -2
  7. package/examples/manual-trigger.js +1 -1
  8. package/package.json +3 -2
  9. package/step.d.ts +13 -11
  10. package/step.js +44 -40
  11. package/util/grpc-helpers.d.ts +10 -0
  12. package/util/grpc-helpers.js +79 -0
  13. package/v1/client/admin.d.ts +64 -0
  14. package/v1/client/admin.js +155 -0
  15. package/v1/client/client.d.ts +14 -9
  16. package/v1/client/client.interface.d.ts +4 -2
  17. package/v1/client/client.js +28 -16
  18. package/v1/client/worker/context.d.ts +246 -0
  19. package/v1/client/worker/context.js +512 -0
  20. package/v1/client/worker/worker-internal.d.ts +62 -0
  21. package/v1/client/worker/worker-internal.js +703 -0
  22. package/v1/client/{worker.d.ts → worker/worker.d.ts} +15 -15
  23. package/v1/client/{worker.js → worker/worker.js} +14 -11
  24. package/v1/declaration.d.ts +3 -3
  25. package/v1/declaration.js +21 -14
  26. package/v1/examples/cancellations/run.js +4 -4
  27. package/v1/examples/cancellations/workflow.js +2 -2
  28. package/v1/examples/high-memory/child-worker.js +29 -0
  29. package/v1/examples/high-memory/parent-worker.d.ts +1 -0
  30. package/v1/examples/high-memory/parent-worker.js +29 -0
  31. package/v1/examples/high-memory/run.d.ts +1 -0
  32. package/v1/examples/high-memory/run.js +27 -0
  33. package/v1/examples/high-memory/workflow-with-child.d.ts +12 -0
  34. package/v1/examples/high-memory/workflow-with-child.js +48 -0
  35. package/v1/examples/with_timeouts/workflow.js +4 -4
  36. package/v1/index.d.ts +1 -1
  37. package/v1/index.js +1 -1
  38. package/v1/task.d.ts +2 -1
  39. package/version.d.ts +1 -1
  40. package/version.js +1 -1
  41. package/examples/api.js +0 -61
  42. /package/{examples/api.d.ts → v1/examples/high-memory/child-worker.d.ts} +0 -0
@@ -0,0 +1,703 @@
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
+ var __asyncValues = (this && this.__asyncValues) || function (o) {
12
+ if (!Symbol.asyncIterator) throw new TypeError("Symbol.asyncIterator is not defined.");
13
+ var m = o[Symbol.asyncIterator], i;
14
+ return m ? m.call(o) : (o = typeof __values === "function" ? __values(o) : o[Symbol.iterator](), i = {}, verb("next"), verb("throw"), verb("return"), i[Symbol.asyncIterator] = function () { return this; }, i);
15
+ function verb(n) { i[n] = o[n] && function (v) { return new Promise(function (resolve, reject) { v = o[n](v), settle(resolve, reject, v.done, v.value); }); }; }
16
+ function settle(resolve, reject, d, v) { Promise.resolve(v).then(function(v) { resolve({ value: v, done: d }); }, reject); }
17
+ };
18
+ var __importDefault = (this && this.__importDefault) || function (mod) {
19
+ return (mod && mod.__esModule) ? mod : { "default": mod };
20
+ };
21
+ Object.defineProperty(exports, "__esModule", { value: true });
22
+ exports.V1Worker = void 0;
23
+ /* eslint-disable no-underscore-dangle */
24
+ /* eslint-disable no-nested-ternary */
25
+ const hatchet_error_1 = __importDefault(require("../../../util/errors/hatchet-error"));
26
+ const dispatcher_1 = require("../../../protoc/dispatcher");
27
+ const hatchet_promise_1 = __importDefault(require("../../../util/hatchet-promise/hatchet-promise"));
28
+ const workflows_1 = require("../../../protoc/workflows");
29
+ const task_1 = require("../../task");
30
+ const transformer_1 = require("../../conditions/transformer");
31
+ const step_1 = require("../../../step");
32
+ const context_1 = require("./context");
33
+ class V1Worker {
34
+ constructor(client, options) {
35
+ this.workflow_registry = [];
36
+ this.futures = {};
37
+ this.contexts = {};
38
+ this.registeredWorkflowPromises = [];
39
+ this.labels = {};
40
+ this.client = client;
41
+ this.name = this.client.config.namespace + options.name;
42
+ this.action_registry = {};
43
+ this.maxRuns = options.maxRuns;
44
+ this.labels = options.labels || {};
45
+ process.on('SIGTERM', () => this.exitGracefully(true));
46
+ process.on('SIGINT', () => this.exitGracefully(true));
47
+ this.killing = false;
48
+ this.handle_kill = options.handleKill === undefined ? true : options.handleKill;
49
+ this.logger = client.config.logger(`Worker/${this.name}`, this.client.config.log_level);
50
+ }
51
+ registerActions(workflow) {
52
+ var _a;
53
+ const newActions = workflow.steps.reduce((acc, step) => {
54
+ acc[`${workflow.id}:${step.name.toLowerCase()}`] = step.run;
55
+ return acc;
56
+ }, {});
57
+ const onFailureAction = workflow.onFailure
58
+ ? {
59
+ [`${workflow.id}-on-failure:${workflow.onFailure.name}`]: workflow.onFailure.run,
60
+ }
61
+ : {};
62
+ this.action_registry = Object.assign(Object.assign(Object.assign({}, this.action_registry), newActions), onFailureAction);
63
+ this.action_registry =
64
+ ((_a = workflow.concurrency) === null || _a === void 0 ? void 0 : _a.name) && workflow.concurrency.key
65
+ ? Object.assign(Object.assign({}, this.action_registry), { [`${workflow.id}:${workflow.concurrency.name.toLowerCase()}`]: workflow.concurrency.key }) : Object.assign({}, this.action_registry);
66
+ }
67
+ getHandler(workflows) {
68
+ throw new Error('Not implemented');
69
+ // TODO v1
70
+ // for (const workflow of workflows) {
71
+ // const wf: Workflow = {
72
+ // ...workflow,
73
+ // id: this.client.config.namespace + workflow.id,
74
+ // };
75
+ // this.registerActions(wf);
76
+ // }
77
+ // return new WebhookHandler(this, workflows);
78
+ }
79
+ registerWebhook(webhook) {
80
+ return __awaiter(this, void 0, void 0, function* () {
81
+ return this.client._v0.admin.registerWebhook(Object.assign({}, webhook));
82
+ });
83
+ }
84
+ /**
85
+ * @deprecated use registerWorkflow instead
86
+ */
87
+ register_workflow(initWorkflow) {
88
+ return __awaiter(this, void 0, void 0, function* () {
89
+ return this.registerWorkflow(initWorkflow);
90
+ });
91
+ }
92
+ registerDurableActionsV1(workflow) {
93
+ const newActions = workflow._durableTasks.reduce((acc, task) => {
94
+ acc[`${workflow.name}:${task.name.toLowerCase()}`] = (ctx) => task.fn(ctx.input, ctx);
95
+ return acc;
96
+ }, {});
97
+ this.action_registry = Object.assign(Object.assign({}, this.action_registry), newActions);
98
+ }
99
+ registerActionsV1(workflow) {
100
+ const newActions = workflow._tasks.reduce((acc, task) => {
101
+ acc[`${workflow.name}:${task.name.toLowerCase()}`] = (ctx) => task.fn(ctx.input, ctx);
102
+ return acc;
103
+ }, {});
104
+ const onFailureFn = workflow.onFailure
105
+ ? typeof workflow.onFailure === 'function'
106
+ ? workflow.onFailure
107
+ : workflow.onFailure.fn
108
+ : undefined;
109
+ const onFailureAction = onFailureFn
110
+ ? {
111
+ [onFailureTaskName(workflow)]: (ctx) => onFailureFn(ctx.input, ctx),
112
+ }
113
+ : {};
114
+ this.action_registry = Object.assign(Object.assign(Object.assign({}, this.action_registry), newActions), onFailureAction);
115
+ }
116
+ registerWorkflowV1(initWorkflow) {
117
+ return __awaiter(this, void 0, void 0, function* () {
118
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v;
119
+ // patch the namespace
120
+ const workflow = Object.assign(Object.assign({}, initWorkflow.definition), { name: (this.client.config.namespace + initWorkflow.definition.name).toLowerCase() });
121
+ try {
122
+ const { concurrency } = workflow;
123
+ let onFailureTask;
124
+ if (workflow.onFailure && typeof workflow.onFailure === 'function') {
125
+ onFailureTask = {
126
+ readableId: 'on-failure-task',
127
+ action: onFailureTaskName(workflow),
128
+ timeout: '60s',
129
+ inputs: '{}',
130
+ parents: [],
131
+ retries: 0,
132
+ rateLimits: [],
133
+ workerLabels: {},
134
+ concurrency: [],
135
+ };
136
+ }
137
+ if (workflow.onFailure && typeof workflow.onFailure === 'object') {
138
+ const onFailure = workflow.onFailure;
139
+ onFailureTask = {
140
+ readableId: 'on-failure-task',
141
+ action: onFailureTaskName(workflow),
142
+ timeout: onFailure.executionTimeout || ((_a = workflow.taskDefaults) === null || _a === void 0 ? void 0 : _a.executionTimeout) || '60s',
143
+ scheduleTimeout: onFailure.scheduleTimeout || ((_b = workflow.taskDefaults) === null || _b === void 0 ? void 0 : _b.scheduleTimeout),
144
+ inputs: '{}',
145
+ parents: [],
146
+ retries: onFailure.retries || ((_c = workflow.taskDefaults) === null || _c === void 0 ? void 0 : _c.retries) || 0,
147
+ rateLimits: (0, step_1.mapRateLimit)(onFailure.rateLimits || ((_d = workflow.taskDefaults) === null || _d === void 0 ? void 0 : _d.rateLimits)),
148
+ workerLabels: toPbWorkerLabel(onFailure.desiredWorkerLabels || ((_e = workflow.taskDefaults) === null || _e === void 0 ? void 0 : _e.workerLabels)),
149
+ concurrency: [],
150
+ 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),
151
+ 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),
152
+ };
153
+ }
154
+ let onSuccessTask;
155
+ if (workflow.onSuccess && typeof workflow.onSuccess === 'function') {
156
+ const parents = getLeaves(workflow._tasks);
157
+ onSuccessTask = {
158
+ name: 'on-success-task',
159
+ fn: workflow.onSuccess,
160
+ timeout: '60s',
161
+ parents,
162
+ retries: 0,
163
+ rateLimits: [],
164
+ desiredWorkerLabels: {},
165
+ concurrency: [],
166
+ };
167
+ }
168
+ if (workflow.onSuccess && typeof workflow.onSuccess === 'object') {
169
+ const onSuccess = workflow.onSuccess;
170
+ const parents = getLeaves(workflow._tasks);
171
+ onSuccessTask = {
172
+ name: 'on-success-task',
173
+ fn: onSuccess.fn,
174
+ timeout: onSuccess.executionTimeout || ((_m = workflow.taskDefaults) === null || _m === void 0 ? void 0 : _m.executionTimeout) || '60s',
175
+ scheduleTimeout: onSuccess.scheduleTimeout || ((_o = workflow.taskDefaults) === null || _o === void 0 ? void 0 : _o.scheduleTimeout),
176
+ parents,
177
+ retries: onSuccess.retries || ((_p = workflow.taskDefaults) === null || _p === void 0 ? void 0 : _p.retries) || 0,
178
+ rateLimits: onSuccess.rateLimits || ((_q = workflow.taskDefaults) === null || _q === void 0 ? void 0 : _q.rateLimits),
179
+ desiredWorkerLabels: onSuccess.desiredWorkerLabels || ((_r = workflow.taskDefaults) === null || _r === void 0 ? void 0 : _r.workerLabels),
180
+ concurrency: onSuccess.concurrency || ((_s = workflow.taskDefaults) === null || _s === void 0 ? void 0 : _s.concurrency),
181
+ backoff: onSuccess.backoff || ((_t = workflow.taskDefaults) === null || _t === void 0 ? void 0 : _t.backoff),
182
+ };
183
+ }
184
+ if (onSuccessTask) {
185
+ workflow._tasks.push(onSuccessTask);
186
+ }
187
+ // cron and event triggers
188
+ if (workflow.on) {
189
+ this.logger.warn(`\`on\` for event and cron triggers is deprecated and will be removed soon, use \`onEvents\` and \`onCrons\` instead for ${workflow.name}`);
190
+ }
191
+ const eventTriggers = [
192
+ ...(workflow.onEvents || []),
193
+ ...(((_u = workflow.on) === null || _u === void 0 ? void 0 : _u.event) ? [workflow.on.event] : []),
194
+ ];
195
+ const cronTriggers = [
196
+ ...(workflow.onCrons || []),
197
+ ...(((_v = workflow.on) === null || _v === void 0 ? void 0 : _v.cron) ? [workflow.on.cron] : []),
198
+ ];
199
+ const concurrencyArr = Array.isArray(concurrency) ? concurrency : [];
200
+ const concurrencySolo = !Array.isArray(concurrency) ? concurrency : undefined;
201
+ const registeredWorkflow = this.client._v0.admin.putWorkflowV1({
202
+ name: workflow.name,
203
+ description: workflow.description || '',
204
+ version: workflow.version || '',
205
+ eventTriggers,
206
+ cronTriggers,
207
+ sticky: workflow.sticky,
208
+ concurrencyArr,
209
+ onFailureTask,
210
+ defaultPriority: workflow.defaultPriority,
211
+ tasks: [...workflow._tasks, ...workflow._durableTasks].map((task) => {
212
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p;
213
+ return ({
214
+ readableId: task.name,
215
+ action: `${workflow.name}:${task.name}`,
216
+ timeout: task.executionTimeout ||
217
+ task.timeout ||
218
+ ((_a = workflow.taskDefaults) === null || _a === void 0 ? void 0 : _a.executionTimeout) ||
219
+ '60s',
220
+ scheduleTimeout: task.scheduleTimeout || ((_b = workflow.taskDefaults) === null || _b === void 0 ? void 0 : _b.scheduleTimeout),
221
+ inputs: '{}',
222
+ parents: (_d = (_c = task.parents) === null || _c === void 0 ? void 0 : _c.map((p) => p.name)) !== null && _d !== void 0 ? _d : [],
223
+ userData: '{}',
224
+ retries: task.retries || ((_e = workflow.taskDefaults) === null || _e === void 0 ? void 0 : _e.retries) || 0,
225
+ rateLimits: (0, step_1.mapRateLimit)(task.rateLimits || ((_f = workflow.taskDefaults) === null || _f === void 0 ? void 0 : _f.rateLimits)),
226
+ workerLabels: toPbWorkerLabel(task.desiredWorkerLabels || ((_g = workflow.taskDefaults) === null || _g === void 0 ? void 0 : _g.workerLabels)),
227
+ 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),
228
+ 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),
229
+ conditions: (0, transformer_1.taskConditionsToPb)(task),
230
+ concurrency: task.concurrency
231
+ ? Array.isArray(task.concurrency)
232
+ ? task.concurrency
233
+ : [task.concurrency]
234
+ : ((_p = workflow.taskDefaults) === null || _p === void 0 ? void 0 : _p.concurrency)
235
+ ? Array.isArray(workflow.taskDefaults.concurrency)
236
+ ? workflow.taskDefaults.concurrency
237
+ : [workflow.taskDefaults.concurrency]
238
+ : [],
239
+ });
240
+ }),
241
+ concurrency: concurrencySolo,
242
+ });
243
+ this.registeredWorkflowPromises.push(registeredWorkflow);
244
+ yield registeredWorkflow;
245
+ this.workflow_registry.push(workflow);
246
+ }
247
+ catch (e) {
248
+ throw new hatchet_error_1.default(`Could not register workflow: ${e.message}`);
249
+ }
250
+ this.registerActionsV1(workflow);
251
+ });
252
+ }
253
+ registerWorkflow(initWorkflow) {
254
+ return __awaiter(this, void 0, void 0, function* () {
255
+ var _a, _b, _c;
256
+ const workflow = Object.assign(Object.assign({}, initWorkflow), { id: (this.client.config.namespace + initWorkflow.id).toLowerCase() });
257
+ try {
258
+ if (((_a = workflow.concurrency) === null || _a === void 0 ? void 0 : _a.key) && workflow.concurrency.expression) {
259
+ throw new hatchet_error_1.default('Cannot have both key function and expression in workflow concurrency configuration');
260
+ }
261
+ const concurrency = ((_b = workflow.concurrency) === null || _b === void 0 ? void 0 : _b.name) || ((_c = workflow.concurrency) === null || _c === void 0 ? void 0 : _c.expression)
262
+ ? {
263
+ action: !workflow.concurrency.expression
264
+ ? `${workflow.id}:${workflow.concurrency.name}`
265
+ : undefined,
266
+ maxRuns: workflow.concurrency.maxRuns || 1,
267
+ expression: workflow.concurrency.expression,
268
+ limitStrategy: workflow.concurrency.limitStrategy || workflows_1.ConcurrencyLimitStrategy.CANCEL_IN_PROGRESS,
269
+ }
270
+ : undefined;
271
+ const onFailureJob = workflow.onFailure
272
+ ? {
273
+ name: `${workflow.id}-on-failure`,
274
+ description: workflow.description,
275
+ steps: [
276
+ {
277
+ readableId: workflow.onFailure.name,
278
+ action: `${workflow.id}-on-failure:${workflow.onFailure.name}`,
279
+ timeout: workflow.onFailure.timeout || '60s',
280
+ inputs: '{}',
281
+ parents: [],
282
+ userData: '{}',
283
+ retries: workflow.onFailure.retries || 0,
284
+ rateLimits: (0, step_1.mapRateLimit)(workflow.onFailure.rate_limits),
285
+ workerLabels: {}, // no worker labels for on failure steps
286
+ },
287
+ ],
288
+ }
289
+ : undefined;
290
+ const registeredWorkflow = this.client._v0.admin.putWorkflow({
291
+ name: workflow.id,
292
+ description: workflow.description,
293
+ version: workflow.version || '',
294
+ eventTriggers: workflow.on && workflow.on.event
295
+ ? [this.client.config.namespace + workflow.on.event]
296
+ : [],
297
+ cronTriggers: workflow.on && workflow.on.cron ? [workflow.on.cron] : [],
298
+ scheduledTriggers: [],
299
+ concurrency,
300
+ scheduleTimeout: workflow.scheduleTimeout,
301
+ onFailureJob,
302
+ sticky: workflow.sticky,
303
+ jobs: [
304
+ {
305
+ name: workflow.id,
306
+ description: workflow.description,
307
+ steps: workflow.steps.map((step) => {
308
+ var _a, _b, _c;
309
+ return ({
310
+ readableId: step.name,
311
+ action: `${workflow.id}:${step.name}`,
312
+ timeout: step.timeout || '60s',
313
+ inputs: '{}',
314
+ parents: (_a = step.parents) !== null && _a !== void 0 ? _a : [],
315
+ userData: '{}',
316
+ retries: step.retries || 0,
317
+ rateLimits: (0, step_1.mapRateLimit)(step.rate_limits),
318
+ workerLabels: toPbWorkerLabel(step.worker_labels),
319
+ backoffFactor: (_b = step.backoff) === null || _b === void 0 ? void 0 : _b.factor,
320
+ backoffMaxSeconds: (_c = step.backoff) === null || _c === void 0 ? void 0 : _c.maxSeconds,
321
+ });
322
+ }),
323
+ },
324
+ ],
325
+ });
326
+ this.registeredWorkflowPromises.push(registeredWorkflow);
327
+ yield registeredWorkflow;
328
+ this.workflow_registry.push(workflow);
329
+ }
330
+ catch (e) {
331
+ throw new hatchet_error_1.default(`Could not register workflow: ${e.message}`);
332
+ }
333
+ this.registerActions(workflow);
334
+ });
335
+ }
336
+ registerAction(actionId, action) {
337
+ this.action_registry[actionId.toLowerCase()] = action;
338
+ }
339
+ handleStartStepRun(action) {
340
+ return __awaiter(this, void 0, void 0, function* () {
341
+ const { actionId } = action;
342
+ try {
343
+ // Note: we always use a DurableContext since its a superset of the Context class
344
+ const context = new context_1.DurableContext(action, this.client, this);
345
+ this.contexts[action.stepRunId] = context;
346
+ const step = this.action_registry[actionId];
347
+ if (!step) {
348
+ this.logger.error(`Registered actions: '${Object.keys(this.action_registry).join(', ')}'`);
349
+ this.logger.error(`Could not find step '${actionId}'`);
350
+ return;
351
+ }
352
+ const run = () => __awaiter(this, void 0, void 0, function* () {
353
+ return step(context);
354
+ });
355
+ const success = (result) => __awaiter(this, void 0, void 0, function* () {
356
+ this.logger.info(`Step run ${action.stepRunId} succeeded`);
357
+ try {
358
+ // Send the action event to the dispatcher
359
+ const event = this.getStepActionEvent(action, dispatcher_1.StepActionEventType.STEP_EVENT_TYPE_COMPLETED, false, result || null, action.retryCount);
360
+ yield this.client._v0.dispatcher.sendStepActionEvent(event);
361
+ }
362
+ catch (actionEventError) {
363
+ this.logger.error(`Could not send completed action event: ${actionEventError.message || actionEventError}`);
364
+ // send a failure event
365
+ const failureEvent = this.getStepActionEvent(action, dispatcher_1.StepActionEventType.STEP_EVENT_TYPE_FAILED, false, actionEventError.message, action.retryCount);
366
+ try {
367
+ yield this.client._v0.dispatcher.sendStepActionEvent(failureEvent);
368
+ }
369
+ catch (failureEventError) {
370
+ this.logger.error(`Could not send failed action event: ${failureEventError.message || failureEventError}`);
371
+ }
372
+ this.logger.error(`Could not send action event: ${actionEventError.message || actionEventError}`);
373
+ }
374
+ finally {
375
+ // delete the run from the futures
376
+ delete this.futures[action.stepRunId];
377
+ delete this.contexts[action.stepRunId];
378
+ }
379
+ });
380
+ const failure = (error) => __awaiter(this, void 0, void 0, function* () {
381
+ this.logger.error(`Step run ${action.stepRunId} failed: ${error.message}`);
382
+ if (error.stack) {
383
+ this.logger.error(error.stack);
384
+ }
385
+ const shouldNotRetry = error instanceof task_1.NonRetryableError;
386
+ try {
387
+ // Send the action event to the dispatcher
388
+ const event = this.getStepActionEvent(action, dispatcher_1.StepActionEventType.STEP_EVENT_TYPE_FAILED, shouldNotRetry, {
389
+ message: error === null || error === void 0 ? void 0 : error.message,
390
+ stack: error === null || error === void 0 ? void 0 : error.stack,
391
+ }, action.retryCount);
392
+ yield this.client._v0.dispatcher.sendStepActionEvent(event);
393
+ }
394
+ catch (e) {
395
+ this.logger.error(`Could not send action event: ${e.message}`);
396
+ }
397
+ finally {
398
+ // delete the run from the futures
399
+ delete this.futures[action.stepRunId];
400
+ delete this.contexts[action.stepRunId];
401
+ }
402
+ });
403
+ const future = new hatchet_promise_1.default((() => __awaiter(this, void 0, void 0, function* () {
404
+ let result;
405
+ try {
406
+ result = yield run();
407
+ }
408
+ catch (e) {
409
+ yield failure(e);
410
+ return;
411
+ }
412
+ yield success(result);
413
+ }))());
414
+ this.futures[action.stepRunId] = future;
415
+ // Send the action event to the dispatcher
416
+ const event = this.getStepActionEvent(action, dispatcher_1.StepActionEventType.STEP_EVENT_TYPE_STARTED, false, undefined, action.retryCount);
417
+ this.client._v0.dispatcher.sendStepActionEvent(event).catch((e) => {
418
+ this.logger.error(`Could not send action event: ${e.message}`);
419
+ });
420
+ try {
421
+ yield future.promise;
422
+ }
423
+ catch (e) {
424
+ this.logger.error('Could not wait for step run to finish: ', e);
425
+ }
426
+ }
427
+ catch (e) {
428
+ this.logger.error('Could not send action event (outer): ', e);
429
+ }
430
+ });
431
+ }
432
+ handleStartGroupKeyRun(action) {
433
+ return __awaiter(this, void 0, void 0, function* () {
434
+ const { actionId } = action;
435
+ this.logger.error('Concurrency Key Functions have been deprecated and will be removed in a future release. Use Concurrency Expressions instead.');
436
+ try {
437
+ const context = new context_1.Context(action, this.client, this);
438
+ const key = action.getGroupKeyRunId;
439
+ if (!key) {
440
+ this.logger.error(`No group key run id provided for action ${actionId}`);
441
+ return;
442
+ }
443
+ this.contexts[key] = context;
444
+ this.logger.debug(`Starting group key run ${key}`);
445
+ const step = this.action_registry[actionId];
446
+ if (!step) {
447
+ this.logger.error(`Could not find step '${actionId}'`);
448
+ return;
449
+ }
450
+ const run = () => __awaiter(this, void 0, void 0, function* () {
451
+ return step(context);
452
+ });
453
+ const success = (result) => {
454
+ this.logger.info(`Step run ${action.stepRunId} succeeded`);
455
+ try {
456
+ // Send the action event to the dispatcher
457
+ const event = this.getGroupKeyActionEvent(action, dispatcher_1.GroupKeyActionEventType.GROUP_KEY_EVENT_TYPE_COMPLETED, result);
458
+ this.client._v0.dispatcher.sendGroupKeyActionEvent(event).catch((e) => {
459
+ this.logger.error(`Could not send action event: ${e.message}`);
460
+ });
461
+ }
462
+ catch (e) {
463
+ this.logger.error(`Could not send action event: ${e.message}`);
464
+ }
465
+ finally {
466
+ // delete the run from the futures
467
+ delete this.futures[key];
468
+ delete this.contexts[key];
469
+ }
470
+ };
471
+ const failure = (error) => {
472
+ this.logger.error(`Step run ${key} failed: ${error.message}`);
473
+ try {
474
+ // Send the action event to the dispatcher
475
+ const event = this.getGroupKeyActionEvent(action, dispatcher_1.GroupKeyActionEventType.GROUP_KEY_EVENT_TYPE_FAILED, error);
476
+ this.client._v0.dispatcher.sendGroupKeyActionEvent(event).catch((e) => {
477
+ this.logger.error(`Could not send action event: ${e.message}`);
478
+ });
479
+ }
480
+ catch (e) {
481
+ this.logger.error(`Could not send action event: ${e.message}`);
482
+ }
483
+ finally {
484
+ // delete the run from the futures
485
+ delete this.futures[key];
486
+ delete this.contexts[key];
487
+ }
488
+ };
489
+ const future = new hatchet_promise_1.default(run().then(success).catch(failure));
490
+ this.futures[key] = future;
491
+ // Send the action event to the dispatcher
492
+ const event = this.getGroupKeyActionEvent(action, dispatcher_1.GroupKeyActionEventType.GROUP_KEY_EVENT_TYPE_STARTED);
493
+ this.client._v0.dispatcher.sendGroupKeyActionEvent(event).catch((e) => {
494
+ this.logger.error(`Could not send action event: ${e.message}`);
495
+ });
496
+ yield future.promise;
497
+ }
498
+ catch (e) {
499
+ this.logger.error(`Could not send action event: ${e.message}`);
500
+ }
501
+ });
502
+ }
503
+ getStepActionEvent(action, eventType, shouldNotRetry, payload = '', retryCount = 0) {
504
+ return {
505
+ workerId: this.name,
506
+ jobId: action.jobId,
507
+ jobRunId: action.jobRunId,
508
+ stepId: action.stepId,
509
+ stepRunId: action.stepRunId,
510
+ actionId: action.actionId,
511
+ eventTimestamp: new Date(),
512
+ eventType,
513
+ eventPayload: JSON.stringify(payload),
514
+ shouldNotRetry,
515
+ retryCount,
516
+ };
517
+ }
518
+ getGroupKeyActionEvent(action, eventType, payload = '') {
519
+ if (!action.getGroupKeyRunId) {
520
+ throw new hatchet_error_1.default('No group key run id provided');
521
+ }
522
+ return {
523
+ workerId: this.name,
524
+ workflowRunId: action.workflowRunId,
525
+ getGroupKeyRunId: action.getGroupKeyRunId,
526
+ actionId: action.actionId,
527
+ eventTimestamp: new Date(),
528
+ eventType,
529
+ eventPayload: JSON.stringify(payload),
530
+ };
531
+ }
532
+ handleCancelStepRun(action) {
533
+ return __awaiter(this, void 0, void 0, function* () {
534
+ const { stepRunId } = action;
535
+ try {
536
+ this.logger.info(`Cancelling step run ${action.stepRunId}`);
537
+ const future = this.futures[stepRunId];
538
+ const context = this.contexts[stepRunId];
539
+ if (context && context.abortController) {
540
+ context.abortController.abort('Cancelled by worker');
541
+ }
542
+ if (future) {
543
+ future.promise.catch(() => {
544
+ this.logger.info(`Cancelled step run ${action.stepRunId}`);
545
+ });
546
+ future.cancel('Cancelled by worker');
547
+ yield future.promise;
548
+ }
549
+ }
550
+ catch (e) {
551
+ this.logger.error('Could not cancel step run: ', e);
552
+ }
553
+ finally {
554
+ delete this.futures[stepRunId];
555
+ delete this.contexts[stepRunId];
556
+ }
557
+ });
558
+ }
559
+ stop() {
560
+ return __awaiter(this, void 0, void 0, function* () {
561
+ yield this.exitGracefully(false);
562
+ });
563
+ }
564
+ exitGracefully(handleKill) {
565
+ return __awaiter(this, void 0, void 0, function* () {
566
+ var _a;
567
+ this.killing = true;
568
+ this.logger.info('Starting to exit...');
569
+ try {
570
+ yield ((_a = this.listener) === null || _a === void 0 ? void 0 : _a.unregister());
571
+ }
572
+ catch (e) {
573
+ this.logger.error(`Could not unregister listener: ${e.message}`);
574
+ }
575
+ this.logger.info('Gracefully exiting hatchet worker, running tasks will attempt to finish...');
576
+ // attempt to wait for futures to finish
577
+ yield Promise.all(Object.values(this.futures).map(({ promise }) => promise));
578
+ this.logger.info('Successfully finished pending tasks.');
579
+ if (handleKill) {
580
+ this.logger.info('Exiting hatchet worker...');
581
+ process.exit(0);
582
+ }
583
+ });
584
+ }
585
+ start() {
586
+ return __awaiter(this, void 0, void 0, function* () {
587
+ var _a, e_1, _b, _c;
588
+ // ensure all workflows are registered
589
+ yield Promise.all(this.registeredWorkflowPromises);
590
+ if (Object.keys(this.action_registry).length === 0) {
591
+ return;
592
+ }
593
+ try {
594
+ this.listener = yield this.client._v0.dispatcher.getActionListener({
595
+ workerName: this.name,
596
+ services: ['default'],
597
+ actions: Object.keys(this.action_registry),
598
+ maxRuns: this.maxRuns,
599
+ labels: this.labels,
600
+ });
601
+ this.workerId = this.listener.workerId;
602
+ const generator = this.listener.actions();
603
+ this.logger.info(`Worker ${this.name} listening for actions`);
604
+ try {
605
+ for (var _d = true, generator_1 = __asyncValues(generator), generator_1_1; generator_1_1 = yield generator_1.next(), _a = generator_1_1.done, !_a; _d = true) {
606
+ _c = generator_1_1.value;
607
+ _d = false;
608
+ const action = _c;
609
+ this.logger.info(`Worker ${this.name} received action ${action.actionId}:${action.actionType}`);
610
+ void this.handleAction(action);
611
+ }
612
+ }
613
+ catch (e_1_1) { e_1 = { error: e_1_1 }; }
614
+ finally {
615
+ try {
616
+ if (!_d && !_a && (_b = generator_1.return)) yield _b.call(generator_1);
617
+ }
618
+ finally { if (e_1) throw e_1.error; }
619
+ }
620
+ }
621
+ catch (e) {
622
+ if (this.killing) {
623
+ this.logger.info(`Exiting worker, ignoring error: ${e.message}`);
624
+ return;
625
+ }
626
+ this.logger.error(`Could not run worker: ${e.message}`);
627
+ throw new hatchet_error_1.default(`Could not run worker: ${e.message}`);
628
+ }
629
+ });
630
+ }
631
+ handleAction(action) {
632
+ return __awaiter(this, void 0, void 0, function* () {
633
+ const type = action.actionType
634
+ ? (0, dispatcher_1.actionTypeFromJSON)(action.actionType)
635
+ : dispatcher_1.ActionType.START_STEP_RUN;
636
+ if (type === dispatcher_1.ActionType.START_STEP_RUN) {
637
+ yield this.handleStartStepRun(action);
638
+ }
639
+ else if (type === dispatcher_1.ActionType.CANCEL_STEP_RUN) {
640
+ yield this.handleCancelStepRun(action);
641
+ }
642
+ else if (type === dispatcher_1.ActionType.START_GET_GROUP_KEY) {
643
+ yield this.handleStartGroupKeyRun(action);
644
+ }
645
+ else {
646
+ this.logger.error(`Worker ${this.name} received unknown action type ${type}`);
647
+ }
648
+ });
649
+ }
650
+ upsertLabels(labels) {
651
+ return __awaiter(this, void 0, void 0, function* () {
652
+ this.labels = labels;
653
+ if (!this.workerId) {
654
+ this.logger.warn('Worker not registered.');
655
+ return this.labels;
656
+ }
657
+ this.client._v0.dispatcher.upsertWorkerLabels(this.workerId, labels);
658
+ return this.labels;
659
+ });
660
+ }
661
+ }
662
+ exports.V1Worker = V1Worker;
663
+ function toPbWorkerLabel(in_) {
664
+ if (!in_) {
665
+ return {};
666
+ }
667
+ return Object.entries(in_).reduce((acc, [key, value]) => {
668
+ if (!value) {
669
+ return Object.assign(Object.assign({}, acc), { [key]: {
670
+ strValue: undefined,
671
+ intValue: undefined,
672
+ } });
673
+ }
674
+ if (typeof value === 'string') {
675
+ return Object.assign(Object.assign({}, acc), { [key]: {
676
+ strValue: value,
677
+ intValue: undefined,
678
+ } });
679
+ }
680
+ if (typeof value === 'number') {
681
+ return Object.assign(Object.assign({}, acc), { [key]: {
682
+ strValue: undefined,
683
+ intValue: value,
684
+ } });
685
+ }
686
+ return Object.assign(Object.assign({}, acc), { [key]: {
687
+ strValue: typeof value.value === 'string' ? value.value : undefined,
688
+ intValue: typeof value.value === 'number' ? value.value : undefined,
689
+ required: value.required,
690
+ weight: value.weight,
691
+ comparator: value.comparator,
692
+ } });
693
+ }, {});
694
+ }
695
+ function onFailureTaskName(workflow) {
696
+ return `${workflow.name}:on-failure-task`;
697
+ }
698
+ function getLeaves(tasks) {
699
+ return tasks.filter((task) => isLeafTask(task, tasks));
700
+ }
701
+ function isLeafTask(task, allTasks) {
702
+ return !allTasks.some((t) => { var _a; return (_a = t.parents) === null || _a === void 0 ? void 0 : _a.some((p) => p.name === task.name); });
703
+ }