@diia-inhouse/workflow 1.17.11 → 2.5.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 (144) hide show
  1. package/dist/activities/index.d.ts +1 -0
  2. package/dist/activities/index.js +2 -18
  3. package/dist/activities/proxy.d.ts +34 -0
  4. package/dist/activities/proxy.js +16 -24
  5. package/dist/activity.d.ts +2 -0
  6. package/dist/activity.js +2 -15
  7. package/dist/cli/checkWorkflowDeterminism.js +249 -275
  8. package/dist/cli/determinism/errorClassifier.js +56 -60
  9. package/dist/cli/determinism/historyFiles.js +68 -97
  10. package/dist/cli/determinism/index.js +7 -19
  11. package/dist/cli/determinism/replayExecutor.js +114 -133
  12. package/dist/cli/determinism/replayOptions.js +13 -22
  13. package/dist/cli/determinism/report.js +55 -45
  14. package/dist/cli/determinism/reportPrinter.js +101 -138
  15. package/dist/cli/index.d.ts +1 -0
  16. package/dist/cli/index.js +79 -119
  17. package/dist/cli/syncTemporalSchedules.js +74 -91
  18. package/dist/cli/updateTemporalSchedule.js +43 -53
  19. package/dist/client.d.ts +3 -0
  20. package/dist/client.js +3 -19
  21. package/dist/common.d.ts +2 -0
  22. package/dist/common.js +2 -13
  23. package/dist/encryption/crypto.d.ts +7 -0
  24. package/dist/encryption/crypto.js +20 -22
  25. package/dist/encryption/dataConverter.d.ts +7 -0
  26. package/dist/encryption/dataConverter.js +15 -22
  27. package/dist/encryption/encryptionCodec.d.ts +31 -0
  28. package/dist/encryption/encryptionCodec.js +108 -124
  29. package/dist/encryption/index.d.ts +3 -0
  30. package/dist/encryption/index.js +4 -20
  31. package/dist/index.d.ts +7 -0
  32. package/dist/index.js +6 -42
  33. package/dist/instrumentation.js +6 -10
  34. package/dist/interceptors/asyncLocalStorageBridge.js +29 -66
  35. package/dist/interceptors/traceLogAttributes.d.ts +6 -0
  36. package/dist/interceptors/traceLogAttributes.js +16 -54
  37. package/dist/interceptors.d.ts +6 -0
  38. package/dist/interceptors.js +6 -8
  39. package/dist/interfaces/config.d.ts +58 -0
  40. package/dist/interfaces/index.d.ts +1 -0
  41. package/dist/interfaces/services/schedulesExporter.d.ts +96 -0
  42. package/dist/interfaces/services/worker.d.ts +60 -0
  43. package/dist/operations.d.ts +9 -0
  44. package/dist/operations.js +11 -75
  45. package/dist/services/client.d.ts +24 -0
  46. package/dist/services/client.js +89 -96
  47. package/dist/services/schedulesExporter.d.ts +101 -0
  48. package/dist/services/schedulesExporter.js +456 -0
  49. package/dist/services/worker/identity.d.ts +4 -0
  50. package/dist/services/worker/identity.js +6 -9
  51. package/dist/services/worker.d.ts +124 -0
  52. package/dist/services/worker.js +324 -304
  53. package/dist/services/workerHealth.d.ts +15 -0
  54. package/dist/services/workerHealth.js +26 -35
  55. package/dist/testing.d.ts +42 -0
  56. package/dist/testing.js +43 -54
  57. package/dist/worker.d.ts +9 -0
  58. package/dist/worker.js +7 -25
  59. package/package.json +40 -37
  60. package/dist/activities/index.js.map +0 -1
  61. package/dist/activities/proxy.js.map +0 -1
  62. package/dist/activity.js.map +0 -1
  63. package/dist/cli/checkWorkflowDeterminism.js.map +0 -1
  64. package/dist/cli/determinism/errorClassifier.js.map +0 -1
  65. package/dist/cli/determinism/historyFiles.js.map +0 -1
  66. package/dist/cli/determinism/index.js.map +0 -1
  67. package/dist/cli/determinism/replayExecutor.js.map +0 -1
  68. package/dist/cli/determinism/replayOptions.js.map +0 -1
  69. package/dist/cli/determinism/report.js.map +0 -1
  70. package/dist/cli/determinism/reportPrinter.js.map +0 -1
  71. package/dist/cli/determinism/types.js +0 -3
  72. package/dist/cli/determinism/types.js.map +0 -1
  73. package/dist/cli/index.js.map +0 -1
  74. package/dist/cli/syncTemporalSchedules.js.map +0 -1
  75. package/dist/cli/updateTemporalSchedule.js.map +0 -1
  76. package/dist/client.js.map +0 -1
  77. package/dist/common.js.map +0 -1
  78. package/dist/encryption/crypto.js.map +0 -1
  79. package/dist/encryption/dataConverter.js.map +0 -1
  80. package/dist/encryption/encryptionCodec.js.map +0 -1
  81. package/dist/encryption/index.js.map +0 -1
  82. package/dist/index.js.map +0 -1
  83. package/dist/instrumentation.js.map +0 -1
  84. package/dist/interceptors/asyncLocalStorageBridge.js.map +0 -1
  85. package/dist/interceptors/index.js +0 -8
  86. package/dist/interceptors/index.js.map +0 -1
  87. package/dist/interceptors/traceLogAttributes.js.map +0 -1
  88. package/dist/interceptors.js.map +0 -1
  89. package/dist/interfaces/config.js +0 -3
  90. package/dist/interfaces/config.js.map +0 -1
  91. package/dist/interfaces/index.js +0 -18
  92. package/dist/interfaces/index.js.map +0 -1
  93. package/dist/interfaces/services/worker.js +0 -3
  94. package/dist/interfaces/services/worker.js.map +0 -1
  95. package/dist/operations.js.map +0 -1
  96. package/dist/services/client.js.map +0 -1
  97. package/dist/services/index.js +0 -19
  98. package/dist/services/index.js.map +0 -1
  99. package/dist/services/worker/identity.js.map +0 -1
  100. package/dist/services/worker/index.js +0 -18
  101. package/dist/services/worker/index.js.map +0 -1
  102. package/dist/services/worker.js.map +0 -1
  103. package/dist/services/workerHealth.js.map +0 -1
  104. package/dist/testing.js.map +0 -1
  105. package/dist/types/activities/index.d.ts +0 -1
  106. package/dist/types/activities/proxy.d.ts +0 -35
  107. package/dist/types/activity.d.ts +0 -1
  108. package/dist/types/cli/checkWorkflowDeterminism.d.ts +0 -19
  109. package/dist/types/cli/determinism/errorClassifier.d.ts +0 -15
  110. package/dist/types/cli/determinism/historyFiles.d.ts +0 -18
  111. package/dist/types/cli/determinism/index.d.ts +0 -10
  112. package/dist/types/cli/determinism/replayExecutor.d.ts +0 -9
  113. package/dist/types/cli/determinism/replayOptions.d.ts +0 -7
  114. package/dist/types/cli/determinism/report.d.ts +0 -16
  115. package/dist/types/cli/determinism/reportPrinter.d.ts +0 -5
  116. package/dist/types/cli/determinism/types.d.ts +0 -44
  117. package/dist/types/cli/index.d.ts +0 -2
  118. package/dist/types/cli/syncTemporalSchedules.d.ts +0 -12
  119. package/dist/types/cli/updateTemporalSchedule.d.ts +0 -9
  120. package/dist/types/client.d.ts +0 -2
  121. package/dist/types/common.d.ts +0 -1
  122. package/dist/types/encryption/crypto.d.ts +0 -3
  123. package/dist/types/encryption/dataConverter.d.ts +0 -3
  124. package/dist/types/encryption/encryptionCodec.d.ts +0 -27
  125. package/dist/types/encryption/index.d.ts +0 -3
  126. package/dist/types/index.d.ts +0 -3
  127. package/dist/types/instrumentation.d.ts +0 -2
  128. package/dist/types/interceptors/asyncLocalStorageBridge.d.ts +0 -21
  129. package/dist/types/interceptors/index.d.ts +0 -2
  130. package/dist/types/interceptors/traceLogAttributes.d.ts +0 -2
  131. package/dist/types/interceptors.d.ts +0 -2
  132. package/dist/types/interfaces/config.d.ts +0 -38
  133. package/dist/types/interfaces/index.d.ts +0 -1
  134. package/dist/types/interfaces/services/worker.d.ts +0 -37
  135. package/dist/types/operations.d.ts +0 -5
  136. package/dist/types/services/client.d.ts +0 -20
  137. package/dist/types/services/index.d.ts +0 -2
  138. package/dist/types/services/worker/identity.d.ts +0 -1
  139. package/dist/types/services/worker/index.d.ts +0 -1
  140. package/dist/types/services/worker.d.ts +0 -113
  141. package/dist/types/services/workerHealth.d.ts +0 -11
  142. package/dist/types/testing.d.ts +0 -42
  143. package/dist/types/worker.d.ts +0 -3
  144. package/dist/worker.js.map +0 -1
