@hatchet-dev/typescript-sdk 1.15.2 → 1.17.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (202) hide show
  1. package/README.md +14 -2
  2. package/clients/admin/admin-client.d.ts +2 -2
  3. package/clients/admin/admin-client.js +8 -9
  4. package/clients/dispatcher/action-listener.d.ts +3 -6
  5. package/clients/dispatcher/action-listener.js +54 -23
  6. package/clients/dispatcher/dispatcher-client.js +5 -8
  7. package/clients/dispatcher/heartbeat/heartbeat-worker.js +7 -4
  8. package/clients/event/event-client.d.ts +2 -2
  9. package/clients/event/event-client.js +5 -11
  10. package/clients/hatchet-client/hatchet-logger.js +8 -17
  11. package/clients/listeners/durable-listener/durable-listener-client.d.ts +115 -15
  12. package/clients/listeners/durable-listener/durable-listener-client.js +769 -19
  13. package/clients/listeners/durable-listener/pooled-durable-listener-client.js +11 -22
  14. package/clients/listeners/run-listener/child-listener-client.d.ts +1 -1
  15. package/clients/listeners/run-listener/child-listener-client.js +34 -30
  16. package/clients/listeners/run-listener/pooled-child-listener-client.js +9 -19
  17. package/clients/rest/generated/Api.d.ts +25 -1
  18. package/clients/rest/generated/Api.js +20 -0
  19. package/clients/rest/generated/data-contracts.d.ts +60 -1
  20. package/clients/rest/generated/data-contracts.js +9 -1
  21. package/legacy/examples/affinity-workers.js +2 -3
  22. package/legacy/examples/byo-logger.js +0 -2
  23. package/legacy/examples/concurrency/cancel-in-progress/concurrency-worker.js +4 -2
  24. package/legacy/examples/concurrency/group-round-robin/concurrency-event.js +0 -1
  25. package/legacy/examples/concurrency/group-round-robin/concurrency-worker-expression.js +4 -2
  26. package/legacy/examples/concurrency/group-round-robin/concurrency-worker-key-fn.js +4 -2
  27. package/legacy/examples/example-event.js +0 -3
  28. package/legacy/examples/logger.js +0 -1
  29. package/legacy/examples/sticky-worker-with-check.js +0 -1
  30. package/legacy/examples/sticky-worker.js +0 -1
  31. package/legacy/legacy-client.js +2 -2
  32. package/legacy/legacy-transformer.js +2 -4
  33. package/legacy/step.d.ts +16 -16
  34. package/legacy/step.js +8 -17
  35. package/legacy/workflow.d.ts +81 -81
  36. package/package.json +20 -29
  37. package/protoc/dispatcher/dispatcher.d.ts +20 -0
  38. package/protoc/dispatcher/dispatcher.js +136 -2
  39. package/protoc/v1/dispatcher.d.ts +168 -0
  40. package/protoc/v1/dispatcher.js +1920 -1
  41. package/protoc/v1/shared/trigger.d.ts +89 -0
  42. package/protoc/v1/shared/trigger.js +493 -0
  43. package/protoc/v1/workflows.d.ts +34 -34
  44. package/protoc/v1/workflows.js +252 -200
  45. package/protoc/workflows/workflows.d.ts +2 -75
  46. package/protoc/workflows/workflows.js +16 -491
  47. package/util/abort-error.d.ts +15 -1
  48. package/util/abort-error.js +30 -5
  49. package/util/config-loader/config-loader.js +4 -3
  50. package/util/config-loader/token.js +9 -2
  51. package/util/errors/eviction-not-supported-error.d.ts +5 -0
  52. package/util/errors/eviction-not-supported-error.js +18 -0
  53. package/util/errors/hatchet-error.d.ts +9 -1
  54. package/util/errors/hatchet-error.js +23 -2
  55. package/util/errors/non-determinism-error.d.ts +7 -0
  56. package/util/errors/non-determinism-error.js +21 -0
  57. package/util/errors/task-run-terminated-error.d.ts +6 -0
  58. package/util/errors/task-run-terminated-error.js +15 -0
  59. package/util/grpc-error.d.ts +9 -0
  60. package/util/grpc-error.js +25 -0
  61. package/util/hatchet-promise/hatchet-promise.d.ts +6 -1
  62. package/util/hatchet-promise/hatchet-promise.js +16 -2
  63. package/util/logger/logger.js +0 -1
  64. package/util/parse.d.ts +1 -1
  65. package/util/parse.js +4 -2
  66. package/util/retrier.js +2 -3
  67. package/util/sleep.d.ts +3 -2
  68. package/util/sleep.js +6 -4
  69. package/util/workflow-run-ref.js +5 -3
  70. package/v1/client/admin.d.ts +2 -2
  71. package/v1/client/admin.js +2 -6
  72. package/v1/client/client.d.ts +7 -11
  73. package/v1/client/client.interface.d.ts +5 -8
  74. package/v1/client/client.js +34 -40
  75. package/v1/client/duration.d.ts +11 -1
  76. package/v1/client/duration.js +44 -0
  77. package/v1/client/features/cel.js +1 -1
  78. package/v1/client/features/crons.js +2 -2
  79. package/v1/client/features/index.d.ts +5 -0
  80. package/v1/client/features/index.js +5 -0
  81. package/v1/client/features/logs.d.ts +37 -0
  82. package/v1/client/features/logs.js +46 -0
  83. package/v1/client/features/runs.d.ts +16 -3
  84. package/v1/client/features/runs.js +38 -4
  85. package/v1/client/features/schedules.js +4 -4
  86. package/v1/client/features/webhooks.js +4 -2
  87. package/v1/client/features/workflows.js +1 -1
  88. package/v1/client/worker/context.d.ts +101 -6
  89. package/v1/client/worker/context.js +257 -44
  90. package/v1/client/worker/deprecated/deprecation.js +8 -4
  91. package/v1/client/worker/deprecated/index.d.ts +1 -1
  92. package/v1/client/worker/deprecated/index.js +2 -1
  93. package/v1/client/worker/deprecated/legacy-worker.d.ts +5 -0
  94. package/v1/client/worker/deprecated/legacy-worker.js +33 -24
  95. package/v1/client/worker/deprecated/pre-eviction.d.ts +12 -0
  96. package/v1/client/worker/deprecated/pre-eviction.js +37 -0
  97. package/v1/client/worker/engine-version.d.ts +5 -0
  98. package/v1/client/worker/engine-version.js +14 -0
  99. package/v1/client/worker/eviction/eviction-cache.d.ts +33 -0
  100. package/v1/client/worker/eviction/eviction-cache.js +139 -0
  101. package/v1/client/worker/eviction/eviction-manager.d.ts +42 -0
  102. package/v1/client/worker/eviction/eviction-manager.js +132 -0
  103. package/v1/client/worker/eviction/eviction-policy.d.ts +19 -0
  104. package/v1/client/worker/eviction/eviction-policy.js +8 -0
  105. package/v1/client/worker/eviction/index.d.ts +3 -0
  106. package/v1/client/worker/eviction/index.js +11 -0
  107. package/v1/client/worker/health-server.js +3 -3
  108. package/v1/client/worker/slot-utils.js +0 -3
  109. package/v1/client/worker/worker-internal.d.ts +23 -4
  110. package/v1/client/worker/worker-internal.js +216 -148
  111. package/v1/client/worker/worker.d.ts +1 -0
  112. package/v1/client/worker/worker.js +34 -0
  113. package/v1/conditions/base.js +0 -1
  114. package/v1/conditions/index.js +2 -4
  115. package/v1/conditions/sleep-condition.js +2 -1
  116. package/v1/conditions/transformer.js +2 -1
  117. package/v1/declaration.d.ts +6 -4
  118. package/v1/declaration.js +20 -7
  119. package/v1/examples/__e2e__/harness.d.ts +5 -0
  120. package/v1/examples/__e2e__/harness.js +17 -3
  121. package/v1/examples/affinity/affinity-workers.js +0 -1
  122. package/v1/examples/bulk_operations/workflow.js +0 -1
  123. package/v1/examples/cancellation/run.js +0 -1
  124. package/v1/examples/cancellations/run.js +0 -1
  125. package/v1/examples/child_workflows/run.js +0 -2
  126. package/v1/examples/child_workflows/workflow.js +0 -1
  127. package/v1/examples/concurrency-rr/load.js +0 -1
  128. package/v1/examples/concurrency-rr/run.js +0 -3
  129. package/v1/examples/concurrency_limit_rr/load.js +0 -1
  130. package/v1/examples/concurrency_limit_rr/run.js +0 -3
  131. package/v1/examples/concurrency_workflow_level/workflow.d.ts +1 -1
  132. package/v1/examples/concurrency_workflow_level/workflow.js +1 -1
  133. package/v1/examples/conditions/event.js +0 -1
  134. package/v1/examples/conditions/run.js +0 -1
  135. package/v1/examples/dag/run.js +0 -1
  136. package/v1/examples/dag_match_condition/event.js +0 -1
  137. package/v1/examples/dag_match_condition/run.js +0 -1
  138. package/v1/examples/deep/run.js +0 -2
  139. package/v1/examples/durable/workflow.d.ts +57 -0
  140. package/v1/examples/durable/workflow.js +164 -10
  141. package/v1/examples/durable-event/event.js +0 -1
  142. package/v1/examples/durable-event/run.js +0 -2
  143. package/v1/examples/durable-event/workflow.js +2 -7
  144. package/v1/examples/durable-sleep/event.js +0 -1
  145. package/v1/examples/durable-sleep/run.js +0 -2
  146. package/v1/examples/durable_event/event.js +0 -1
  147. package/v1/examples/durable_event/run.js +0 -2
  148. package/v1/examples/durable_event/workflow.d.ts +1 -0
  149. package/v1/examples/durable_event/workflow.js +4 -9
  150. package/v1/examples/durable_eviction/capacity-worker.d.ts +1 -0
  151. package/v1/examples/durable_eviction/capacity-worker.js +31 -0
  152. package/v1/examples/durable_eviction/worker.d.ts +1 -0
  153. package/v1/examples/durable_eviction/worker.js +34 -0
  154. package/v1/examples/durable_eviction/workflow.d.ts +44 -0
  155. package/v1/examples/durable_eviction/workflow.js +129 -0
  156. package/v1/examples/durable_sleep/event.js +0 -1
  157. package/v1/examples/durable_sleep/run.js +0 -2
  158. package/v1/examples/e2e-worker.js +42 -19
  159. package/v1/examples/events/event.js +0 -1
  160. package/v1/examples/high-memory/run.js +0 -1
  161. package/v1/examples/inferred-typing/run.js +0 -1
  162. package/v1/examples/landing_page/durable-excution.js +0 -1
  163. package/v1/examples/landing_page/queues.js +0 -1
  164. package/v1/examples/legacy/run.js +0 -1
  165. package/v1/examples/logger/byo-logger.js +0 -2
  166. package/v1/examples/logger/logger.js +0 -1
  167. package/v1/examples/logging/byo-logger.js +0 -2
  168. package/v1/examples/logging/logger.js +0 -1
  169. package/v1/examples/middleware/recipes.js +3 -1
  170. package/v1/examples/migration-guides/mergent.js +2 -1
  171. package/v1/examples/multiple_wf_concurrency/run.js +0 -3
  172. package/v1/examples/non_retryable/run.js +0 -1
  173. package/v1/examples/on_event/event.js +0 -1
  174. package/v1/examples/on_failure/run.js +0 -1
  175. package/v1/examples/on_failure/workflow.js +0 -1
  176. package/v1/examples/on_success/run.js +0 -1
  177. package/v1/examples/on_success/workflow.js +0 -1
  178. package/v1/examples/priority/run.js +0 -1
  179. package/v1/examples/priority/workflow.js +0 -1
  180. package/v1/examples/retries/run.js +0 -1
  181. package/v1/examples/retries/workflow.js +0 -1
  182. package/v1/examples/simple/bulk.js +0 -1
  183. package/v1/examples/simple/cron.js +0 -2
  184. package/v1/examples/simple/delay.js +0 -1
  185. package/v1/examples/simple/enqueue.js +0 -2
  186. package/v1/examples/simple/run.js +0 -1
  187. package/v1/examples/simple/schedule.js +0 -1
  188. package/v1/examples/simple/workflow-with-child.js +10 -4
  189. package/v1/examples/sticky/run.js +0 -1
  190. package/v1/examples/sticky/workflow.js +0 -1
  191. package/v1/examples/streaming/nextjs-proxy.js +0 -1
  192. package/v1/examples/streaming/run.js +0 -1
  193. package/v1/examples/timeout/run.js +0 -1
  194. package/v1/examples/timeouts/run.js +0 -1
  195. package/v1/index.d.ts +5 -0
  196. package/v1/index.js +10 -0
  197. package/v1/parent-run-context-vars.d.ts +6 -0
  198. package/v1/slot-types.js +0 -1
  199. package/v1/task.d.ts +10 -2
  200. package/v1/task.js +2 -1
  201. package/version.d.ts +1 -1
  202. package/version.js +1 -1
