@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
|
@@ -59,7 +59,7 @@ class Context {
|
|
|
59
59
|
cancel() {
|
|
60
60
|
return __awaiter(this, void 0, void 0, function* () {
|
|
61
61
|
yield this.v1.runs.cancel({
|
|
62
|
-
ids: [this.action.
|
|
62
|
+
ids: [this.action.taskRunExternalId],
|
|
63
63
|
});
|
|
64
64
|
// optimistically abort the run
|
|
65
65
|
this.controller.abort();
|
|
@@ -150,7 +150,7 @@ class Context {
|
|
|
150
150
|
* @returns The name of the task.
|
|
151
151
|
*/
|
|
152
152
|
taskName() {
|
|
153
|
-
return this.action.
|
|
153
|
+
return this.action.taskName;
|
|
154
154
|
}
|
|
155
155
|
/**
|
|
156
156
|
* Gets the ID of the current workflow run.
|
|
@@ -177,8 +177,16 @@ class Context {
|
|
|
177
177
|
* Gets the ID of the current task run.
|
|
178
178
|
* @returns The task run ID.
|
|
179
179
|
*/
|
|
180
|
+
taskRunExternalId() {
|
|
181
|
+
return this.action.taskRunExternalId;
|
|
182
|
+
}
|
|
183
|
+
/**
|
|
184
|
+
* Gets the ID of the current task run.
|
|
185
|
+
* @returns The task run ID.
|
|
186
|
+
* @deprecated use taskRunExternalId() instead
|
|
187
|
+
*/
|
|
180
188
|
taskRunId() {
|
|
181
|
-
return this.
|
|
189
|
+
return this.taskRunExternalId();
|
|
182
190
|
}
|
|
183
191
|
/**
|
|
184
192
|
* Gets the number of times the current task has been retried.
|
|
@@ -194,14 +202,14 @@ class Context {
|
|
|
194
202
|
* @deprecated use ctx.logger.infoger.info, ctx.logger.infoger.debug, ctx.logger.infoger.warn, ctx.logger.infoger.error, ctx.logger.infoger.trace instead
|
|
195
203
|
*/
|
|
196
204
|
log(message, level, extra) {
|
|
197
|
-
const {
|
|
198
|
-
if (!
|
|
205
|
+
const { taskRunExternalId } = this.action;
|
|
206
|
+
if (!taskRunExternalId) {
|
|
199
207
|
// log a warning
|
|
200
208
|
this._logger.warn('cannot log from context without stepRunId');
|
|
201
209
|
return Promise.resolve();
|
|
202
210
|
}
|
|
203
211
|
const logger = this.v1.config.logger('ctx', this.v1.config.log_level);
|
|
204
|
-
const contextExtra = Object.assign({ workflowRunId: this.action.workflowRunId,
|
|
212
|
+
const contextExtra = Object.assign({ workflowRunId: this.action.workflowRunId, taskRunExternalId: this.action.taskRunExternalId, retryCount: this.action.retryCount, workflowName: this.action.jobName }, extra === null || extra === void 0 ? void 0 : extra.extra);
|
|
205
213
|
const promises = [];
|
|
206
214
|
if (!level || level === 'INFO') {
|
|
207
215
|
promises.push(logger.info(message, contextExtra));
|
|
@@ -216,7 +224,7 @@ class Context {
|
|
|
216
224
|
promises.push(logger.error(message, extra === null || extra === void 0 ? void 0 : extra.error, contextExtra));
|
|
217
225
|
}
|
|
218
226
|
// FIXME: this is a hack to get around the fact that the log level is not typed
|
|
219
|
-
promises.push(this.v1.event.putLog(
|
|
227
|
+
promises.push(this.v1.event.putLog(taskRunExternalId, message, level, this.retryCount(), extra === null || extra === void 0 ? void 0 : extra.extra));
|
|
220
228
|
return Promise.all(promises);
|
|
221
229
|
}
|
|
222
230
|
get logger() {
|
|
@@ -249,13 +257,13 @@ class Context {
|
|
|
249
257
|
*/
|
|
250
258
|
refreshTimeout(incrementBy) {
|
|
251
259
|
return __awaiter(this, void 0, void 0, function* () {
|
|
252
|
-
const {
|
|
253
|
-
if (!
|
|
260
|
+
const { taskRunExternalId } = this.action;
|
|
261
|
+
if (!taskRunExternalId) {
|
|
254
262
|
// log a warning
|
|
255
263
|
this._logger.warn('cannot refresh timeout from context without stepRunId');
|
|
256
264
|
return;
|
|
257
265
|
}
|
|
258
|
-
yield this.v1._v0.dispatcher.refreshTimeout(incrementBy,
|
|
266
|
+
yield this.v1._v0.dispatcher.refreshTimeout(incrementBy, taskRunExternalId);
|
|
259
267
|
});
|
|
260
268
|
}
|
|
261
269
|
/**
|
|
@@ -266,7 +274,7 @@ class Context {
|
|
|
266
274
|
releaseSlot() {
|
|
267
275
|
return __awaiter(this, void 0, void 0, function* () {
|
|
268
276
|
yield this.v1._v0.dispatcher.client.releaseSlot({
|
|
269
|
-
|
|
277
|
+
taskRunExternalId: this.action.taskRunExternalId,
|
|
270
278
|
});
|
|
271
279
|
});
|
|
272
280
|
}
|
|
@@ -277,14 +285,14 @@ class Context {
|
|
|
277
285
|
*/
|
|
278
286
|
putStream(data) {
|
|
279
287
|
return __awaiter(this, void 0, void 0, function* () {
|
|
280
|
-
const {
|
|
281
|
-
if (!
|
|
288
|
+
const { taskRunExternalId } = this.action;
|
|
289
|
+
if (!taskRunExternalId) {
|
|
282
290
|
// log a warning
|
|
283
291
|
this._logger.warn('cannot log from context without stepRunId');
|
|
284
292
|
return;
|
|
285
293
|
}
|
|
286
294
|
const index = this._incrementStreamIndex();
|
|
287
|
-
yield this.v1._v0.event.putStream(
|
|
295
|
+
yield this.v1._v0.event.putStream(taskRunExternalId, data, index);
|
|
288
296
|
});
|
|
289
297
|
}
|
|
290
298
|
spawnOptions(workflow, options) {
|
|
@@ -300,8 +308,8 @@ class Context {
|
|
|
300
308
|
if (sticky && !this.worker.hasWorkflow(workflowName)) {
|
|
301
309
|
throw new hatchet_error_1.default(`Cannot run with sticky: workflow ${workflowName} is not registered on the worker`);
|
|
302
310
|
}
|
|
303
|
-
const { workflowRunId,
|
|
304
|
-
const finalOpts = Object.assign(Object.assign({}, options), { parentId: workflowRunId,
|
|
311
|
+
const { workflowRunId, taskRunExternalId } = this.action;
|
|
312
|
+
const finalOpts = Object.assign(Object.assign({}, options), { parentId: workflowRunId, parentTaskRunExternalId: taskRunExternalId, childIndex: this.spawnIndex, childKey: options === null || options === void 0 ? void 0 : options.key, desiredWorkerId: sticky ? this.worker.id() : undefined, _standaloneTaskName: workflow instanceof declaration_1.TaskWorkflowDeclaration ? workflow._standalone_task_name : undefined });
|
|
305
313
|
this.spawnIndex += 1;
|
|
306
314
|
return { workflowName, opts: finalOpts };
|
|
307
315
|
}
|
|
@@ -452,7 +460,7 @@ class Context {
|
|
|
452
460
|
*/
|
|
453
461
|
spawnWorkflows(workflows) {
|
|
454
462
|
return __awaiter(this, void 0, void 0, function* () {
|
|
455
|
-
const { workflowRunId,
|
|
463
|
+
const { workflowRunId, taskRunExternalId } = this.action;
|
|
456
464
|
const workflowRuns = workflows.map(({ workflow, input, options }) => {
|
|
457
465
|
let workflowName;
|
|
458
466
|
if (typeof workflow === 'string') {
|
|
@@ -470,7 +478,7 @@ class Context {
|
|
|
470
478
|
const resp = {
|
|
471
479
|
workflowName: name,
|
|
472
480
|
input,
|
|
473
|
-
options: Object.assign(Object.assign({}, opts), { parentId: workflowRunId,
|
|
481
|
+
options: Object.assign(Object.assign({}, opts), { parentId: workflowRunId, parentTaskRunExternalId: taskRunExternalId, childIndex: this.spawnIndex, desiredWorkerId: sticky ? this.worker.id() : undefined }),
|
|
474
482
|
};
|
|
475
483
|
this.spawnIndex += 1;
|
|
476
484
|
return resp;
|
|
@@ -510,7 +518,7 @@ class Context {
|
|
|
510
518
|
*/
|
|
511
519
|
spawnWorkflow(workflow, input, options) {
|
|
512
520
|
return __awaiter(this, void 0, void 0, function* () {
|
|
513
|
-
const { workflowRunId,
|
|
521
|
+
const { workflowRunId, taskRunExternalId } = this.action;
|
|
514
522
|
let workflowName = '';
|
|
515
523
|
if (typeof workflow === 'string') {
|
|
516
524
|
workflowName = workflow;
|
|
@@ -525,7 +533,7 @@ class Context {
|
|
|
525
533
|
throw new hatchet_error_1.default(`cannot run with sticky: workflow ${name} is not registered on the worker`);
|
|
526
534
|
}
|
|
527
535
|
try {
|
|
528
|
-
const resp = yield this.v1._v0.admin.runWorkflow(name, input, Object.assign({ parentId: workflowRunId,
|
|
536
|
+
const resp = yield this.v1._v0.admin.runWorkflow(name, input, Object.assign({ parentId: workflowRunId, parentTaskRunExternalId: taskRunExternalId, childIndex: this.spawnIndex, desiredWorkerId: sticky ? this.worker.id() : undefined }, opts));
|
|
529
537
|
this.spawnIndex += 1;
|
|
530
538
|
if (workflow instanceof declaration_1.TaskWorkflowDeclaration) {
|
|
531
539
|
resp._standaloneTaskName = workflow._standalone_task_name;
|
|
@@ -572,13 +580,13 @@ class DurableContext extends Context {
|
|
|
572
580
|
// eslint-disable-next-line no-plusplus
|
|
573
581
|
const key = `waitFor-${this.waitKey++}`;
|
|
574
582
|
yield this.v1._v0.durableListener.registerDurableEvent({
|
|
575
|
-
taskId: this.action.
|
|
583
|
+
taskId: this.action.taskRunExternalId,
|
|
576
584
|
signalKey: key,
|
|
577
585
|
sleepConditions: pbConditions.sleepConditions,
|
|
578
586
|
userEventConditions: pbConditions.userEventConditions,
|
|
579
587
|
});
|
|
580
588
|
const listener = this.v1._v0.durableListener.subscribe({
|
|
581
|
-
taskId: this.action.
|
|
589
|
+
taskId: this.action.taskRunExternalId,
|
|
582
590
|
signalKey: key,
|
|
583
591
|
});
|
|
584
592
|
const event = yield listener.get();
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Generic time-aware deprecation helper.
|
|
3
|
+
*
|
|
4
|
+
* Timeline (from a given start date, with configurable windows):
|
|
5
|
+
* 0 to warnDays: WARNING logged once per feature
|
|
6
|
+
* warnDays to errorDays: ERROR logged once per feature
|
|
7
|
+
* after errorDays: throws an error 1-in-5 calls (20% chance)
|
|
8
|
+
*
|
|
9
|
+
* Defaults: warnDays=90, errorDays=undefined (error phase disabled unless set).
|
|
10
|
+
*/
|
|
11
|
+
import { Logger } from '../../../../util/logger';
|
|
12
|
+
export declare class DeprecationError extends Error {
|
|
13
|
+
feature: string;
|
|
14
|
+
constructor(feature: string, message: string);
|
|
15
|
+
}
|
|
16
|
+
export interface DeprecationOpts {
|
|
17
|
+
/** Days after start during which a warning is logged. Defaults to 90. */
|
|
18
|
+
warnDays?: number;
|
|
19
|
+
/** Days after start during which an error is logged.
|
|
20
|
+
* After this window, calls have a 20% chance of throwing.
|
|
21
|
+
* If undefined (default), the error/raise phase is never reached —
|
|
22
|
+
* the notice stays at error-level logging indefinitely. */
|
|
23
|
+
errorDays?: number;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Emit a time-aware deprecation notice.
|
|
27
|
+
*
|
|
28
|
+
* @param feature - A short identifier for deduplication (each feature logs once).
|
|
29
|
+
* @param message - The human-readable deprecation message.
|
|
30
|
+
* @param start - The Date when the deprecation window began.
|
|
31
|
+
* @param logger - A Logger instance for outputting warnings/errors.
|
|
32
|
+
* @param opts - Optional configuration for time windows.
|
|
33
|
+
* @throws DeprecationError after the errorDays window (~20% chance).
|
|
34
|
+
*/
|
|
35
|
+
/**
|
|
36
|
+
* Parses a semver string like "v0.78.23" into [major, minor, patch].
|
|
37
|
+
* Returns [0, 0, 0] if parsing fails.
|
|
38
|
+
*/
|
|
39
|
+
export declare function parseSemver(v: string): [number, number, number];
|
|
40
|
+
/**
|
|
41
|
+
* Returns true if semver string a is strictly less than b.
|
|
42
|
+
*/
|
|
43
|
+
export declare function semverLessThan(a: string, b: string): boolean;
|
|
44
|
+
export declare function emitDeprecationNotice(feature: string, message: string, start: Date, logger: Logger, opts?: DeprecationOpts): void;
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Generic time-aware deprecation helper.
|
|
4
|
+
*
|
|
5
|
+
* Timeline (from a given start date, with configurable windows):
|
|
6
|
+
* 0 to warnDays: WARNING logged once per feature
|
|
7
|
+
* warnDays to errorDays: ERROR logged once per feature
|
|
8
|
+
* after errorDays: throws an error 1-in-5 calls (20% chance)
|
|
9
|
+
*
|
|
10
|
+
* Defaults: warnDays=90, errorDays=undefined (error phase disabled unless set).
|
|
11
|
+
*/
|
|
12
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
13
|
+
exports.DeprecationError = void 0;
|
|
14
|
+
exports.parseSemver = parseSemver;
|
|
15
|
+
exports.semverLessThan = semverLessThan;
|
|
16
|
+
exports.emitDeprecationNotice = emitDeprecationNotice;
|
|
17
|
+
const DEFAULT_WARN_DAYS = 90;
|
|
18
|
+
const MS_PER_DAY = 24 * 60 * 60 * 1000;
|
|
19
|
+
/** Tracks which features have already been logged (keyed by feature name). */
|
|
20
|
+
const alreadyLogged = new Set();
|
|
21
|
+
class DeprecationError extends Error {
|
|
22
|
+
constructor(feature, message) {
|
|
23
|
+
super(`${feature}: ${message}`);
|
|
24
|
+
this.name = 'DeprecationError';
|
|
25
|
+
this.feature = feature;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
exports.DeprecationError = DeprecationError;
|
|
29
|
+
/**
|
|
30
|
+
* Emit a time-aware deprecation notice.
|
|
31
|
+
*
|
|
32
|
+
* @param feature - A short identifier for deduplication (each feature logs once).
|
|
33
|
+
* @param message - The human-readable deprecation message.
|
|
34
|
+
* @param start - The Date when the deprecation window began.
|
|
35
|
+
* @param logger - A Logger instance for outputting warnings/errors.
|
|
36
|
+
* @param opts - Optional configuration for time windows.
|
|
37
|
+
* @throws DeprecationError after the errorDays window (~20% chance).
|
|
38
|
+
*/
|
|
39
|
+
/**
|
|
40
|
+
* Parses a semver string like "v0.78.23" into [major, minor, patch].
|
|
41
|
+
* Returns [0, 0, 0] if parsing fails.
|
|
42
|
+
*/
|
|
43
|
+
function parseSemver(v) {
|
|
44
|
+
let s = v.startsWith('v') ? v.slice(1) : v;
|
|
45
|
+
const dashIdx = s.indexOf('-');
|
|
46
|
+
if (dashIdx !== -1)
|
|
47
|
+
s = s.slice(0, dashIdx);
|
|
48
|
+
const parts = s.split('.');
|
|
49
|
+
if (parts.length !== 3)
|
|
50
|
+
return [0, 0, 0];
|
|
51
|
+
return [parseInt(parts[0], 10) || 0, parseInt(parts[1], 10) || 0, parseInt(parts[2], 10) || 0];
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Returns true if semver string a is strictly less than b.
|
|
55
|
+
*/
|
|
56
|
+
function semverLessThan(a, b) {
|
|
57
|
+
const [aMaj, aMin, aPat] = parseSemver(a);
|
|
58
|
+
const [bMaj, bMin, bPat] = parseSemver(b);
|
|
59
|
+
if (aMaj !== bMaj)
|
|
60
|
+
return aMaj < bMaj;
|
|
61
|
+
if (aMin !== bMin)
|
|
62
|
+
return aMin < bMin;
|
|
63
|
+
return aPat < bPat;
|
|
64
|
+
}
|
|
65
|
+
function emitDeprecationNotice(feature, message, start, logger, opts) {
|
|
66
|
+
var _a;
|
|
67
|
+
const warnMs = ((_a = opts === null || opts === void 0 ? void 0 : opts.warnDays) !== null && _a !== void 0 ? _a : DEFAULT_WARN_DAYS) * MS_PER_DAY;
|
|
68
|
+
const errorDays = opts === null || opts === void 0 ? void 0 : opts.errorDays;
|
|
69
|
+
const errorMs = errorDays != null ? errorDays * MS_PER_DAY : undefined;
|
|
70
|
+
const elapsed = Date.now() - start.getTime();
|
|
71
|
+
if (elapsed < warnMs) {
|
|
72
|
+
// Phase 1: warning
|
|
73
|
+
if (!alreadyLogged.has(feature)) {
|
|
74
|
+
logger.warn(message);
|
|
75
|
+
alreadyLogged.add(feature);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
else if (errorMs === undefined || elapsed < errorMs) {
|
|
79
|
+
// Phase 2: error-level log (indefinite when errorDays is not set)
|
|
80
|
+
if (!alreadyLogged.has(feature)) {
|
|
81
|
+
logger.error(`${message} This fallback will be removed soon. Upgrade immediately.`);
|
|
82
|
+
alreadyLogged.add(feature);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
else {
|
|
86
|
+
// Phase 3: throw 1-in-5 times
|
|
87
|
+
if (!alreadyLogged.has(feature)) {
|
|
88
|
+
logger.error(`${message} This fallback is no longer supported and will fail intermittently.`);
|
|
89
|
+
alreadyLogged.add(feature);
|
|
90
|
+
}
|
|
91
|
+
if (Math.random() < 0.2) {
|
|
92
|
+
throw new DeprecationError(feature, message);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export { isLegacyEngine, LegacyDualWorker } from './legacy-worker';
|
|
2
|
+
export { LegacyV1Worker } from './legacy-v1-worker';
|
|
3
|
+
export { legacyGetActionListener } from './legacy-registration';
|
|
4
|
+
export { emitDeprecationNotice, DeprecationError, parseSemver, semverLessThan, } from './deprecation';
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.semverLessThan = exports.parseSemver = exports.DeprecationError = exports.emitDeprecationNotice = exports.legacyGetActionListener = exports.LegacyV1Worker = exports.LegacyDualWorker = exports.isLegacyEngine = void 0;
|
|
4
|
+
var legacy_worker_1 = require("./legacy-worker");
|
|
5
|
+
Object.defineProperty(exports, "isLegacyEngine", { enumerable: true, get: function () { return legacy_worker_1.isLegacyEngine; } });
|
|
6
|
+
Object.defineProperty(exports, "LegacyDualWorker", { enumerable: true, get: function () { return legacy_worker_1.LegacyDualWorker; } });
|
|
7
|
+
var legacy_v1_worker_1 = require("./legacy-v1-worker");
|
|
8
|
+
Object.defineProperty(exports, "LegacyV1Worker", { enumerable: true, get: function () { return legacy_v1_worker_1.LegacyV1Worker; } });
|
|
9
|
+
var legacy_registration_1 = require("./legacy-registration");
|
|
10
|
+
Object.defineProperty(exports, "legacyGetActionListener", { enumerable: true, get: function () { return legacy_registration_1.legacyGetActionListener; } });
|
|
11
|
+
var deprecation_1 = require("./deprecation");
|
|
12
|
+
Object.defineProperty(exports, "emitDeprecationNotice", { enumerable: true, get: function () { return deprecation_1.emitDeprecationNotice; } });
|
|
13
|
+
Object.defineProperty(exports, "DeprecationError", { enumerable: true, get: function () { return deprecation_1.DeprecationError; } });
|
|
14
|
+
Object.defineProperty(exports, "parseSemver", { enumerable: true, get: function () { return deprecation_1.parseSemver; } });
|
|
15
|
+
Object.defineProperty(exports, "semverLessThan", { enumerable: true, get: function () { return deprecation_1.semverLessThan; } });
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Legacy worker registration using the deprecated `slots` proto field
|
|
3
|
+
* instead of `slotConfig`. For backward compatibility with engines
|
|
4
|
+
* that do not support multiple slot types.
|
|
5
|
+
*/
|
|
6
|
+
import { DispatcherClient, WorkerLabels } from '../../../../clients/dispatcher/dispatcher-client';
|
|
7
|
+
import { ActionListener } from '../../../../clients/dispatcher/action-listener';
|
|
8
|
+
export interface LegacyRegistrationOptions {
|
|
9
|
+
workerName: string;
|
|
10
|
+
services: string[];
|
|
11
|
+
actions: string[];
|
|
12
|
+
slots: number;
|
|
13
|
+
labels: WorkerLabels;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Registers a worker using the legacy `slots` proto field instead of `slotConfig`.
|
|
17
|
+
*/
|
|
18
|
+
export declare function legacyGetActionListener(dispatcher: DispatcherClient, options: LegacyRegistrationOptions): Promise<ActionListener>;
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Legacy worker registration using the deprecated `slots` proto field
|
|
4
|
+
* instead of `slotConfig`. For backward compatibility with engines
|
|
5
|
+
* that do not support multiple slot types.
|
|
6
|
+
*/
|
|
7
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
8
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
9
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
10
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
11
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
12
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
13
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
14
|
+
});
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
exports.legacyGetActionListener = legacyGetActionListener;
|
|
18
|
+
const dispatcher_client_1 = require("../../../../clients/dispatcher/dispatcher-client");
|
|
19
|
+
const action_listener_1 = require("../../../../clients/dispatcher/action-listener");
|
|
20
|
+
/**
|
|
21
|
+
* Registers a worker using the legacy `slots` proto field instead of `slotConfig`.
|
|
22
|
+
*/
|
|
23
|
+
function legacyGetActionListener(dispatcher, options) {
|
|
24
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
25
|
+
const registration = yield dispatcher.client.register({
|
|
26
|
+
workerName: options.workerName,
|
|
27
|
+
services: options.services,
|
|
28
|
+
actions: options.actions,
|
|
29
|
+
slots: options.slots,
|
|
30
|
+
labels: options.labels ? (0, dispatcher_client_1.mapLabels)(options.labels) : undefined,
|
|
31
|
+
runtimeInfo: dispatcher.getRuntimeInfo(),
|
|
32
|
+
});
|
|
33
|
+
return new action_listener_1.ActionListener(dispatcher, registration.workerId);
|
|
34
|
+
});
|
|
35
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Legacy V1Worker subclass that registers with the old `slots` proto field
|
|
3
|
+
* instead of `slotConfig`. Used when connected to pre-slot-config engines.
|
|
4
|
+
*/
|
|
5
|
+
import { ActionListener } from '../../../../clients/dispatcher/action-listener';
|
|
6
|
+
import { HatchetClient } from '../../..';
|
|
7
|
+
import { V1Worker } from '../worker-internal';
|
|
8
|
+
export declare class LegacyV1Worker extends V1Worker {
|
|
9
|
+
private _legacySlotCount;
|
|
10
|
+
constructor(client: HatchetClient, options: ConstructorParameters<typeof V1Worker>[1], legacySlots: number);
|
|
11
|
+
/**
|
|
12
|
+
* Override registration to use the legacy `slots` proto field.
|
|
13
|
+
*/
|
|
14
|
+
protected createListener(): Promise<ActionListener>;
|
|
15
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Legacy V1Worker subclass that registers with the old `slots` proto field
|
|
4
|
+
* instead of `slotConfig`. Used when connected to pre-slot-config engines.
|
|
5
|
+
*/
|
|
6
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
7
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
8
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
9
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
10
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
11
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
12
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
13
|
+
});
|
|
14
|
+
};
|
|
15
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
16
|
+
exports.LegacyV1Worker = void 0;
|
|
17
|
+
const worker_internal_1 = require("../worker-internal");
|
|
18
|
+
const legacy_registration_1 = require("./legacy-registration");
|
|
19
|
+
class LegacyV1Worker extends worker_internal_1.V1Worker {
|
|
20
|
+
constructor(client, options, legacySlots) {
|
|
21
|
+
super(client, options);
|
|
22
|
+
this._legacySlotCount = legacySlots;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Override registration to use the legacy `slots` proto field.
|
|
26
|
+
*/
|
|
27
|
+
createListener() {
|
|
28
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
29
|
+
return (0, legacy_registration_1.legacyGetActionListener)(this.client._v0.dispatcher, {
|
|
30
|
+
workerName: this.name,
|
|
31
|
+
services: ['default'],
|
|
32
|
+
actions: Object.keys(this.action_registry),
|
|
33
|
+
slots: this._legacySlotCount,
|
|
34
|
+
labels: this.labels,
|
|
35
|
+
});
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
exports.LegacyV1Worker = LegacyV1Worker;
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Legacy dual-worker implementation for pre-slot-config engines.
|
|
3
|
+
*
|
|
4
|
+
* When connected to an older Hatchet engine that does not support multiple slot types,
|
|
5
|
+
* this module provides the old worker start flow which creates separate durable and
|
|
6
|
+
* non-durable workers, each registered with the legacy `slots` proto field.
|
|
7
|
+
*/
|
|
8
|
+
import { HatchetClient } from '../../..';
|
|
9
|
+
import { CreateWorkerOpts } from '../worker';
|
|
10
|
+
import { LegacyV1Worker } from './legacy-v1-worker';
|
|
11
|
+
/**
|
|
12
|
+
* Checks if the connected engine is legacy by comparing its semantic version
|
|
13
|
+
* against the minimum required version for slot_config support.
|
|
14
|
+
* Returns true if the engine is legacy, false otherwise.
|
|
15
|
+
* Emits a time-aware deprecation notice when a legacy engine is detected.
|
|
16
|
+
*/
|
|
17
|
+
export declare function isLegacyEngine(v1: HatchetClient): Promise<boolean>;
|
|
18
|
+
/**
|
|
19
|
+
* LegacyDualWorker manages two V1Worker instances (nonDurable + durable)
|
|
20
|
+
* for engines that don't support slot_config.
|
|
21
|
+
* Uses the legacy `slots` proto field (maxRuns) instead of `slotConfig`.
|
|
22
|
+
*/
|
|
23
|
+
export declare class LegacyDualWorker {
|
|
24
|
+
private nonDurable;
|
|
25
|
+
private durable;
|
|
26
|
+
private name;
|
|
27
|
+
constructor(name: string, nonDurable: LegacyV1Worker, durable?: LegacyV1Worker);
|
|
28
|
+
/**
|
|
29
|
+
* Creates a legacy dual-worker setup from the given options.
|
|
30
|
+
* Workers are created with legacy registration (old `slots` proto field).
|
|
31
|
+
*/
|
|
32
|
+
static create(v1: HatchetClient, name: string, options: CreateWorkerOpts): Promise<LegacyDualWorker>;
|
|
33
|
+
/**
|
|
34
|
+
* Starts both workers using Promise.all.
|
|
35
|
+
*/
|
|
36
|
+
start(): Promise<void>;
|
|
37
|
+
/**
|
|
38
|
+
* Stops both workers.
|
|
39
|
+
*/
|
|
40
|
+
stop(): Promise<void>;
|
|
41
|
+
}
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Legacy dual-worker implementation for pre-slot-config engines.
|
|
4
|
+
*
|
|
5
|
+
* When connected to an older Hatchet engine that does not support multiple slot types,
|
|
6
|
+
* this module provides the old worker start flow which creates separate durable and
|
|
7
|
+
* non-durable workers, each registered with the legacy `slots` proto field.
|
|
8
|
+
*/
|
|
9
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
10
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
11
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
12
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
13
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
14
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
15
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
16
|
+
});
|
|
17
|
+
};
|
|
18
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
19
|
+
exports.LegacyDualWorker = void 0;
|
|
20
|
+
exports.isLegacyEngine = isLegacyEngine;
|
|
21
|
+
const nice_grpc_1 = require("nice-grpc");
|
|
22
|
+
const declaration_1 = require("../../../declaration");
|
|
23
|
+
const legacy_v1_worker_1 = require("./legacy-v1-worker");
|
|
24
|
+
const deprecation_1 = require("./deprecation");
|
|
25
|
+
const DEFAULT_DEFAULT_SLOTS = 100;
|
|
26
|
+
const DEFAULT_DURABLE_SLOTS = 1000;
|
|
27
|
+
/** The date when slot_config support was released. */
|
|
28
|
+
const LEGACY_ENGINE_START = new Date('2026-02-12T00:00:00Z');
|
|
29
|
+
/** Minimum engine version that supports multiple slot types. */
|
|
30
|
+
const MIN_SLOT_CONFIG_VERSION = 'v0.78.23';
|
|
31
|
+
const LEGACY_ENGINE_MESSAGE = 'Connected to an older Hatchet engine that does not support multiple slot types. ' +
|
|
32
|
+
'Falling back to legacy worker registration. ' +
|
|
33
|
+
'Please upgrade your Hatchet engine to the latest version.';
|
|
34
|
+
/**
|
|
35
|
+
* Checks if the connected engine is legacy by comparing its semantic version
|
|
36
|
+
* against the minimum required version for slot_config support.
|
|
37
|
+
* Returns true if the engine is legacy, false otherwise.
|
|
38
|
+
* Emits a time-aware deprecation notice when a legacy engine is detected.
|
|
39
|
+
*/
|
|
40
|
+
function isLegacyEngine(v1) {
|
|
41
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
42
|
+
try {
|
|
43
|
+
const version = yield v1._v0.dispatcher.getVersion();
|
|
44
|
+
// If the version is empty or older than the minimum, treat as legacy
|
|
45
|
+
if (!version || (0, deprecation_1.semverLessThan)(version, MIN_SLOT_CONFIG_VERSION)) {
|
|
46
|
+
const logger = v1._v0.config.logger('Worker', v1._v0.config.log_level);
|
|
47
|
+
(0, deprecation_1.emitDeprecationNotice)('legacy-engine', LEGACY_ENGINE_MESSAGE, LEGACY_ENGINE_START, logger, {
|
|
48
|
+
errorDays: 180,
|
|
49
|
+
});
|
|
50
|
+
return true;
|
|
51
|
+
}
|
|
52
|
+
return false;
|
|
53
|
+
}
|
|
54
|
+
catch (e) {
|
|
55
|
+
if ((e === null || e === void 0 ? void 0 : e.code) === nice_grpc_1.Status.UNIMPLEMENTED) {
|
|
56
|
+
const logger = v1._v0.config.logger('Worker', v1._v0.config.log_level);
|
|
57
|
+
(0, deprecation_1.emitDeprecationNotice)('legacy-engine', LEGACY_ENGINE_MESSAGE, LEGACY_ENGINE_START, logger, {
|
|
58
|
+
errorDays: 180,
|
|
59
|
+
});
|
|
60
|
+
return true;
|
|
61
|
+
}
|
|
62
|
+
// For other errors, assume new engine and let registration fail naturally
|
|
63
|
+
return false;
|
|
64
|
+
}
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* LegacyDualWorker manages two V1Worker instances (nonDurable + durable)
|
|
69
|
+
* for engines that don't support slot_config.
|
|
70
|
+
* Uses the legacy `slots` proto field (maxRuns) instead of `slotConfig`.
|
|
71
|
+
*/
|
|
72
|
+
class LegacyDualWorker {
|
|
73
|
+
constructor(name, nonDurable, durable) {
|
|
74
|
+
this.name = name;
|
|
75
|
+
this.nonDurable = nonDurable;
|
|
76
|
+
this.durable = durable;
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Creates a legacy dual-worker setup from the given options.
|
|
80
|
+
* Workers are created with legacy registration (old `slots` proto field).
|
|
81
|
+
*/
|
|
82
|
+
static create(v1, name, options) {
|
|
83
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
84
|
+
const defaultSlots = options.slots || options.maxRuns || DEFAULT_DEFAULT_SLOTS;
|
|
85
|
+
const durableSlots = options.durableSlots || DEFAULT_DURABLE_SLOTS;
|
|
86
|
+
// Create the non-durable worker with legacy registration
|
|
87
|
+
const nonDurable = new legacy_v1_worker_1.LegacyV1Worker(v1, { name, labels: options.labels, handleKill: options.handleKill }, defaultSlots);
|
|
88
|
+
// Check if any workflows have durable tasks
|
|
89
|
+
let hasDurableTasks = false;
|
|
90
|
+
for (const wf of options.workflows || []) {
|
|
91
|
+
if (wf instanceof declaration_1.BaseWorkflowDeclaration) {
|
|
92
|
+
if (wf.definition._durableTasks.length > 0) {
|
|
93
|
+
hasDurableTasks = true;
|
|
94
|
+
break;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
let durableWorker;
|
|
99
|
+
if (hasDurableTasks) {
|
|
100
|
+
// Create the durable worker with legacy registration
|
|
101
|
+
durableWorker = new legacy_v1_worker_1.LegacyV1Worker(v1, { name: `${name}-durable`, labels: options.labels, handleKill: options.handleKill }, durableSlots);
|
|
102
|
+
}
|
|
103
|
+
const legacyWorker = new LegacyDualWorker(name, nonDurable, durableWorker);
|
|
104
|
+
// Register workflows on appropriate workers
|
|
105
|
+
for (const wf of options.workflows || []) {
|
|
106
|
+
if (wf instanceof declaration_1.BaseWorkflowDeclaration) {
|
|
107
|
+
if (wf.definition._durableTasks.length > 0 && durableWorker) {
|
|
108
|
+
yield durableWorker.registerWorkflowV1(wf);
|
|
109
|
+
durableWorker.registerDurableActionsV1(wf.definition);
|
|
110
|
+
}
|
|
111
|
+
else {
|
|
112
|
+
yield nonDurable.registerWorkflowV1(wf);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
else {
|
|
116
|
+
// fallback to v0 client for backwards compatibility
|
|
117
|
+
yield nonDurable.registerWorkflow(wf);
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
return legacyWorker;
|
|
121
|
+
});
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* Starts both workers using Promise.all.
|
|
125
|
+
*/
|
|
126
|
+
start() {
|
|
127
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
128
|
+
const promises = [this.nonDurable.start()];
|
|
129
|
+
if (this.durable) {
|
|
130
|
+
promises.push(this.durable.start());
|
|
131
|
+
}
|
|
132
|
+
yield Promise.all(promises);
|
|
133
|
+
});
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* Stops both workers.
|
|
137
|
+
*/
|
|
138
|
+
stop() {
|
|
139
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
140
|
+
const promises = [this.nonDurable.stop()];
|
|
141
|
+
if (this.durable) {
|
|
142
|
+
promises.push(this.durable.stop());
|
|
143
|
+
}
|
|
144
|
+
yield Promise.all(promises);
|
|
145
|
+
});
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
exports.LegacyDualWorker = LegacyDualWorker;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { Workflow as V0Workflow } from '../../../workflow';
|
|
2
|
+
import { BaseWorkflowDeclaration } from '../../declaration';
|
|
3
|
+
import { SlotConfig } from '../../slot-types';
|
|
4
|
+
export interface WorkerSlotOptions {
|
|
5
|
+
/** (optional) Maximum number of concurrent runs on this worker, defaults to 100 */
|
|
6
|
+
slots?: number;
|
|
7
|
+
/** (optional) Maximum number of concurrent durable tasks, defaults to 1,000 */
|
|
8
|
+
durableSlots?: number;
|
|
9
|
+
/** (optional) Array of workflows to register */
|
|
10
|
+
workflows?: BaseWorkflowDeclaration<any, any>[] | V0Workflow[];
|
|
11
|
+
/** @deprecated Use slots instead */
|
|
12
|
+
maxRuns?: number;
|
|
13
|
+
}
|
|
14
|
+
export declare function resolveWorkerOptions<T extends WorkerSlotOptions>(options: T): T & {
|
|
15
|
+
slots?: number;
|
|
16
|
+
durableSlots?: number;
|
|
17
|
+
slotConfig: SlotConfig;
|
|
18
|
+
};
|
|
19
|
+
export declare const testingExports: {
|
|
20
|
+
resolveWorkerOptions: typeof resolveWorkerOptions;
|
|
21
|
+
};
|