@@ -1,65 +1,61 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.isNewStepsAdded = isNewStepsAdded;
4
- exports.classifyReplayError = classifyReplayError;
5
- const workflow_1 = require("@temporalio/workflow");
1
+ import { DeterminismViolationError } from "@temporalio/workflow";
2
+ //#region src/cli/determinism/errorClassifier.ts
6
3
  const activityMismatchRegex = /Activity type of scheduled event '(.+?)' does not match activity type of activity command '(.+?)'/;
7
4
  function isNewStepsAdded(error) {
8
- return error.errorType === 'DeterminismViolation' && error.errorMessage.includes('WorkflowExecutionCompleted');
5
+ return error.errorType === "DeterminismViolation" && error.errorMessage.includes("WorkflowExecutionCompleted");
9
6
  }
10
7
  function classifyReplayError(workflowId, error) {
11
- if (error instanceof workflow_1.DeterminismViolationError) {
12
- const message = error.message || '';
13
- const match = message.match(activityMismatchRegex);
14
- if (match) {
15
- const [, scheduledEvent, activityCommand] = match;
16
- return {
17
- type: 'determinism-violation',
18
- subtype: 'activity-mismatch',
19
- entry: {
20
- workflowId,
21
- errorType: 'DeterminismViolation',
22
- errorMessage: message,
23
- details: {
24
- issue: 'Activity Type Mismatch',
25
- explanation: `The workflow history expected activity '${scheduledEvent}' but the code attempted to execute '${activityCommand}'`,
26
- },
27
- },
28
- };
29
- }
30
- if (message.includes('WorkflowExecutionCompleted')) {
31
- return {
32
- type: 'determinism-violation',
33
- subtype: 'new-steps-added',
34
- entry: {
35
- workflowId,
36
- errorType: 'DeterminismViolation',
37
- errorMessage: message,
38
- details: {
39
- issue: 'New Steps Added',
40
- explanation: 'This workflow has been modified to add new steps after the point where it previously completed. This is safe to ignore as it does not affect existing history.',
41
- },
42
- },
43
- };
44
- }
45
- return {
46
- type: 'determinism-violation',
47
- subtype: 'other',
48
- entry: {
49
- workflowId,
50
- errorType: 'DeterminismViolation',
51
- errorMessage: message,
52
- },
53
- };
54
- }
55
- return {
56
- type: 'replay-failure',
57
- subtype: undefined,
58
- entry: {
59
- workflowId,
60
- errorType: 'ReplayFailure',
61
- errorMessage: error.message,
62
- },
63
- };
8
+ if (error instanceof DeterminismViolationError) {
9
+ const message = error.message || "";
10
+ const match = message.match(activityMismatchRegex);
11
+ if (match) {
12
+ const [, scheduledEvent, activityCommand] = match;
13
+ return {
14
+ type: "determinism-violation",
15
+ subtype: "activity-mismatch",
16
+ entry: {
17
+ workflowId,
18
+ errorType: "DeterminismViolation",
19
+ errorMessage: message,
20
+ details: {
21
+ issue: "Activity Type Mismatch",
22
+ explanation: `The workflow history expected activity '${scheduledEvent}' but the code attempted to execute '${activityCommand}'`
23
+ }
24
+ }
25
+ };
26
+ }
27
+ if (message.includes("WorkflowExecutionCompleted")) return {
28
+ type: "determinism-violation",
29
+ subtype: "new-steps-added",
30
+ entry: {
31
+ workflowId,
32
+ errorType: "DeterminismViolation",
33
+ errorMessage: message,
34
+ details: {
35
+ issue: "New Steps Added",
36
+ explanation: "This workflow has been modified to add new steps after the point where it previously completed. This is safe to ignore as it does not affect existing history."
37
+ }
38
+ }
39
+ };
40
+ return {
41
+ type: "determinism-violation",
42
+ subtype: "other",
43
+ entry: {
44
+ workflowId,
45
+ errorType: "DeterminismViolation",
46
+ errorMessage: message
47
+ }
48
+ };
49
+ }
50
+ return {
51
+ type: "replay-failure",
52
+ subtype: void 0,
53
+ entry: {
54
+ workflowId,
55
+ errorType: "ReplayFailure",
56
+ errorMessage: error.message
57
+ }
58
+ };
64
59
  }