@@ -17,22 +17,40 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
17
17
  };
18
18
  Object.defineProperty(exports, "__esModule", { value: true });
19
19
  exports.LegacyDualWorker = void 0;
20
+ exports.fetchEngineVersion = fetchEngineVersion;
20
21
  exports.isLegacyEngine = isLegacyEngine;
21
- /* eslint-disable no-underscore-dangle */
22
22
  const nice_grpc_1 = require("nice-grpc");
23
23
  const declaration_1 = require("../../../declaration");
24
24
  const legacy_v1_worker_1 = require("./legacy-v1-worker");
25
25
  const deprecation_1 = require("./deprecation");
26
26
  const legacy_transformer_1 = require("../../../../legacy/legacy-transformer");
27
+ const engine_version_1 = require("../engine-version");
28
+ const grpc_error_1 = require("../../../../util/grpc-error");
27
29
  const DEFAULT_DEFAULT_SLOTS = 100;
28
30
  const DEFAULT_DURABLE_SLOTS = 1000;
29
31
  /** The date when slot_config support was released. */
30
32
  const LEGACY_ENGINE_START = new Date('2026-02-12T00:00:00Z');
31
- /** Minimum engine version that supports multiple slot types. */
32
- const MIN_SLOT_CONFIG_VERSION = 'v0.78.23';
33
33
  const LEGACY_ENGINE_MESSAGE = 'Connected to an older Hatchet engine that does not support multiple slot types. ' +