65
- //# sourceMappingURL=errorClassifier.js.map
60
+ //#endregion
61
+ export { classifyReplayError, isNewStepsAdded };
@@ -1,107 +1,78 @@
1
- "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
4
- };
5
- Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.collectHistoryFiles = collectHistoryFiles;
7
- exports.parseHistoryFile = parseHistoryFile;
8
- exports.loadHistoryEntries = loadHistoryEntries;
9
- const node_fs_1 = require("node:fs");
10
- const node_path_1 = __importDefault(require("node:path"));
11
- const ENCRYPTED_ENCODING = 'YmluYXJ5L2VuY3J5cHRlZA=='; // base64 of 'binary/encrypted'
1
+ import path from "node:path";
2
+ import { existsSync, readFileSync, readdirSync } from "node:fs";
3
+ //#region src/cli/determinism/historyFiles.ts
4
+ const ENCRYPTED_ENCODING = "YmluYXJ5L2VuY3J5cHRlZA==";
12
5
  function collectHistoryFiles(dir) {
13
- // eslint-disable-next-line security/detect-non-literal-fs-filename
14
- const dirExists = (0, node_fs_1.existsSync)(dir); // nosemgrep: eslint.detect-non-literal-fs-filename
15
- if (!dirExists) {
16
- throw new Error(`History directory does not exist: ${dir}`);
17
- }
18
- const files = [];
19
- // eslint-disable-next-line security/detect-non-literal-fs-filename
20
- const entries = (0, node_fs_1.readdirSync)(dir, { withFileTypes: true }); // nosemgrep: eslint.detect-non-literal-fs-filename
21
- for (const entry of entries) {
22
- const fullPath = node_path_1.default.join(dir, entry.name);
23
- if (entry.isDirectory()) {
24
- files.push(...collectHistoryFiles(fullPath));
25
- }
26
- else if (entry.name.endsWith('.json')) {
27
- files.push(fullPath);
28
- }
29
- }
30
- return files;
6
+ if (!existsSync(dir)) throw new Error(`History directory does not exist: ${dir}`);
7
+ const files = [];
8
+ const entries = readdirSync(dir, { withFileTypes: true });
9
+ for (const entry of entries) {
10
+ const fullPath = path.join(dir, entry.name);
11
+ if (entry.isDirectory()) files.push(...collectHistoryFiles(fullPath));
12
+ else if (entry.name.endsWith(".json")) files.push(fullPath);
13
+ }
14
+ return files;
31
15
  }
32
16
  const TERMINAL_EVENT_TYPES = new Set([
33
- 'EVENT_TYPE_WORKFLOW_EXECUTION_COMPLETED',
34
- 'EVENT_TYPE_WORKFLOW_EXECUTION_FAILED',
35
- 'EVENT_TYPE_WORKFLOW_EXECUTION_TIMED_OUT',
36
- 'EVENT_TYPE_WORKFLOW_EXECUTION_CANCELED',
37
- 'EVENT_TYPE_WORKFLOW_EXECUTION_TERMINATED',
17
+ "EVENT_TYPE_WORKFLOW_EXECUTION_COMPLETED",
18
+ "EVENT_TYPE_WORKFLOW_EXECUTION_FAILED",
19
+ "EVENT_TYPE_WORKFLOW_EXECUTION_TIMED_OUT",
20
+ "EVENT_TYPE_WORKFLOW_EXECUTION_CANCELED",
21
+ "EVENT_TYPE_WORKFLOW_EXECUTION_TERMINATED"
38
22
  ]);
39
23
  function parseHistoryFile(filePath) {
40
- const workflowId = node_path_1.default.basename(filePath, '.json');
41
- // eslint-disable-next-line security/detect-non-literal-fs-filename
42
- const content = JSON.parse((0, node_fs_1.readFileSync)(filePath, 'utf8')); // nosemgrep: eslint.detect-non-literal-fs-filename
43
- const history = content.history ?? content;
44
- const events = history.events ?? [];
45
- const startEvent = events.find((e) => e.eventType === 'EVENT_TYPE_WORKFLOW_EXECUTION_STARTED');
46
- const workflowType = startEvent?.workflowExecutionStartedEventAttributes?.workflowType?.name ?? 'unknown';
47
- const encrypted = hasEncryptedPayloads(events);
48
- const running = !events.some((e) => TERMINAL_EVENT_TYPES.has(e.eventType ?? ''));
49
- return { workflowId, workflowType, history, encrypted, running };
24
+ const workflowId = path.basename(filePath, ".json");
25
+ const content = JSON.parse(readFileSync(filePath, "utf8"));
26
+ const history = content.history ?? content;
27
+ const events = history.events ?? [];
28
+ return {
29
+ workflowId,
30
+ workflowType: events.find((e) => e.eventType === "EVENT_TYPE_WORKFLOW_EXECUTION_STARTED")?.workflowExecutionStartedEventAttributes?.workflowType?.name ?? "unknown",
31
+ history,
32
+ encrypted: hasEncryptedPayloads(events),
33
+ running: !events.some((e) => TERMINAL_EVENT_TYPES.has(e.eventType ?? ""))
34
+ };
50
35
  }