34
34
  'Falling back to legacy worker registration. ' +
35
35
  'Please upgrade your Hatchet engine to the latest version.';
36
+ /**
37
+ * Fetches the engine version from the dispatcher.
38
+ * Returns the semver string, or undefined if the engine is too old to support GetVersion.
39
+ */
40
+ function fetchEngineVersion(v1) {
41
+ return __awaiter(this, void 0, void 0, function* () {
42
+ try {
43
+ const version = yield v1.dispatcher.getVersion();
44
+ return version || undefined;
45
+ }
46
+ catch (e) {
47
+ if ((0, grpc_error_1.getGrpcErrorCode)(e) == nice_grpc_1.Status.UNIMPLEMENTED) {
48
+ return undefined;
49
+ }
50
+ throw e;
51
+ }
52
+ });
53
+ }
36
54
  /**
37
55
  * Checks if the connected engine is legacy by comparing its semantic version
38
56
  * against the minimum required version for slot_config support.
@@ -41,29 +59,20 @@ const LEGACY_ENGINE_MESSAGE = 'Connected to an older Hatchet engine that does no
41
59
  */
42
60
  function isLegacyEngine(v1) {
43
61
  return __awaiter(this, void 0, void 0, function* () {
44
- try {
45
- const version = yield v1.dispatcher.getVersion();
46
- // If the version is empty or older than the minimum, treat as legacy
47
- if (!version || (0, deprecation_1.semverLessThan)(version, MIN_SLOT_CONFIG_VERSION)) {
48
- const logger = v1.config.logger('Worker', v1.config.log_level);
49
- (0, deprecation_1.emitDeprecationNotice)('legacy-engine', LEGACY_ENGINE_MESSAGE, LEGACY_ENGINE_START, logger, {
50
- errorDays: 180,
51
- });
52
- return true;
62
+ const version = yield fetchEngineVersion(v1).catch((e) => {
63
+ if ((0, grpc_error_1.getGrpcErrorCode)(e) === nice_grpc_1.Status.UNIMPLEMENTED) {
64
+ return undefined;
53
65
  }
54
- return false;
55
- }
56
- catch (e) {
57
- if ((e === null || e === void 0 ? void 0 : e.code) === nice_grpc_1.Status.UNIMPLEMENTED) {
58
- const logger = v1.config.logger('Worker', v1.config.log_level);
59
- (0, deprecation_1.emitDeprecationNotice)('legacy-engine', LEGACY_ENGINE_MESSAGE, LEGACY_ENGINE_START, logger, {
60
- errorDays: 180,
61
- });
62
- return true;
63
- }
64
- // For other errors, assume new engine and let registration fail naturally
65
- return false;
66
+ throw e;
67
+ });
68
+ if (!version || (0, deprecation_1.semverLessThan)(version, engine_version_1.MinEngineVersion.SLOT_CONFIG)) {
69
+ const logger = v1.config.logger('Worker', v1.config.log_level);
70
+ (0, deprecation_1.emitDeprecationNotice)('legacy-engine', LEGACY_ENGINE_MESSAGE, LEGACY_ENGINE_START, logger, {
71
+ errorDays: 180,
72
+ });
73
+ return true;
66
74
  }
75
+ return false;
67
76
  });
68
77
  }
69
78
  /**
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Pre-eviction fallback for DurableContext.
3
+ *
4
+ * Supports engines older than MinEngineVersion.DURABLE_EVICTION.
5
+ * Remove this module when support for those engines is dropped.
6
+ */
7
+ import { Conditions } from '../../../conditions';
8
+ import { DurableListenerClient } from '../../../../clients/listeners/durable-listener/durable-listener-client';
9
+ export declare function waitForPreEviction(durableListener: DurableListenerClient, taskRunExternalId: string, waitKey: number, conditions: Conditions | Conditions[], namespace?: string, signal?: AbortSignal): Promise<{
10
+ result: Record<string, unknown>;
11
+ nextWaitKey: number;
12
+ }>;
@@ -0,0 +1,37 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.waitForPreEviction = waitForPreEviction;
13
+ /**
14
+ * Pre-eviction fallback for DurableContext.
15
+ *
16
+ * Supports engines older than MinEngineVersion.DURABLE_EVICTION.
17
+ * Remove this module when support for those engines is dropped.
18
+ */
19
+ const conditions_1 = require("../../../conditions");
20
+ const transformer_1 = require("../../../conditions/transformer");
21
+ const condition_1 = require("../../../../protoc/v1/shared/condition");
22
+ function waitForPreEviction(durableListener, taskRunExternalId, waitKey, conditions, namespace, signal) {
23
+ return __awaiter(this, void 0, void 0, function* () {
24
+ const pbConditions = (0, transformer_1.conditionsToPb)((0, conditions_1.Render)(condition_1.Action.CREATE, conditions), namespace);
25
+ const key = `waitFor-${waitKey}`;
26
+ yield durableListener.registerDurableEvent({
27
+ taskId: taskRunExternalId,
28
+ signalKey: key,
29
+ sleepConditions: pbConditions.sleepConditions,
30
+ userEventConditions: pbConditions.userEventConditions,
31
+ });
32
+ const event = yield durableListener.result({ taskId: taskRunExternalId, signalKey: key }, { signal });
33
+ const eventData = event.data instanceof Uint8Array ? new TextDecoder().decode(event.data) : event.data;
34
+ const res = JSON.parse(eventData);
35
+ return { result: res.CREATE, nextWaitKey: waitKey + 1 };
36
+ });
37
+ }
@@ -0,0 +1,5 @@
1
+ export declare const MinEngineVersion: {
2
+ readonly SLOT_CONFIG: "v0.78.23";
3
+ readonly DURABLE_EVICTION: "v0.80.0";
4
+ };
5
+ export declare function supportsEviction(engineVersion: string | undefined): boolean;
@@ -0,0 +1,14 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.MinEngineVersion = void 0;
4
+ exports.supportsEviction = supportsEviction;
5
+ const deprecation_1 = require("./deprecated/deprecation");
6
+ exports.MinEngineVersion = {
7
+ SLOT_CONFIG: 'v0.78.23',
8
+ DURABLE_EVICTION: 'v0.80.0',
9
+ };
10
+ function supportsEviction(engineVersion) {
11
+ if (!engineVersion)
12
+ return false;
13
+ return !(0, deprecation_1.semverLessThan)(engineVersion, exports.MinEngineVersion.DURABLE_EVICTION);
14
+ }
@@ -0,0 +1,33 @@
1
+ import { ActionKey } from '../../../../clients/dispatcher/action-listener';
2
+ import { EvictionPolicy } from './eviction-policy';
3
+ export type { ActionKey };
4
+ export declare enum EvictionCause {
5
+ TTL_EXCEEDED = "ttl_exceeded",
6
+ CAPACITY_PRESSURE = "capacity_pressure",
7
+ WORKER_SHUTDOWN = "worker_shutdown"
8
+ }
9
+ export interface DurableRunRecord {
10
+ key: ActionKey;
11
+ taskRunExternalId: string;
12
+ invocationCount: number;
13
+ evictionPolicy: EvictionPolicy | undefined;
14
+ registeredAt: number;
15
+ waitingSince: number | undefined;
16
+ waitKind: string | undefined;
17
+ waitResourceId: string | undefined;
18
+ _waitCount: number;
19
+ evictionReason: string | undefined;
20
+ }
21
+ export declare class DurableEvictionCache {
22
+ private _runs;
23
+ registerRun(key: ActionKey, taskRunExternalId: string, invocationCount: number, now: number, evictionPolicy: EvictionPolicy | undefined): void;
24
+ unregisterRun(key: ActionKey): void;
25
+ get(key: ActionKey): DurableRunRecord | undefined;
26
+ getAllWaiting(): DurableRunRecord[];
27
+ findKeyByTaskRunExternalId(taskRunExternalId: string): ActionKey | undefined;
28
+ markWaiting(key: ActionKey, now: number, waitKind: string, resourceId: string): void;
29
+ markActive(key: ActionKey): void;
30
+ selectEvictionCandidate(now: number, durableSlots: number, reserveSlots: number, minWaitForCapacityEvictionMs: number): ActionKey | undefined;
31
+ private _hasCapacityPressure;
32
+ }
33
+ export declare function buildEvictionReason(cause: EvictionCause, rec: DurableRunRecord): string;
@@ -0,0 +1,139 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.DurableEvictionCache = exports.EvictionCause = void 0;
4
+ exports.buildEvictionReason = buildEvictionReason;
5
+ const duration_1 = require("../../duration");
6
+ var EvictionCause;
7
+ (function (EvictionCause) {
8
+ EvictionCause["TTL_EXCEEDED"] = "ttl_exceeded";
9
+ EvictionCause["CAPACITY_PRESSURE"] = "capacity_pressure";
10
+ EvictionCause["WORKER_SHUTDOWN"] = "worker_shutdown";
11
+ })(EvictionCause || (exports.EvictionCause = EvictionCause = {}));
12
+ class DurableEvictionCache {
13
+ constructor() {
14
+ this._runs = new Map();
15
+ }
16
+ registerRun(key, taskRunExternalId, invocationCount, now, evictionPolicy) {
17
+ this._runs.set(key, {
18
+ key,
19
+ taskRunExternalId,
20
+ invocationCount,
21
+ evictionPolicy,
22
+ registeredAt: now,
23
+ waitingSince: undefined,
24
+ waitKind: undefined,
25
+ waitResourceId: undefined,
26
+ _waitCount: 0,
27
+ evictionReason: undefined,
28
+ });
29
+ }
30
+ unregisterRun(key) {
31
+ this._runs.delete(key);
32
+ }
33
+ get(key) {
34
+ return this._runs.get(key);
35
+ }
36
+ getAllWaiting() {
37
+ return [...this._runs.values()].filter((r) => r._waitCount > 0);
38
+ }
39
+ findKeyByTaskRunExternalId(taskRunExternalId) {
40
+ for (const [key, rec] of this._runs) {
41
+ if (rec.taskRunExternalId === taskRunExternalId)
42
+ return key;
43
+ }
44
+ return undefined;
45
+ }
46
+ markWaiting(key, now, waitKind, resourceId) {
47
+ const rec = this._runs.get(key);
48
+ if (!rec)
49
+ return;
50
+ rec._waitCount += 1;
51
+ if (rec._waitCount === 1) {
52
+ rec.waitingSince = now;
53
+ }
54
+ rec.waitKind = waitKind;
55
+ rec.waitResourceId = resourceId;
56
+ }
57
+ markActive(key) {
58
+ const rec = this._runs.get(key);
59
+ if (!rec)
60
+ return;
61
+ rec._waitCount = Math.max(0, rec._waitCount - 1);
62
+ if (rec._waitCount === 0) {
63
+ rec.waitingSince = undefined;
64
+ rec.waitKind = undefined;
65
+ rec.waitResourceId = undefined;
66
+ }
67
+ }
68
+ selectEvictionCandidate(now, durableSlots, reserveSlots, minWaitForCapacityEvictionMs) {
69
+ const waiting = [...this._runs.values()].filter((r) => r._waitCount > 0 && r.evictionPolicy !== undefined);
70
+ if (waiting.length === 0)
71
+ return undefined;
72
+ const ttlEligible = waiting.filter((r) => {
73
+ var _a;
74
+ const ttl = (_a = r.evictionPolicy) === null || _a === void 0 ? void 0 : _a.ttl;
75
+ if (!ttl || !r.waitingSince)
76
+ return false;
77
+ return now - r.waitingSince >= (0, duration_1.durationToMs)(ttl);
78
+ });
79
+ if (ttlEligible.length > 0) {
80
+ ttlEligible.sort((a, b) => {
81
+ var _a, _b, _c, _d, _e, _f;
82
+ return ((_b = (_a = a.evictionPolicy) === null || _a === void 0 ? void 0 : _a.priority) !== null && _b !== void 0 ? _b : 0) - ((_d = (_c = b.evictionPolicy) === null || _c === void 0 ? void 0 : _c.priority) !== null && _d !== void 0 ? _d : 0) ||
83
+ ((_e = a.waitingSince) !== null && _e !== void 0 ? _e : now) - ((_f = b.waitingSince) !== null && _f !== void 0 ? _f : now);
84
+ });
85
+ const [chosen] = ttlEligible;
86
+ chosen.evictionReason = buildEvictionReason(EvictionCause.TTL_EXCEEDED, chosen);
87
+ return chosen.key;
88
+ }
89
+ if (!this._hasCapacityPressure(durableSlots, reserveSlots, waiting.length)) {
90
+ return undefined;
91
+ }
92
+ const capacityCandidates = waiting.filter((r) => {
93
+ var _a;
94
+ return ((_a = r.evictionPolicy) === null || _a === void 0 ? void 0 : _a.allowCapacityEviction) !== false &&
95
+ r.waitingSince !== undefined &&
96
+ now - r.waitingSince >= minWaitForCapacityEvictionMs;
97
+ });
98
+ if (capacityCandidates.length === 0)
99
+ return undefined;
100
+ capacityCandidates.sort((a, b) => {
101
+ var _a, _b, _c, _d, _e, _f;
102
+ return ((_b = (_a = a.evictionPolicy) === null || _a === void 0 ? void 0 : _a.priority) !== null && _b !== void 0 ? _b : 0) - ((_d = (_c = b.evictionPolicy) === null || _c === void 0 ? void 0 : _c.priority) !== null && _d !== void 0 ? _d : 0) ||
103
+ ((_e = a.waitingSince) !== null && _e !== void 0 ? _e : now) - ((_f = b.waitingSince) !== null && _f !== void 0 ? _f : now);
104
+ });
105
+ const [chosen] = capacityCandidates;
106
+ chosen.evictionReason = buildEvictionReason(EvictionCause.CAPACITY_PRESSURE, chosen);
107
+ return chosen.key;
108
+ }
109
+ _hasCapacityPressure(durableSlots, reserveSlots, waitingCount) {
110
+ if (durableSlots <= 0)
111
+ return false;
112
+ const maxWaiting = durableSlots - reserveSlots;
113
+ if (maxWaiting <= 0)
114
+ return false;
115
+ return waitingCount >= maxWaiting;
116
+ }
117
+ }
118
+ exports.DurableEvictionCache = DurableEvictionCache;
119
+ function buildEvictionReason(cause, rec) {
120
+ var _a;
121
+ let waitDesc = rec.waitKind || 'unknown';
122
+ if (rec.waitResourceId) {
123
+ waitDesc = `${waitDesc}(${rec.waitResourceId})`;
124
+ }
125
+ switch (cause) {
126
+ case EvictionCause.TTL_EXCEEDED: {
127
+ const ttlStr = ((_a = rec.evictionPolicy) === null || _a === void 0 ? void 0 : _a.ttl) ? ` (${rec.evictionPolicy.ttl})` : '';
128
+ return `Wait TTL${ttlStr} exceeded while waiting on ${waitDesc}`;
129
+ }
130
+ case EvictionCause.CAPACITY_PRESSURE:
131
+ return `Worker at capacity while waiting on ${waitDesc}`;
132
+ case EvictionCause.WORKER_SHUTDOWN:
133
+ return `Worker shutdown while waiting on ${waitDesc}`;
134
+ default: {
135
+ const _exhaustive = cause;
136
+ throw new Error(`Unknown eviction cause: ${_exhaustive}`);
137
+ }
138
+ }
139
+ }
@@ -0,0 +1,42 @@
1
+ import { Logger } from '../../../../util/logger';
2
+ import { EvictionPolicy } from './eviction-policy';
3
+ import { ActionKey, DurableEvictionCache, DurableRunRecord } from './eviction-cache';
4
+ export interface DurableEvictionConfig {
5
+ /** How often we try selecting an eviction candidate. Default: 1000ms */
6
+ checkIntervalMs?: number;
7
+ /** How many slots to reserve from capacity-based eviction decisions. Default: 0 */
8
+ reserveSlots?: number;
9
+ /** Avoid immediately evicting runs that just entered a wait. Default: 10000ms */
10
+ minWaitForCapacityEvictionMs?: number;
11
+ }
12
+ export declare const DEFAULT_DURABLE_EVICTION_CONFIG: Required<DurableEvictionConfig>;
13
+ export declare class DurableEvictionManager {
14
+ private _durableSlots;
15
+ private _cancelLocal;
16
+ private _requestEvictionWithAck;
17
+ private _config;
18
+ private _cache;
19
+ private _logger;
20
+ private _timer;
21
+ private _ticking;
22
+ constructor(opts: {
23
+ durableSlots: number;
24
+ cancelLocal: (key: ActionKey) => void;
25
+ requestEvictionWithAck: (key: ActionKey, rec: DurableRunRecord) => Promise<void>;
26
+ config?: DurableEvictionConfig;
27
+ cache?: DurableEvictionCache;
28
+ logger: Logger;
29
+ });
30
+ get cache(): DurableEvictionCache;
31
+ start(): void;
32
+ stop(): void;
33
+ registerRun(key: ActionKey, taskRunExternalId: string, invocationCount: number, evictionPolicy: EvictionPolicy | undefined): void;
34
+ unregisterRun(key: ActionKey): void;
35
+ markWaiting(key: ActionKey, waitKind: string, resourceId: string): void;
36
+ markActive(key: ActionKey): void;
37
+ private _evictRun;
38
+ private _tickSafe;
39
+ private _tick;
40
+ handleServerEviction(taskRunExternalId: string, invocationCount: number): void;
41
+ evictAllWaiting(): Promise<number>;
42
+ }
@@ -0,0 +1,132 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.DurableEvictionManager = exports.DEFAULT_DURABLE_EVICTION_CONFIG = void 0;
13
+ const eviction_cache_1 = require("./eviction-cache");
14
+ const hatchet_error_1 = require("../../../../util/errors/hatchet-error");
15
+ exports.DEFAULT_DURABLE_EVICTION_CONFIG = {
16
+ checkIntervalMs: 1000,
17
+ reserveSlots: 0,
18
+ minWaitForCapacityEvictionMs: 10000,
19
+ };
20
+ class DurableEvictionManager {
21
+ constructor(opts) {
22
+ this._ticking = false;
23
+ this._durableSlots = opts.durableSlots;
24
+ this._cancelLocal = opts.cancelLocal;
25
+ this._requestEvictionWithAck = opts.requestEvictionWithAck;
26
+ this._config = Object.assign(Object.assign({}, exports.DEFAULT_DURABLE_EVICTION_CONFIG), opts.config);
27
+ this._cache = opts.cache || new eviction_cache_1.DurableEvictionCache();
28
+ this._logger = opts.logger;
29
+ }
30
+ get cache() {
31
+ return this._cache;
32
+ }
33
+ start() {
34
+ if (this._timer)
35
+ return;
36
+ this._timer = setInterval(() => this._tickSafe(), this._config.checkIntervalMs);
37
+ }
38
+ stop() {
39
+ if (this._timer) {
40
+ clearInterval(this._timer);
41
+ this._timer = undefined;
42
+ }
43
+ }
44
+ registerRun(key, taskRunExternalId, invocationCount, evictionPolicy) {
45
+ this._cache.registerRun(key, taskRunExternalId, invocationCount, Date.now(), evictionPolicy);
46
+ }
47
+ unregisterRun(key) {
48
+ this._cache.unregisterRun(key);
49
+ }
50
+ markWaiting(key, waitKind, resourceId) {
51
+ this._cache.markWaiting(key, Date.now(), waitKind, resourceId);
52
+ }
53
+ markActive(key) {
54
+ this._cache.markActive(key);
55
+ }
56
+ _evictRun(key) {
57
+ this._cancelLocal(key);
58
+ this.unregisterRun(key);
59
+ }
60
+ _tickSafe() {
61
+ return __awaiter(this, void 0, void 0, function* () {
62
+ if (this._ticking)
63
+ return;
64
+ this._ticking = true;
65
+ try {
66
+ yield this._tick();
67
+ }
68
+ catch (err) {
69
+ this._logger.error(`DurableEvictionManager: error in eviction loop: ${(0, hatchet_error_1.getErrorMessage)(err)}`);
70
+ }
71
+ finally {
72
+ this._ticking = false;
73
+ }
74
+ });
75
+ }
76
+ _tick() {
77
+ return __awaiter(this, void 0, void 0, function* () {
78
+ const evictedThisTick = new Set();
79
+ while (true) {
80
+ const key = this._cache.selectEvictionCandidate(Date.now(), this._durableSlots, this._config.reserveSlots, this._config.minWaitForCapacityEvictionMs);
81
+ if (!key)
82
+ return;
83
+ if (evictedThisTick.has(key))
84
+ return;
85
+ evictedThisTick.add(key);
86
+ const rec = this._cache.get(key);
87
+ if (!rec || !rec.evictionPolicy)
88
+ continue;
89
+ this._logger.debug(`DurableEvictionManager: evicting task_run_external_id=${rec.taskRunExternalId} ` +
90
+ `wait_kind=${rec.waitKind} resource_id=${rec.waitResourceId}`);
91
+ yield this._requestEvictionWithAck(key, rec);
92
+ this._evictRun(key);
93
+ }
94
+ });
95
+ }
96
+ handleServerEviction(taskRunExternalId, invocationCount) {
97
+ const key = this._cache.findKeyByTaskRunExternalId(taskRunExternalId);
98
+ if (!key)
99
+ return;
100
+ const rec = this._cache.get(key);
101
+ if (rec && rec.invocationCount !== invocationCount)
102
+ return;
103
+ this._logger.info(`DurableEvictionManager: server-initiated eviction for task_run_external_id=${taskRunExternalId} invocation_count=${invocationCount}`);
104
+ this._evictRun(key);
105
+ }
106
+ evictAllWaiting() {
107
+ return __awaiter(this, void 0, void 0, function* () {
108
+ this.stop();
109
+ const waiting = this._cache.getAllWaiting();
110
+ let evicted = 0;
111
+ for (const rec of waiting) {
112
+ rec.evictionReason = (0, eviction_cache_1.buildEvictionReason)(eviction_cache_1.EvictionCause.WORKER_SHUTDOWN, rec);
113
+ this._logger.debug(`DurableEvictionManager: shutdown-evicting task_run_external_id=${rec.taskRunExternalId} ` +
114
+ `wait_kind=${rec.waitKind}`);
115
+ try {
116
+ yield this._requestEvictionWithAck(rec.key, rec);
117
+ }
118
+ catch (err) {
119
+ this._logger.error(`DurableEvictionManager: failed to send eviction for ` +
120
+ `task_run_external_id=${rec.taskRunExternalId}: ${(0, hatchet_error_1.getErrorMessage)(err)}`);
121
+ }
122
+ // Always cancel locally even if the server ACK failed, so the
123
+ // future settles and exitGracefully doesn't hang.
124
+ // This will get resolved by the reassignment of the task.
125
+ this._evictRun(rec.key);
126
+ evicted++;
127
+ }
128
+ return evicted;
129
+ });
130
+ }
131
+ }
132
+ exports.DurableEvictionManager = DurableEvictionManager;
@@ -0,0 +1,19 @@
1
+ import { Duration } from '../../duration';
2
+ export type EvictionPolicy = {
3
+ /**
4
+ * Maximum continuous waiting duration before TTL-eligible eviction.
5
+ * `undefined` means no TTL-based eviction.
6
+ */
7
+ ttl?: Duration;
8
+ /**
9
+ * Whether this task may be evicted under durable-slot pressure.
10
+ * @default true
11
+ */
12
+ allowCapacityEviction?: boolean;
13
+ /**
14
+ * Lower values are evicted first when multiple candidates exist.
15
+ * @default 0
16
+ */
17
+ priority?: number;
18
+ };
19
+ export declare const DEFAULT_DURABLE_TASK_EVICTION_POLICY: EvictionPolicy;
@@ -0,0 +1,8 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.DEFAULT_DURABLE_TASK_EVICTION_POLICY = void 0;
4
+ exports.DEFAULT_DURABLE_TASK_EVICTION_POLICY = {
5
+ ttl: '15m',
6
+ allowCapacityEviction: true,
7
+ priority: 0,
8
+ };
@@ -0,0 +1,3 @@
1
+ export { EvictionPolicy, DEFAULT_DURABLE_TASK_EVICTION_POLICY } from './eviction-policy';
2
+ export { DurableEvictionCache, ActionKey, DurableRunRecord, EvictionCause } from './eviction-cache';
3
+ export { DurableEvictionManager, DurableEvictionConfig, DEFAULT_DURABLE_EVICTION_CONFIG, } from './eviction-manager';
@@ -0,0 +1,11 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.DEFAULT_DURABLE_EVICTION_CONFIG = exports.DurableEvictionManager = exports.EvictionCause = exports.DurableEvictionCache = exports.DEFAULT_DURABLE_TASK_EVICTION_POLICY = void 0;
4
+ var eviction_policy_1 = require("./eviction-policy");
5
+ Object.defineProperty(exports, "DEFAULT_DURABLE_TASK_EVICTION_POLICY", { enumerable: true, get: function () { return eviction_policy_1.DEFAULT_DURABLE_TASK_EVICTION_POLICY; } });
6
+ var eviction_cache_1 = require("./eviction-cache");
7
+ Object.defineProperty(exports, "DurableEvictionCache", { enumerable: true, get: function () { return eviction_cache_1.DurableEvictionCache; } });
8
+ Object.defineProperty(exports, "EvictionCause", { enumerable: true, get: function () { return eviction_cache_1.EvictionCause; } });
9
+ var eviction_manager_1 = require("./eviction-manager");
10
+ Object.defineProperty(exports, "DurableEvictionManager", { enumerable: true, get: function () { return eviction_manager_1.DurableEvictionManager; } });
11
+ Object.defineProperty(exports, "DEFAULT_DURABLE_EVICTION_CONFIG", { enumerable: true, get: function () { return eviction_manager_1.DEFAULT_DURABLE_EVICTION_CONFIG; } });
@@ -65,8 +65,8 @@ class HealthServer {
65
65
  }
66
66
  initializeMetrics() {
67
67
  try {
68
- // @ts-ignore - prom-client is an optional dependency
69
- // eslint-disable-next-line
68
+ // THIS IS AN OPTIONAL DEPENDENCY
69
+ // eslint-disable-next-line @typescript-eslint/no-require-imports
70
70
  const { Registry, Gauge, collectDefaultMetrics } = require('prom-client');
71
71
  this.register = new Registry();
72
72
  collectDefaultMetrics({ register: this.register });
@@ -96,7 +96,7 @@ class HealthServer {
96
96
  });
97
97
  this.metricsInitialized = true;
98
98
  }
99
- catch (error) {
99
+ catch (_a) {
100
100
  this.metricsInitialized = false;
101
101
  this.logger.error('Metrics initialization failed - prom-client dependency not installed');
102
102
  }
@@ -28,7 +28,6 @@ function resolveWorkerOptions(options) {
28
28
  (slotConfig[slot_types_1.SlotType.Default] != null ? slotConfig[slot_types_1.SlotType.Default] : undefined), durableSlots: options.durableSlots ||
29
29
  (slotConfig[slot_types_1.SlotType.Durable] != null ? slotConfig[slot_types_1.SlotType.Durable] : undefined), slotConfig });
30
30
  }
31
- // eslint-disable-next-line @typescript-eslint/naming-convention
32
31
  exports.testingExports = {
33
32
  resolveWorkerOptions,
34
33
  };
@@ -49,12 +48,10 @@ function getRequiredSlotTypes(workflows) {
49
48
  };
50
49
  for (const wf of workflows) {
51
50
  if (wf instanceof declaration_1.BaseWorkflowDeclaration) {
52
- // eslint-disable-next-line dot-notation
53
51
  const tasks = wf.definition['_tasks'];
54
52
  for (const task of tasks) {
55
53
  addFromRequests(task.slotRequests, slot_types_1.SlotType.Default);
56
54
  }
57
- // eslint-disable-next-line dot-notation
58
55
  const durableTasks = wf.definition['_durableTasks'];
59
56
  if (durableTasks.length > 0) {
60
57
  required.add(slot_types_1.SlotType.Durable);
@@ -1,4 +1,4 @@
1
- import { Action, ActionListener } from '../../../clients/dispatcher/action-listener';
1
+ import { Action, ActionKey, ActionListener } from '../../../clients/dispatcher/action-listener';
2
2
  import { StepActionEvent, StepActionEventType, GroupKeyActionEvent, GroupKeyActionEventType } from '../../../protoc/dispatcher';
3
3
  import HatchetPromise from '../../../util/hatchet-promise/hatchet-promise';
4
4
  import { CreateStepRateLimit } from '../../../protoc/workflows';
@@ -6,8 +6,11 @@ import { Logger } from '../../../util/logger';
6
6
  import { BaseWorkflowDeclaration, WorkflowDefinition, HatchetClient } from '../..';
7
7
  import { CreateWorkflowTaskOpts } from '../../task';
8
8
  import { WorkerLabels } from '../../../clients/dispatcher/dispatcher-client';
9
+ import { Duration } from '../duration';
9
10
  import { Context } from './context';
10
11
  import { SlotConfig } from '../../slot-types';
12
+ import { DurableEvictionManager } from './eviction/eviction-manager';
13
+ import { EvictionPolicy } from './eviction/eviction-policy';
11
14
  export type ActionRegistry = Record<Action['actionId'], Function>;
12
15
  export interface WorkerOpts {
13
16
  name: string;
@@ -25,13 +28,17 @@ export declare class InternalWorker {
25
28
  killing: boolean;
26
29
  handle_kill: boolean;
27
30
  action_registry: ActionRegistry;
31
+ durable_action_set: Set<string>;
32
+ eviction_policies: Map<string, EvictionPolicy | undefined>;
33
+ evictionManager: DurableEvictionManager | undefined;
28
34
  workflow_registry: Array<WorkflowDefinition>;
29
35
  listener: ActionListener | undefined;
30
- futures: Record<Action['taskRunExternalId'], HatchetPromise<any>>;
31
- contexts: Record<Action['taskRunExternalId'], Context<any, any>>;
36
+ futures: Record<ActionKey, HatchetPromise<any>>;
37
+ contexts: Record<ActionKey, Context<any, any>>;
32
38
  slots?: number;
33
39
  durableSlots?: number;
34
40
  slotConfig: SlotConfig;
41
+ engineVersion: string | undefined;
35
42
  logger: Logger;
36
43
  registeredWorkflowPromises: Array<Promise<any>>;
37
44
  labels: WorkerLabels;
@@ -55,8 +62,9 @@ export declare class InternalWorker {
55
62
  registerDurableActions(workflow: WorkflowDefinition): void;
56
63
  private registerActions;
57
64
  registerWorkflow(initWorkflow: BaseWorkflowDeclaration<any, any>, durable?: boolean): Promise<void>;
65
+ private ensureEvictionManager;
66
+ private cleanupRun;
58
67
  handleStartStepRun(action: Action): Promise<void>;
59
- handleStartGroupKeyRun(action: Action): Promise<void>;
60
68
  getStepActionEvent(action: Action, eventType: StepActionEventType, shouldNotRetry: boolean, payload?: any, retryCount?: number): StepActionEvent;
61
69
  getGroupKeyActionEvent(action: Action, eventType: GroupKeyActionEventType, payload?: any): GroupKeyActionEvent;
62
70
  handleCancelStepRun(action: Action): Promise<void>;
@@ -72,3 +80,14 @@ export declare class InternalWorker {
72
80
  upsertLabels(labels: WorkerLabels): Promise<WorkerLabels>;
73
81
  }
74
82
  export declare function mapRateLimitPb(limits: CreateWorkflowTaskOpts<any, any>['rateLimits']): CreateStepRateLimit[];
83
+ export declare function resolveExecutionTimeout(task: {
84
+ executionTimeout?: Duration;
85
+ timeout?: Duration;
86
+ }, workflowDefaults?: {
87
+ executionTimeout?: Duration;
88
+ }): string;
89
+ export declare function resolveScheduleTimeout(task: {
90
+ scheduleTimeout?: Duration;
91
+ }, workflowDefaults?: {
92
+ scheduleTimeout?: Duration;
93
+ }): string | undefined;