51
36
  function hasEncryptedPayloads(events) {
52
- for (const event of events) {
53
- for (const [key, val] of Object.entries(event)) {
54
- if (!key.includes('Attributes') || typeof val !== 'object' || val === null) {
55
- continue;
56
- }
57
- for (const nested of Object.values(val)) {
58
- if (typeof nested !== 'object' || nested === null) {
59
- continue;
60
- }
61
- const payloads = nested.payloads;
62
- if (!Array.isArray(payloads)) {
63
- continue;
64
- }
65
- for (const payload of payloads) {
66
- if (payload.metadata?.encoding === ENCRYPTED_ENCODING) {
67
- return true;
68
- }
69
- }
70
- }
71
- }
72
- }
73
- return false;
37
+ for (const event of events) for (const [key, val] of Object.entries(event)) {
38
+ if (!key.includes("Attributes") || typeof val !== "object" || val === null) continue;
39
+ for (const nested of Object.values(val)) {
40
+ if (typeof nested !== "object" || nested === null) continue;
41
+ const payloads = nested.payloads;
42
+ if (!Array.isArray(payloads)) continue;
43
+ for (const payload of payloads) if (payload.metadata?.encoding === ENCRYPTED_ENCODING) return true;
44
+ }
45
+ }
46
+ return false;
74
47
  }
75
48
  function loadHistoryEntries(historyDir, workflows, options = {}) {
76
- const { limit, encryptionEnabled = false, logger } = options;
77
- let historyFiles = collectHistoryFiles(historyDir);
78
- if (limit && limit > 0 && historyFiles.length > limit) {
79
- historyFiles = historyFiles.slice(0, limit);
80
- }
81
- const entries = [];
82
- let encryptedCount = 0;
83
- let runningCount = 0;
84
- for (const filePath of historyFiles) {
85
- try {
86
- const entry = parseHistoryFile(filePath);
87
- if (entry.workflowType !== 'unknown' && !workflows[entry.workflowType]) {
88
- continue;
89
- }
90
- if (entry.running) {
91
- runningCount++;
92
- continue;
93
- }
94
- if (entry.encrypted && !encryptionEnabled) {
95
- encryptedCount++;
96
- continue;
97
- }
98
- entries.push(entry);
99
- }
100
- catch (err) {
101
- const workflowId = node_path_1.default.basename(filePath, '.json');
102
- logger?.warn(`Skipping ${workflowId} — failed to parse: ${err.message}`);
103
- }
104
- }
105
- return { entries, encryptedCount, runningCount };
49
+ const { limit, encryptionEnabled = false, logger } = options;
50
+ let historyFiles = collectHistoryFiles(historyDir);
51
+ if (limit && limit > 0 && historyFiles.length > limit) historyFiles = historyFiles.slice(0, limit);
52
+ const entries = [];
53
+ let encryptedCount = 0;
54
+ let runningCount = 0;
55
+ for (const filePath of historyFiles) try {
56
+ const entry = parseHistoryFile(filePath);
57
+ if (entry.workflowType !== "unknown" && !workflows[entry.workflowType]) continue;
58
+ if (entry.running) {
59
+ runningCount++;
60
+ continue;
61
+ }
62
+ if (entry.encrypted && !encryptionEnabled) {
63
+ encryptedCount++;
64
+ continue;
65
+ }
66
+ entries.push(entry);
67
+ } catch (err) {
68
+ const workflowId = path.basename(filePath, ".json");
69
+ logger?.warn(`Skipping ${workflowId} — failed to parse: ${err.message}`);
70
+ }
71
+ return {
72
+ entries,
73
+ encryptedCount,
74
+ runningCount
75
+ };
106
76
  }
107
- //# sourceMappingURL=historyFiles.js.map
77
+ //#endregion
78
+ export { loadHistoryEntries };
@@ -1,19 +1,7 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.printReport = exports.replaySingle = exports.replayBatch = exports.resolveWorkflowsPath = exports.buildReplayOptions = exports.DeterminismReportBuilder = exports.loadHistoryEntries = exports.isNewStepsAdded = exports.classifyReplayError = void 0;
4
- var errorClassifier_1 = require("./errorClassifier");
5
- Object.defineProperty(exports, "classifyReplayError", { enumerable: true, get: function () { return errorClassifier_1.classifyReplayError; } });
6
- Object.defineProperty(exports, "isNewStepsAdded", { enumerable: true, get: function () { return errorClassifier_1.isNewStepsAdded; } });
7
- var historyFiles_1 = require("./historyFiles");
8
- Object.defineProperty(exports, "loadHistoryEntries", { enumerable: true, get: function () { return historyFiles_1.loadHistoryEntries; } });
9
- var report_1 = require("./report");
10
- Object.defineProperty(exports, "DeterminismReportBuilder", { enumerable: true, get: function () { return report_1.DeterminismReportBuilder; } });
11
- var replayOptions_1 = require("./replayOptions");
12
- Object.defineProperty(exports, "buildReplayOptions", { enumerable: true, get: function () { return replayOptions_1.buildReplayOptions; } });
13
- Object.defineProperty(exports, "resolveWorkflowsPath", { enumerable: true, get: function () { return replayOptions_1.resolveWorkflowsPath; } });
14
- var replayExecutor_1 = require("./replayExecutor");
15
- Object.defineProperty(exports, "replayBatch", { enumerable: true, get: function () { return replayExecutor_1.replayBatch; } });
16
- Object.defineProperty(exports, "replaySingle", { enumerable: true, get: function () { return replayExecutor_1.replaySingle; } });
17
- var reportPrinter_1 = require("./reportPrinter");
18
- Object.defineProperty(exports, "printReport", { enumerable: true, get: function () { return reportPrinter_1.printReport; } });
19
- //# sourceMappingURL=index.js.map
1
+ import "./errorClassifier.js";
2
+ import "./historyFiles.js";
3
+ import "./report.js";
4
+ import "./replayOptions.js";
5
+ import "./replayExecutor.js";
6
+ import "./reportPrinter.js";
7
+ export {};
@@ -1,139 +1,120 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.replaySingle = replaySingle;
4
- exports.replayBatch = replayBatch;
5
- const worker_1 = require("@temporalio/worker");
6
- const workflow_1 = require("@temporalio/workflow");
7
- const errorClassifier_1 = require("./errorClassifier");
8
- class TimeoutError extends Error {
9
- timeoutMs;
10
- name = 'TimeoutError';
11
- constructor(timeoutMs) {
12
- super(`Replay timed out after ${timeoutMs / 1000}s`);
13
- this.timeoutMs = timeoutMs;
14
- }
15
- }
1
+ import { classifyReplayError } from "./errorClassifier.js";
2
+ import { DeterminismViolationError } from "@temporalio/workflow";
3
+ import { Worker } from "@temporalio/worker";
4
+ import { setTimeout as setTimeout$1 } from "node:timers/promises";
5
+ //#region src/cli/determinism/replayExecutor.ts
6
+ var TimeoutError = class extends Error {
7
+ timeoutMs;
8
+ name = "TimeoutError";
9
+ constructor(timeoutMs) {
10
+ super(`Replay timed out after ${timeoutMs / 1e3}s`);
11
+ this.timeoutMs = timeoutMs;
12
+ }
13
+ };
16
14
  function runWithTimeout(options, history, workflowId, timeoutMs) {
17
- return new Promise((resolve, reject) => {
18
- const timer = setTimeout(() => reject(new TimeoutError(timeoutMs)), timeoutMs);
19
- void worker_1.Worker.runReplayHistory(options, history, workflowId)
20
- .then(resolve, reject)
21
- .finally(() => clearTimeout(timer));
22
- });
15
+ return new Promise((resolve, reject) => {
16
+ const timer = setTimeout(() => reject(new TimeoutError(timeoutMs)), timeoutMs);
17
+ Worker.runReplayHistory(options, history, workflowId).then(resolve, reject).finally(() => clearTimeout(timer));
18
+ });
23
19
  }
24
20
  async function replaySingle(options, history, workflowId, workflowType, config) {
25
- let failedAttempts = 0;
26
- const originalErrors = [];
27
- for (let attempt = 1; attempt <= config.maxRetries; attempt++) {
28
- try {
29
- if (attempt > 1) {
30
- const delay = Math.min(config.retryDelayMs * Math.pow(2, attempt - 2), 4000);
31
- await new Promise((resolve) => setTimeout(resolve, delay));
32
- }
33
- await runWithTimeout(options, history, workflowId, config.timeoutMs);
34
- return {
35
- status: 'success',
36
- workflowId,
37
- workflowType,
38
- recoveredOnRetry: attempt > 1,
39
- failedAttempts,
40
- originalErrors,
41
- };
42
- }
43
- catch (err) {
44
- if (err instanceof workflow_1.DeterminismViolationError) {
45
- const classification = (0, errorClassifier_1.classifyReplayError)(workflowId, err);
46
- return { status: 'failure', workflowId, workflowType, error: classification.entry };
47
- }
48
- if (err instanceof TimeoutError) {
49
- return { status: 'timeout', workflowId, workflowType, timeoutMs: err.timeoutMs };
50
- }
51
- failedAttempts++;
52
- originalErrors.push(`Attempt ${attempt}: ${err instanceof Error ? err.message : String(err)}`);
53
- }
54
- }
55
- return {
56
- status: 'failure',
57
- workflowId,
58
- workflowType,
59
- error: {
60
- workflowId,
61
- errorType: 'ReplayFailure',
62
- errorMessage: `Replay failed after ${config.maxRetries} attempts`,
63
- details: { originalErrors },
64
- },
65
- };
21
+ let failedAttempts = 0;
22
+ const originalErrors = [];
23
+ for (let attempt = 1; attempt <= config.maxRetries; attempt++) try {
24
+ if (attempt > 1) await setTimeout$1(Math.min(config.retryDelayMs * Math.pow(2, attempt - 2), 4e3));
25
+ await runWithTimeout(options, history, workflowId, config.timeoutMs);
26
+ return {
27
+ status: "success",
28
+ workflowId,
29
+ workflowType,
30
+ recoveredOnRetry: attempt > 1,
31
+ failedAttempts,
32
+ originalErrors
33
+ };
34
+ } catch (err) {
35
+ if (err instanceof DeterminismViolationError) return {
36
+ status: "failure",
37
+ workflowId,
38
+ workflowType,
39
+ error: classifyReplayError(workflowId, err).entry
40
+ };
41
+ if (err instanceof TimeoutError) return {
42
+ status: "timeout",
43
+ workflowId,
44
+ workflowType,
45
+ timeoutMs: err.timeoutMs
46
+ };
47
+ failedAttempts++;
48
+ originalErrors.push(`Attempt ${attempt}: ${err instanceof Error ? err.message : String(err)}`);
49
+ }
50
+ return {
51
+ status: "failure",
52
+ workflowId,
53
+ workflowType,
54
+ error: {
55
+ workflowId,
56
+ errorType: "ReplayFailure",
57
+ errorMessage: `Replay failed after ${config.maxRetries} attempts`,
58
+ details: { originalErrors }
59
+ }
60
+ };
66
61
  }
67
- const DEFAULT_BATCH_TIMEOUT_MS = 30_000;
62
+ const DEFAULT_BATCH_TIMEOUT_MS = 3e4;
68
63
  async function* replayBatch(options, entries, timeoutMs = DEFAULT_BATCH_TIMEOUT_MS) {
69
- const entryMap = new Map(entries.map((e) => [e.workflowId, e]));
70
- const entryOrder = entries.map((e) => e.workflowId);
71
- let nextExpectedIndex = 0;
72
- async function* historyIterator() {
73
- for (const entry of entries) {
74
- yield { history: entry.history, workflowId: entry.workflowId };
75
- }
76
- }
77
- const iterator = worker_1.Worker.runReplayHistories(options, historyIterator())[Symbol.asyncIterator]();
78
- while (true) {
79
- const nextResult = await Promise.race([
80
- iterator.next(),
81
- new Promise((resolve) => setTimeout(() => resolve('timeout'), timeoutMs)),
82
- ]);
83
- if (nextResult === 'timeout') {
84
- // The replay stream is stuck — emit timeout for the current expected workflow and abort
85
- const stuckWorkflowId = entryOrder[nextExpectedIndex];
86
- if (stuckWorkflowId) {
87
- const entry = entryMap.get(stuckWorkflowId);
88
- yield {
89
- status: 'timeout',
90
- workflowId: stuckWorkflowId,
91
- workflowType: entry?.workflowType ?? 'unknown',
92
- timeoutMs,
93
- };
94
- }
95
- // Cannot continue the worker is stuck, remaining workflows won't be processed
96
- break;
97
- }
98
- if (nextResult.done) {
99
- break;
100
- }
101
- const result = nextResult.value;
102
- const entry = entryMap.get(result.workflowId);
103
- const workflowType = entry?.workflowType ?? 'unknown';
104
- // Track progress for timeout detection
105
- const resultIndex = entryOrder.indexOf(result.workflowId);
106
- if (resultIndex >= nextExpectedIndex) {
107
- nextExpectedIndex = resultIndex + 1;
108
- }
109
- if (result.error) {
110
- if (result.error instanceof workflow_1.DeterminismViolationError) {
111
- const classification = (0, errorClassifier_1.classifyReplayError)(result.workflowId, result.error);
112
- yield { status: 'failure', workflowId: result.workflowId, workflowType, error: classification.entry };
113
- }
114
- else {
115
- yield {
116
- status: 'failure',
117
- workflowId: result.workflowId,
118
- workflowType,
119
- error: {
120
- workflowId: result.workflowId,
121
- errorType: 'ReplayFailure',
122
- errorMessage: result.error.message,
123
- },
124
- };
125
- }
126
- }
127
- else {
128
- yield {
129
- status: 'success',
130
- workflowId: result.workflowId,
131
- workflowType,
132
- recoveredOnRetry: false,
133
- failedAttempts: 0,
134
- originalErrors: [],
135
- };
136
- }
137
- }
64
+ const entryMap = new Map(entries.map((e) => [e.workflowId, e]));
65
+ const entryOrder = entries.map((e) => e.workflowId);
66
+ let nextExpectedIndex = 0;
67
+ async function* historyIterator() {
68
+ for (const entry of entries) yield {
69
+ history: entry.history,
70
+ workflowId: entry.workflowId
71
+ };
72
+ }
73
+ const iterator = Worker.runReplayHistories(options, historyIterator())[Symbol.asyncIterator]();
74
+ while (true) {
75
+ const nextResult = await Promise.race([iterator.next(), setTimeout$1(timeoutMs).then(() => "timeout")]);
76
+ if (nextResult === "timeout") {
77
+ const stuckWorkflowId = entryOrder[nextExpectedIndex];
78
+ if (stuckWorkflowId) yield {
79
+ status: "timeout",
80
+ workflowId: stuckWorkflowId,
81
+ workflowType: entryMap.get(stuckWorkflowId)?.workflowType ?? "unknown",
82
+ timeoutMs
83
+ };
84
+ break;
85
+ }
86
+ if (nextResult.done) break;
87
+ const result = nextResult.value;
88
+ const workflowType = entryMap.get(result.workflowId)?.workflowType ?? "unknown";
89
+ const resultIndex = entryOrder.indexOf(result.workflowId);
90
+ if (resultIndex >= nextExpectedIndex) nextExpectedIndex = resultIndex + 1;
91
+ if (result.error) if (result.error instanceof DeterminismViolationError) {
92
+ const classification = classifyReplayError(result.workflowId, result.error);
93
+ yield {
94
+ status: "failure",
95
+ workflowId: result.workflowId,
96
+ workflowType,
97
+ error: classification.entry
98
+ };
99
+ } else yield {
100
+ status: "failure",
101
+ workflowId: result.workflowId,
102
+ workflowType,
103
+ error: {
104
+ workflowId: result.workflowId,
105
+ errorType: "ReplayFailure",
106
+ errorMessage: result.error.message
107
+ }
108
+ };
109
+ else yield {
110
+ status: "success",
111
+ workflowId: result.workflowId,
112
+ workflowType,
113
+ recoveredOnRetry: false,
114
+ failedAttempts: 0,
115
+ originalErrors: []
116
+ };
117
+ }
138
118
  }
139
- //# sourceMappingURL=replayExecutor.js.map
119
+ //#endregion
120
+ export { replayBatch, replaySingle };
@@ -1,26 +1,17 @@
1
- "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
4
- };
5
- Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.resolveWorkflowsPath = resolveWorkflowsPath;
7
- exports.buildReplayOptions = buildReplayOptions;
8
- const node_path_1 = __importDefault(require("node:path"));
9
- const encryption_1 = require("../../encryption");
1
+ import { getDataConverter } from "../../encryption/dataConverter.js";
2
+ import "../../encryption/index.js";
3
+ import path from "node:path";
4
+ //#region src/cli/determinism/replayOptions.ts
10
5
  function resolveWorkflowsPath(workflowsPath) {
11
- const baseDir = node_path_1.default.resolve('./dist');
12
- const fullPath = node_path_1.default.resolve(baseDir, workflowsPath, 'index.js');
13
- if (!fullPath.startsWith(baseDir + node_path_1.default.sep)) {
14
- throw new Error(`Invalid workflows path: path traversal detected in '${workflowsPath}'`);
15
- }
16
- return fullPath;
6
+ const baseDir = path.resolve("./dist");
7
+ const fullPath = path.resolve(baseDir, workflowsPath, "index.js");
8
+ if (!fullPath.startsWith(baseDir + path.sep)) throw new Error(`Invalid workflows path: path traversal detected in '${workflowsPath}'`);
9
+ return fullPath;
17
10
  }
18
11
  async function buildReplayOptions(workflowsPath, encryption, envService) {
19
- const fullPath = resolveWorkflowsPath(workflowsPath);
20
- const options = { workflowsPath: fullPath };
21
- if (encryption.enabled && envService) {
22
- options.dataConverter = await (0, encryption_1.getDataConverter)(encryption.keyId, envService);
23
- }
24
- return options;
12
+ const options = { workflowsPath: resolveWorkflowsPath(workflowsPath) };
13
+ if (encryption.enabled && envService) options.dataConverter = await getDataConverter(encryption.keyId, envService);
14
+ return options;
25
15
  }
26
- //# sourceMappingURL=replayOptions.js.map
16
+ //#endregion
17
+ export { buildReplayOptions, resolveWorkflowsPath };