@solidactions/sdk 0.1.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 (167) hide show
  1. package/.claude/settings.local.json +7 -0
  2. package/.clavix/outputs/dbos-http-sdk/full-prd.md +142 -0
  3. package/.clavix/outputs/dbos-http-sdk/quick-prd.md +12 -0
  4. package/.clavix/outputs/dbos-http-sdk/tasks.md +630 -0
  5. package/.clavix/outputs/prompts/dbos-http-api-20260110-033219.md +91 -0
  6. package/.husky/pre-commit +1 -0
  7. package/.prettierignore +3 -0
  8. package/.prettierrc +9 -0
  9. package/CODE_OF_CONDUCT.md +49 -0
  10. package/CONTRIBUTING.md +47 -0
  11. package/LICENSE +21 -0
  12. package/README.md +172 -0
  13. package/dist/dbos-config.schema.json +132 -0
  14. package/dist/schemas/system_db_schema.d.ts +73 -0
  15. package/dist/schemas/system_db_schema.d.ts.map +1 -0
  16. package/dist/schemas/system_db_schema.js +3 -0
  17. package/dist/schemas/system_db_schema.js.map +1 -0
  18. package/dist/src/adminserver.d.ts +79 -0
  19. package/dist/src/adminserver.d.ts.map +1 -0
  20. package/dist/src/adminserver.js +495 -0
  21. package/dist/src/adminserver.js.map +1 -0
  22. package/dist/src/authdecorators.d.ts +2 -0
  23. package/dist/src/authdecorators.d.ts.map +1 -0
  24. package/dist/src/authdecorators.js +48 -0
  25. package/dist/src/authdecorators.js.map +1 -0
  26. package/dist/src/cli/cli.d.ts +9 -0
  27. package/dist/src/cli/cli.d.ts.map +1 -0
  28. package/dist/src/cli/cli.js +116 -0
  29. package/dist/src/cli/cli.js.map +1 -0
  30. package/dist/src/cli/commands.d.ts +3 -0
  31. package/dist/src/cli/commands.d.ts.map +1 -0
  32. package/dist/src/cli/commands.js +46 -0
  33. package/dist/src/cli/commands.js.map +1 -0
  34. package/dist/src/client.d.ts +85 -0
  35. package/dist/src/client.d.ts.map +1 -0
  36. package/dist/src/client.js +186 -0
  37. package/dist/src/client.js.map +1 -0
  38. package/dist/src/conductor/conductor.d.ts +28 -0
  39. package/dist/src/conductor/conductor.d.ts.map +1 -0
  40. package/dist/src/conductor/conductor.js +376 -0
  41. package/dist/src/conductor/conductor.js.map +1 -0
  42. package/dist/src/conductor/protocol.d.ts +238 -0
  43. package/dist/src/conductor/protocol.d.ts.map +1 -0
  44. package/dist/src/conductor/protocol.js +353 -0
  45. package/dist/src/conductor/protocol.js.map +1 -0
  46. package/dist/src/config.d.ts +91 -0
  47. package/dist/src/config.d.ts.map +1 -0
  48. package/dist/src/config.js +199 -0
  49. package/dist/src/config.js.map +1 -0
  50. package/dist/src/context.d.ts +62 -0
  51. package/dist/src/context.d.ts.map +1 -0
  52. package/dist/src/context.js +118 -0
  53. package/dist/src/context.js.map +1 -0
  54. package/dist/src/database_utils.d.ts +17 -0
  55. package/dist/src/database_utils.d.ts.map +1 -0
  56. package/dist/src/database_utils.js +53 -0
  57. package/dist/src/database_utils.js.map +1 -0
  58. package/dist/src/datasource.d.ts +109 -0
  59. package/dist/src/datasource.d.ts.map +1 -0
  60. package/dist/src/datasource.js +204 -0
  61. package/dist/src/datasource.js.map +1 -0
  62. package/dist/src/dbos-executor.d.ts +189 -0
  63. package/dist/src/dbos-executor.d.ts.map +1 -0
  64. package/dist/src/dbos-executor.js +817 -0
  65. package/dist/src/dbos-executor.js.map +1 -0
  66. package/dist/src/dbos.d.ts +519 -0
  67. package/dist/src/dbos.d.ts.map +1 -0
  68. package/dist/src/dbos.js +1282 -0
  69. package/dist/src/dbos.js.map +1 -0
  70. package/dist/src/debouncer.d.ts +33 -0
  71. package/dist/src/debouncer.d.ts.map +1 -0
  72. package/dist/src/debouncer.js +170 -0
  73. package/dist/src/debouncer.js.map +1 -0
  74. package/dist/src/debugpoint.d.ts +26 -0
  75. package/dist/src/debugpoint.d.ts.map +1 -0
  76. package/dist/src/debugpoint.js +65 -0
  77. package/dist/src/debugpoint.js.map +1 -0
  78. package/dist/src/decorators.d.ts +219 -0
  79. package/dist/src/decorators.d.ts.map +1 -0
  80. package/dist/src/decorators.js +873 -0
  81. package/dist/src/decorators.js.map +1 -0
  82. package/dist/src/error.d.ts +130 -0
  83. package/dist/src/error.d.ts.map +1 -0
  84. package/dist/src/error.js +290 -0
  85. package/dist/src/error.js.map +1 -0
  86. package/dist/src/http_client.d.ts +82 -0
  87. package/dist/src/http_client.d.ts.map +1 -0
  88. package/dist/src/http_client.js +286 -0
  89. package/dist/src/http_client.js.map +1 -0
  90. package/dist/src/http_system_database.d.ts +84 -0
  91. package/dist/src/http_system_database.d.ts.map +1 -0
  92. package/dist/src/http_system_database.js +429 -0
  93. package/dist/src/http_system_database.js.map +1 -0
  94. package/dist/src/index.d.ts +14 -0
  95. package/dist/src/index.d.ts.map +1 -0
  96. package/dist/src/index.js +53 -0
  97. package/dist/src/index.js.map +1 -0
  98. package/dist/src/scheduler/crontab.d.ts +14 -0
  99. package/dist/src/scheduler/crontab.d.ts.map +1 -0
  100. package/dist/src/scheduler/crontab.js +308 -0
  101. package/dist/src/scheduler/crontab.js.map +1 -0
  102. package/dist/src/scheduler/scheduler.d.ts +41 -0
  103. package/dist/src/scheduler/scheduler.d.ts.map +1 -0
  104. package/dist/src/scheduler/scheduler.js +165 -0
  105. package/dist/src/scheduler/scheduler.js.map +1 -0
  106. package/dist/src/serialization.d.ts +57 -0
  107. package/dist/src/serialization.d.ts.map +1 -0
  108. package/dist/src/serialization.js +306 -0
  109. package/dist/src/serialization.js.map +1 -0
  110. package/dist/src/solidactions-executor.d.ts +177 -0
  111. package/dist/src/solidactions-executor.d.ts.map +1 -0
  112. package/dist/src/solidactions-executor.js +817 -0
  113. package/dist/src/solidactions-executor.js.map +1 -0
  114. package/dist/src/solidactions.d.ts +519 -0
  115. package/dist/src/solidactions.d.ts.map +1 -0
  116. package/dist/src/solidactions.js +1284 -0
  117. package/dist/src/solidactions.js.map +1 -0
  118. package/dist/src/step.d.ts +16 -0
  119. package/dist/src/step.d.ts.map +1 -0
  120. package/dist/src/step.js +3 -0
  121. package/dist/src/step.js.map +1 -0
  122. package/dist/src/system_database.d.ts +141 -0
  123. package/dist/src/system_database.d.ts.map +1 -0
  124. package/dist/src/system_database.js +25 -0
  125. package/dist/src/system_database.js.map +1 -0
  126. package/dist/src/telemetry/collector.d.ts +13 -0
  127. package/dist/src/telemetry/collector.d.ts.map +1 -0
  128. package/dist/src/telemetry/collector.js +63 -0
  129. package/dist/src/telemetry/collector.js.map +1 -0
  130. package/dist/src/telemetry/exporters.d.ts +13 -0
  131. package/dist/src/telemetry/exporters.d.ts.map +1 -0
  132. package/dist/src/telemetry/exporters.js +101 -0
  133. package/dist/src/telemetry/exporters.js.map +1 -0
  134. package/dist/src/telemetry/logs.d.ts +52 -0
  135. package/dist/src/telemetry/logs.d.ts.map +1 -0
  136. package/dist/src/telemetry/logs.js +287 -0
  137. package/dist/src/telemetry/logs.js.map +1 -0
  138. package/dist/src/telemetry/traces.d.ts +52 -0
  139. package/dist/src/telemetry/traces.d.ts.map +1 -0
  140. package/dist/src/telemetry/traces.js +150 -0
  141. package/dist/src/telemetry/traces.js.map +1 -0
  142. package/dist/src/utils.d.ts +26 -0
  143. package/dist/src/utils.d.ts.map +1 -0
  144. package/dist/src/utils.js +136 -0
  145. package/dist/src/utils.js.map +1 -0
  146. package/dist/src/wfqueue.d.ts +64 -0
  147. package/dist/src/wfqueue.d.ts.map +1 -0
  148. package/dist/src/wfqueue.js +147 -0
  149. package/dist/src/wfqueue.js.map +1 -0
  150. package/dist/src/workflow.d.ts +154 -0
  151. package/dist/src/workflow.d.ts.map +1 -0
  152. package/dist/src/workflow.js +99 -0
  153. package/dist/src/workflow.js.map +1 -0
  154. package/dist/src/workflow_management.d.ts +15 -0
  155. package/dist/src/workflow_management.d.ts.map +1 -0
  156. package/dist/src/workflow_management.js +87 -0
  157. package/dist/src/workflow_management.js.map +1 -0
  158. package/dist/tsconfig.tsbuildinfo +1 -0
  159. package/docs/api-schema.md +1441 -0
  160. package/docs/migration-guide.md +460 -0
  161. package/docs/phase-14-changes.md +156 -0
  162. package/docs/solidsteps-ai-prompt.md +534 -0
  163. package/eslint.config.cjs +50 -0
  164. package/package.json +84 -0
  165. package/solidactions-ai-prompt.md +1504 -0
  166. package/solidactions-config.schema.json +132 -0
  167. package/solidactions-test-config.yaml +15 -0
@@ -0,0 +1,817 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || function (mod) {
19
+ if (mod && mod.__esModule) return mod;
20
+ var result = {};
21
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
+ __setModuleDefault(result, mod);
23
+ return result;
24
+ };
25
+ Object.defineProperty(exports, "__esModule", { value: true });
26
+ exports.SolidActionsExecutor = exports.TempWorkflowType = exports.OperationType = void 0;
27
+ const error_1 = require("./error");
28
+ const workflow_1 = require("./workflow");
29
+ const collector_1 = require("./telemetry/collector");
30
+ const traces_1 = require("./telemetry/traces");
31
+ const logs_1 = require("./telemetry/logs");
32
+ const exporters_1 = require("./telemetry/exporters");
33
+ const system_database_1 = require("./system_database");
34
+ const node_crypto_1 = require("node:crypto");
35
+ const decorators_1 = require("./decorators");
36
+ const context_1 = require("./context");
37
+ const serialize_error_1 = require("serialize-error");
38
+ const utils_1 = require("./utils");
39
+ const serialization_1 = require("./serialization");
40
+ const debugpoint_1 = require("./debugpoint");
41
+ const crypto = __importStar(require("crypto"));
42
+ const workflow_management_1 = require("./workflow_management");
43
+ const solidActionsNull = {};
44
+ exports.OperationType = {
45
+ HANDLER: 'handler',
46
+ WORKFLOW: 'workflow',
47
+ TRANSACTION: 'transaction',
48
+ STEP: 'step',
49
+ };
50
+ exports.TempWorkflowType = {
51
+ step: 'step',
52
+ send: 'send',
53
+ };
54
+ class SolidActionsExecutor {
55
+ config;
56
+ initialized;
57
+ // System Database
58
+ systemDatabase;
59
+ // Temporary workflows are created by calling transaction/send/recv directly from the executor class
60
+ static #tempWorkflowName = 'temp_workflow';
61
+ telemetryCollector;
62
+ static defaultNotificationTimeoutSec = 60;
63
+ #debugMode;
64
+ logger;
65
+ ctxLogger;
66
+ tracer;
67
+ serializer;
68
+ executorID = utils_1.globalParams.executorID;
69
+ static globalInstance = undefined;
70
+ /* WORKFLOW EXECUTOR LIFE CYCLE MANAGEMENT */
71
+ constructor(config, { systemDatabase, debugMode } = {}) {
72
+ this.config = config;
73
+ this.#debugMode = debugMode ?? false;
74
+ if (config.telemetry.OTLPExporter) {
75
+ const OTLPExporter = new exporters_1.TelemetryExporter(config.telemetry.OTLPExporter);
76
+ this.telemetryCollector = new collector_1.TelemetryCollector(OTLPExporter);
77
+ }
78
+ else {
79
+ // We always setup a collector to drain the signals queue, even if we don't have an exporter.
80
+ this.telemetryCollector = new collector_1.TelemetryCollector();
81
+ }
82
+ this.logger = new logs_1.GlobalLogger(this.telemetryCollector, this.config.telemetry.logs, this.appName);
83
+ this.ctxLogger = new logs_1.SolidActionsContextualLogger(this.logger, () => (0, traces_1.getActiveSpan)());
84
+ this.tracer = new traces_1.Tracer(this.telemetryCollector, this.appName);
85
+ this.serializer = config.serializer;
86
+ if (this.#debugMode) {
87
+ this.logger.info('Running in debug mode!');
88
+ }
89
+ if (systemDatabase) {
90
+ this.logger.debug('Using provided system database');
91
+ this.systemDatabase = systemDatabase;
92
+ }
93
+ else {
94
+ // HTTP mode - use HTTP-based system database
95
+ this.logger.debug('Using HTTP system database');
96
+ this.systemDatabase = new system_database_1.HttpSystemDatabase(config.api, this.executorID, utils_1.globalParams.appVersion, this.logger, this.serializer);
97
+ }
98
+ this.initialized = false;
99
+ SolidActionsExecutor.globalInstance = this;
100
+ }
101
+ get appName() {
102
+ return this.config.name;
103
+ }
104
+ async init() {
105
+ if (this.initialized) {
106
+ this.logger.error('Workflow executor already initialized!');
107
+ return;
108
+ }
109
+ try {
110
+ await this.systemDatabase.init(this.#debugMode);
111
+ }
112
+ catch (err) {
113
+ if (err instanceof error_1.SolidActionsInitializationError) {
114
+ throw err;
115
+ }
116
+ this.logger.error(err);
117
+ let message = 'Failed to initialize workflow executor: ';
118
+ if (err instanceof AggregateError) {
119
+ for (const error of err.errors) {
120
+ message += `${error.message}; `;
121
+ }
122
+ }
123
+ else if (err instanceof Error) {
124
+ message += err.message;
125
+ }
126
+ else {
127
+ message += String(err);
128
+ }
129
+ throw new error_1.SolidActionsInitializationError(message, err instanceof Error ? err : undefined);
130
+ }
131
+ this.initialized = true;
132
+ // Only execute init code if under non-debug mode
133
+ if (!this.#debugMode) {
134
+ // Compute the application version if not provided
135
+ if (utils_1.globalParams.appVersion === '') {
136
+ utils_1.globalParams.appVersion = this.computeAppVersion();
137
+ utils_1.globalParams.wasComputed = true;
138
+ }
139
+ // Any initialization hooks
140
+ const classnames = (0, decorators_1.getAllRegisteredClassNames)();
141
+ for (const cls of classnames) {
142
+ // Init its configurations
143
+ const creg = (0, decorators_1.getClassRegistrationByName)(cls);
144
+ for (const [_cfgname, cfg] of creg.configuredInstances) {
145
+ await cfg.initialize();
146
+ }
147
+ }
148
+ this.logger.info(`Initializing SolidActions (v${utils_1.globalParams.solidActionsVersion})`);
149
+ this.logger.info(`HTTP API: ${this.config.api.apiUrl}`);
150
+ this.logger.info(`Executor ID: ${this.executorID}`);
151
+ this.logger.info(`Application version: ${utils_1.globalParams.appVersion}`);
152
+ await this.recoverPendingWorkflows([this.executorID]);
153
+ }
154
+ this.logger.info('SolidActions launched!');
155
+ }
156
+ async destroy() {
157
+ try {
158
+ await this.systemDatabase.awaitRunningWorkflows();
159
+ await this.systemDatabase.destroy();
160
+ await this.logger.destroy();
161
+ if (SolidActionsExecutor.globalInstance === this) {
162
+ SolidActionsExecutor.globalInstance = undefined;
163
+ }
164
+ }
165
+ catch (err) {
166
+ const e = err;
167
+ this.logger.error(e);
168
+ throw err;
169
+ }
170
+ }
171
+ // This could return WF, or the function underlying a temp wf
172
+ #getFunctionInfoFromWFStatus(wf) {
173
+ const methReg = (0, decorators_1.getFunctionRegistrationByName)(wf.workflowClassName, wf.workflowName);
174
+ return { methReg, configuredInst: (0, decorators_1.getConfiguredInstance)(wf.workflowClassName, wf.workflowConfigName) };
175
+ }
176
+ static reviveResultOrError(r, serializer) {
177
+ if (!r.error) {
178
+ return serializer.parse(r.output ?? null);
179
+ }
180
+ else {
181
+ throw (0, serialize_error_1.deserializeError)(serializer.parse(r.error));
182
+ }
183
+ }
184
+ async workflow(wf, params, ...args) {
185
+ return this.internalWorkflow(wf, params, undefined, undefined, ...args);
186
+ }
187
+ // If callerWFID and functionID are set, it means the workflow is invoked from within a workflow.
188
+ async internalWorkflow(wf, params, callerID, callerFunctionID, ...args) {
189
+ const workflowID = params.workflowUUID ? params.workflowUUID : (0, node_crypto_1.randomUUID)();
190
+ const presetID = params.workflowUUID ? true : false;
191
+ const timeoutMS = params.timeoutMS ?? undefined;
192
+ // If a timeout is explicitly specified, use it over any propagated deadline
193
+ const deadlineEpochMS = params.timeoutMS
194
+ ? // Queued workflows are assigned a deadline on dequeue. Otherwise, compute the deadline immediately
195
+ params.queueName
196
+ ? undefined
197
+ : Date.now() + params.timeoutMS
198
+ : // if no timeout is specified, use the propagated deadline (if any)
199
+ params.deadlineEpochMS;
200
+ const pctx = { ...(0, context_1.getCurrentContextStore)() }; // function ID was already incremented...
201
+ let wConfig = {};
202
+ const wInfo = (0, decorators_1.getFunctionRegistration)(wf);
203
+ const wfNames = (0, decorators_1.getRegisteredFunctionFullName)(wf);
204
+ let wfname = wfNames.name;
205
+ let wfclassname = wfNames.className;
206
+ const isTempWorkflow = SolidActionsExecutor.#tempWorkflowName === wfname || !!params.tempWfType;
207
+ if (!isTempWorkflow) {
208
+ if (!wInfo || !wInfo.workflowConfig) {
209
+ throw new error_1.SolidActionsNotRegisteredError(wf.name);
210
+ }
211
+ wConfig = wInfo.workflowConfig;
212
+ }
213
+ else if (params.tempWfName) {
214
+ wfname = params.tempWfName;
215
+ wfclassname = params.tempWfClass ?? '';
216
+ }
217
+ const maxRecoveryAttempts = wConfig.maxRecoveryAttempts
218
+ ? wConfig.maxRecoveryAttempts
219
+ : workflow_1.DEFAULT_MAX_RECOVERY_ATTEMPTS;
220
+ const span = this.tracer.startSpan(wfname, {
221
+ status: workflow_1.StatusString.PENDING,
222
+ operationUUID: workflowID,
223
+ operationType: exports.OperationType.WORKFLOW,
224
+ operationName: wInfo?.name ?? wf.name,
225
+ authenticatedUser: pctx?.authenticatedUser ?? '',
226
+ authenticatedRoles: pctx?.authenticatedRoles ?? [],
227
+ assumedRole: pctx?.assumedRole ?? '',
228
+ });
229
+ const funcArgs = (0, serialization_1.serializeFunctionInputOutput)(args, [wfname, '<arguments>'], this.serializer);
230
+ args = funcArgs.deserialized;
231
+ const internalStatus = {
232
+ workflowUUID: workflowID,
233
+ status: params.queueName !== undefined ? workflow_1.StatusString.ENQUEUED : workflow_1.StatusString.PENDING,
234
+ workflowName: wfname,
235
+ workflowClassName: wfclassname,
236
+ workflowConfigName: params.configuredInstance?.name || '',
237
+ queueName: params.queueName,
238
+ output: null,
239
+ error: null,
240
+ authenticatedUser: pctx?.authenticatedUser || '',
241
+ assumedRole: pctx?.assumedRole || '',
242
+ authenticatedRoles: pctx?.authenticatedRoles || [],
243
+ request: pctx?.request || {},
244
+ executorId: utils_1.globalParams.executorID,
245
+ applicationVersion: utils_1.globalParams.appVersion,
246
+ applicationID: utils_1.globalParams.appID,
247
+ createdAt: Date.now(), // Remember the start time of this workflow,
248
+ timeoutMS: timeoutMS,
249
+ deadlineEpochMS: deadlineEpochMS,
250
+ input: funcArgs.stringified,
251
+ priority: 0,
252
+ };
253
+ if (isTempWorkflow) {
254
+ internalStatus.workflowName = `${SolidActionsExecutor.#tempWorkflowName}-${params.tempWfType}-${params.tempWfName}`;
255
+ }
256
+ let $deadlineEpochMS = undefined;
257
+ let shouldExecute = undefined;
258
+ const serializer = this.serializer;
259
+ // Synchronously set the workflow's status to PENDING and record workflow inputs.
260
+ // We have to do it for all types of workflows because operation_outputs table has a foreign key constraint on workflow status table.
261
+ if (this.#debugMode) {
262
+ const wfStatus = await this.systemDatabase.getWorkflowStatus(workflowID);
263
+ if (!wfStatus) {
264
+ throw new error_1.SolidActionsDebuggerError(`Failed to find inputs for workflow UUID ${workflowID}`);
265
+ }
266
+ // Make sure we use the same input.
267
+ if (funcArgs.stringified !== wfStatus.input) {
268
+ throw new error_1.SolidActionsDebuggerError(`Detected different inputs for workflow UUID ${workflowID}.\n Received: ${funcArgs.stringified}\n Original: ${wfStatus.input}`);
269
+ }
270
+ }
271
+ else {
272
+ if (callerFunctionID !== undefined && callerID !== undefined) {
273
+ const result = await this.systemDatabase.getOperationResultAndThrowIfCancelled(callerID, callerFunctionID);
274
+ if (result) {
275
+ if (result.error) {
276
+ throw (0, serialize_error_1.deserializeError)(serializer.parse(result.error));
277
+ }
278
+ return new workflow_1.RetrievedHandle(this.systemDatabase, result.childWorkflowID);
279
+ }
280
+ }
281
+ let ires;
282
+ try {
283
+ ires = await this.systemDatabase.initWorkflowStatus(internalStatus, (0, node_crypto_1.randomUUID)(), {
284
+ maxRetries: maxRecoveryAttempts,
285
+ isDequeuedRequest: params.isQueueDispatch,
286
+ isRecoveryRequest: params.isRecoveryDispatch,
287
+ });
288
+ }
289
+ catch (e) {
290
+ if (e instanceof error_1.SolidActionsQueueDuplicatedError && callerID && callerFunctionID) {
291
+ await this.systemDatabase.recordOperationResult(callerID, callerFunctionID, internalStatus.workflowName, true, Date.now(), { error: serializer.stringify((0, serialize_error_1.serializeError)(e)) });
292
+ }
293
+ throw e;
294
+ }
295
+ if (callerFunctionID !== undefined && callerID !== undefined) {
296
+ await this.systemDatabase.recordOperationResult(callerID, callerFunctionID, internalStatus.workflowName, true, Date.now(), {
297
+ childWorkflowID: workflowID,
298
+ });
299
+ }
300
+ $deadlineEpochMS = ires.deadlineEpochMS;
301
+ shouldExecute = ires.shouldExecuteOnThisExecutor;
302
+ await (0, debugpoint_1.debugTriggerPoint)(debugpoint_1.DEBUG_TRIGGER_WORKFLOW_ENQUEUE);
303
+ }
304
+ async function callPromiseWithTimeout(callPromise, deadlineEpochMS, sysdb) {
305
+ let timeoutID = undefined;
306
+ const timeoutResult = {};
307
+ const timeoutPromise = new Promise((_, reject) => {
308
+ timeoutID = setTimeout(reject, deadlineEpochMS - Date.now(), timeoutResult);
309
+ });
310
+ try {
311
+ return await Promise.race([callPromise, timeoutPromise]);
312
+ }
313
+ catch (err) {
314
+ if (err === timeoutResult) {
315
+ await sysdb.cancelWorkflow(workflowID);
316
+ await callPromise.catch(() => { });
317
+ throw new error_1.SolidActionsWorkflowCancelledError(workflowID);
318
+ }
319
+ throw err;
320
+ }
321
+ finally {
322
+ clearTimeout(timeoutID);
323
+ }
324
+ }
325
+ async function handleWorkflowError(err, exec) {
326
+ // Record the error.
327
+ const e = err;
328
+ exec.logger.error(e);
329
+ e.solidactions_already_logged = true;
330
+ internalStatus.error = serializer.stringify((0, serialize_error_1.serializeError)(e));
331
+ internalStatus.status = workflow_1.StatusString.ERROR;
332
+ if (!exec.#debugMode) {
333
+ await exec.systemDatabase.recordWorkflowError(workflowID, internalStatus);
334
+ }
335
+ span.setStatus({ code: traces_1.SpanStatusCode.ERROR, message: e.message });
336
+ }
337
+ const runWorkflow = async () => {
338
+ let result;
339
+ // Execute the workflow.
340
+ try {
341
+ const callResult = await (0, traces_1.runWithTrace)(span, async () => {
342
+ return await (0, context_1.runWithParentContext)(pctx, {
343
+ presetID,
344
+ workflowTimeoutMS: undefined, // Becomes deadline
345
+ deadlineEpochMS,
346
+ workflowId: workflowID,
347
+ logger: this.ctxLogger,
348
+ curWFFunctionId: undefined,
349
+ }, () => {
350
+ const callPromise = wf.call(params.configuredInstance, ...args);
351
+ if ($deadlineEpochMS === undefined) {
352
+ return callPromise;
353
+ }
354
+ else {
355
+ return callPromiseWithTimeout(callPromise, $deadlineEpochMS, this.systemDatabase);
356
+ }
357
+ });
358
+ });
359
+ if (this.#debugMode) {
360
+ function resultsMatch(recordedResult, callResult) {
361
+ if (recordedResult === null) {
362
+ return callResult === undefined || callResult === null;
363
+ }
364
+ return serializer.stringify(recordedResult) === serializer.stringify(callResult);
365
+ }
366
+ const recordedResult = SolidActionsExecutor.reviveResultOrError((await this.systemDatabase.awaitWorkflowResult(workflowID)), this.serializer);
367
+ if (!resultsMatch(recordedResult, callResult)) {
368
+ this.logger.error(`Detect different output for the workflow UUID ${workflowID}!\n Received: ${serializer.stringify(callResult)}\n Original: ${serializer.stringify(recordedResult)}`);
369
+ }
370
+ result = recordedResult;
371
+ }
372
+ else {
373
+ result = callResult;
374
+ }
375
+ const funcResult = (0, serialization_1.serializeFunctionInputOutput)(result, [wfname, '<result>'], this.serializer);
376
+ result = funcResult.deserialized;
377
+ internalStatus.output = funcResult.stringified;
378
+ internalStatus.status = workflow_1.StatusString.SUCCESS;
379
+ if (!this.#debugMode) {
380
+ await this.systemDatabase.recordWorkflowOutput(workflowID, internalStatus);
381
+ }
382
+ span.setStatus({ code: traces_1.SpanStatusCode.OK });
383
+ }
384
+ catch (err) {
385
+ if (err instanceof error_1.SolidActionsWorkflowConflictError) {
386
+ // Retrieve the handle and wait for the result.
387
+ const retrievedHandle = this.retrieveWorkflow(workflowID);
388
+ result = await retrievedHandle.getResult();
389
+ span.setAttribute('cached', true);
390
+ span.setStatus({ code: traces_1.SpanStatusCode.OK });
391
+ }
392
+ else if (err instanceof error_1.SolidActionsWorkflowCancelledError) {
393
+ span.setStatus({ code: traces_1.SpanStatusCode.ERROR, message: err.message });
394
+ internalStatus.error = err.message;
395
+ if (err.workflowID === workflowID) {
396
+ internalStatus.status = workflow_1.StatusString.CANCELLED;
397
+ throw err;
398
+ }
399
+ else {
400
+ const e = new error_1.SolidActionsAwaitedWorkflowCancelledError(err.workflowID);
401
+ await handleWorkflowError(e, this);
402
+ throw e;
403
+ }
404
+ }
405
+ else {
406
+ await handleWorkflowError(err, this);
407
+ throw err;
408
+ }
409
+ }
410
+ finally {
411
+ this.tracer.endSpan(span);
412
+ }
413
+ return result;
414
+ };
415
+ if (this.#debugMode ||
416
+ (shouldExecute &&
417
+ (params.queueName === undefined || params.executeWorkflow) &&
418
+ !this.systemDatabase.checkForRunningWorkflow(workflowID))) {
419
+ const workflowPromise = runWorkflow();
420
+ this.systemDatabase.registerRunningWorkflow(workflowID, workflowPromise);
421
+ // Return the normal handle that doesn't capture errors.
422
+ return new workflow_1.InvokedHandle(this.systemDatabase, workflowPromise, workflowID, wf.name);
423
+ }
424
+ else {
425
+ return new workflow_1.RetrievedHandle(this.systemDatabase, workflowID);
426
+ }
427
+ }
428
+ async runStepTempWF(stepFn, params, ...args) {
429
+ return await (await this.startStepTempWF(stepFn, params, undefined, undefined, ...args)).getResult();
430
+ }
431
+ async startStepTempWF(stepFn, params, callerWFID, callerFunctionID, ...args) {
432
+ // Create a workflow and call external.
433
+ const temp_workflow = async (...args) => {
434
+ return await this.callStepFunction(stepFn, undefined, undefined, params.configuredInstance ?? null, ...args);
435
+ };
436
+ return await this.internalWorkflow(temp_workflow, {
437
+ ...params,
438
+ tempWfType: exports.TempWorkflowType.step,
439
+ tempWfName: (0, decorators_1.getRegisteredFunctionName)(stepFn),
440
+ tempWfClass: (0, decorators_1.getRegisteredFunctionClassName)(stepFn),
441
+ }, callerWFID, callerFunctionID, ...args);
442
+ }
443
+ /**
444
+ * Execute a step function.
445
+ * If it encounters any error, retry according to its configured retry policy until the maximum number of attempts is reached, then throw an SolidActionsError.
446
+ * The step may execute many times, but once it is complete, it will not re-execute.
447
+ */
448
+ async callStepFunction(stepFn, stepFnName, stepConfig, clsInst, ...args) {
449
+ stepFnName = stepFnName ?? stepFn.name ?? '<unnamed>';
450
+ const startTime = Date.now();
451
+ if (!stepConfig) {
452
+ const stepReg = (0, decorators_1.getFunctionRegistration)(stepFn);
453
+ stepConfig = stepReg?.stepConfig;
454
+ }
455
+ if (stepConfig === undefined) {
456
+ throw new error_1.SolidActionsNotRegisteredError(stepFnName);
457
+ }
458
+ // Intentionally advance the function ID before any awaits, then work with a copy of the context.
459
+ const funcID = (0, context_1.functionIDGetIncrement)();
460
+ const lctx = { ...(0, context_1.getCurrentContextStore)() };
461
+ const wfid = lctx.workflowId;
462
+ await this.systemDatabase.checkIfCanceled(wfid);
463
+ const maxRetryIntervalSec = 3600; // Maximum retry interval: 1 hour
464
+ const span = this.tracer.startSpan(stepFnName, {
465
+ operationUUID: wfid,
466
+ operationType: exports.OperationType.STEP,
467
+ operationName: stepFnName,
468
+ authenticatedUser: lctx.authenticatedUser ?? '',
469
+ assumedRole: lctx.assumedRole ?? '',
470
+ authenticatedRoles: lctx.authenticatedRoles ?? [],
471
+ retriesAllowed: stepConfig.retriesAllowed,
472
+ intervalSeconds: stepConfig.intervalSeconds,
473
+ maxAttempts: stepConfig.maxAttempts,
474
+ backoffRate: stepConfig.backoffRate,
475
+ });
476
+ // Check if this execution previously happened, returning its original result if it did.
477
+ const checkr = await this.systemDatabase.getOperationResultAndThrowIfCancelled(wfid, funcID);
478
+ if (checkr) {
479
+ if (checkr.functionName !== stepFnName) {
480
+ throw new error_1.SolidActionsUnexpectedStepError(wfid, funcID, stepFnName, checkr.functionName ?? '?');
481
+ }
482
+ const check = SolidActionsExecutor.reviveResultOrError(checkr, this.serializer);
483
+ span.setAttribute('cached', true);
484
+ span.setStatus({ code: traces_1.SpanStatusCode.OK });
485
+ this.tracer.endSpan(span);
486
+ return check;
487
+ }
488
+ if (this.#debugMode) {
489
+ throw new error_1.SolidActionsDebuggerError(`Failed to find the recorded output for the step: workflow UUID: ${wfid}, step number: ${funcID}`);
490
+ }
491
+ const maxAttempts = stepConfig.maxAttempts ?? 3;
492
+ // Execute the step function. If it throws an exception, retry with exponential backoff.
493
+ // After reaching the maximum number of retries, throw an SolidActionsError.
494
+ let result = solidActionsNull;
495
+ let err = solidActionsNull;
496
+ const errors = [];
497
+ if (stepConfig.retriesAllowed) {
498
+ let attemptNum = 0;
499
+ let intervalSeconds = stepConfig.intervalSeconds ?? 1;
500
+ if (intervalSeconds > maxRetryIntervalSec) {
501
+ this.logger.warn(`Step config interval exceeds maximum allowed interval, capped to ${maxRetryIntervalSec} seconds!`);
502
+ }
503
+ while (result === solidActionsNull && attemptNum++ < (maxAttempts ?? 3)) {
504
+ try {
505
+ await this.systemDatabase.checkIfCanceled(wfid);
506
+ let cresult;
507
+ await (0, traces_1.runWithTrace)(span, async () => {
508
+ await (0, context_1.runInStepContext)(lctx, funcID, maxAttempts, attemptNum, async () => {
509
+ const sf = stepFn;
510
+ cresult = await sf.call(clsInst, ...args);
511
+ });
512
+ });
513
+ result = cresult;
514
+ }
515
+ catch (error) {
516
+ const e = error;
517
+ errors.push(e);
518
+ this.logger.warn(`Error in step being automatically retried. Attempt ${attemptNum} of ${maxAttempts}. ${e.stack}`);
519
+ span.addEvent(`Step attempt ${attemptNum + 1} failed`, { retryIntervalSeconds: intervalSeconds, error: error.message }, performance.now());
520
+ if (attemptNum < maxAttempts) {
521
+ // Sleep for an interval, then increase the interval by backoffRate.
522
+ // Cap at the maximum allowed retry interval.
523
+ await (0, utils_1.sleepms)(intervalSeconds * 1000);
524
+ intervalSeconds *= stepConfig.backoffRate ?? 2;
525
+ intervalSeconds = intervalSeconds < maxRetryIntervalSec ? intervalSeconds : maxRetryIntervalSec;
526
+ }
527
+ }
528
+ }
529
+ }
530
+ else {
531
+ try {
532
+ let cresult;
533
+ await (0, traces_1.runWithTrace)(span, async () => {
534
+ await (0, context_1.runInStepContext)(lctx, funcID, maxAttempts, undefined, async () => {
535
+ const sf = stepFn;
536
+ cresult = await sf.call(clsInst, ...args);
537
+ });
538
+ });
539
+ result = cresult;
540
+ }
541
+ catch (error) {
542
+ err = error;
543
+ }
544
+ }
545
+ // `result` can only be solidActionsNull when the step timed out
546
+ if (result === solidActionsNull) {
547
+ // Record the error, then throw it.
548
+ err = err === solidActionsNull ? new error_1.SolidActionsMaxStepRetriesError(stepFnName, maxAttempts, errors) : err;
549
+ await this.systemDatabase.recordOperationResult(wfid, funcID, stepFnName, true, startTime, {
550
+ error: this.serializer.stringify((0, serialize_error_1.serializeError)(err)),
551
+ });
552
+ span.setStatus({ code: traces_1.SpanStatusCode.ERROR, message: err.message });
553
+ this.tracer.endSpan(span);
554
+ throw err;
555
+ }
556
+ else {
557
+ // Record the execution and return.
558
+ const funcResult = (0, serialization_1.serializeFunctionInputOutput)(result, [stepFnName, '<result>'], this.serializer);
559
+ await this.systemDatabase.recordOperationResult(wfid, funcID, stepFnName, true, startTime, {
560
+ output: funcResult.stringified,
561
+ });
562
+ span.setStatus({ code: traces_1.SpanStatusCode.OK });
563
+ this.tracer.endSpan(span);
564
+ return funcResult.deserialized;
565
+ }
566
+ }
567
+ async runSendTempWF(destinationId, message, topic, idempotencyKey) {
568
+ // Create a workflow and call send.
569
+ const temp_workflow = async (destinationId, message, topic) => {
570
+ const ctx = (0, context_1.getCurrentContextStore)();
571
+ const functionID = (0, context_1.functionIDGetIncrement)();
572
+ await this.systemDatabase.send(ctx.workflowId, functionID, destinationId, this.serializer.stringify(message), topic);
573
+ };
574
+ const workflowUUID = idempotencyKey ? destinationId + idempotencyKey : undefined;
575
+ return (await this.workflow(temp_workflow, {
576
+ workflowUUID: workflowUUID,
577
+ tempWfType: exports.TempWorkflowType.send,
578
+ configuredInstance: null,
579
+ }, destinationId, message, topic)).getResult();
580
+ }
581
+ /**
582
+ * Wait for a workflow to emit an event, then return its value.
583
+ */
584
+ async getEvent(workflowUUID, key, timeoutSeconds = SolidActionsExecutor.defaultNotificationTimeoutSec) {
585
+ return this.serializer.parse(await this.systemDatabase.getEvent(workflowUUID, key, timeoutSeconds));
586
+ }
587
+ /**
588
+ * Fork a workflow.
589
+ * The forked workflow will be assigned a new ID.
590
+ */
591
+ forkWorkflow(workflowID, startStep, options = {}) {
592
+ const newWorkflowID = options.newWorkflowID ?? (0, context_1.getNextWFID)(undefined);
593
+ return (0, workflow_management_1.forkWorkflow)(this.systemDatabase, workflowID, startStep, { ...options, newWorkflowID });
594
+ }
595
+ /**
596
+ * Retrieve a handle for a workflow UUID.
597
+ */
598
+ retrieveWorkflow(workflowID) {
599
+ return new workflow_1.RetrievedHandle(this.systemDatabase, workflowID);
600
+ }
601
+ async runInternalStep(callback, functionName, workflowID, functionID, childWfId) {
602
+ const startTime = Date.now();
603
+ const result = await this.systemDatabase.getOperationResultAndThrowIfCancelled(workflowID, functionID);
604
+ if (result) {
605
+ if (result.functionName !== functionName) {
606
+ throw new error_1.SolidActionsUnexpectedStepError(workflowID, functionID, functionName, result.functionName);
607
+ }
608
+ return SolidActionsExecutor.reviveResultOrError(result, this.serializer);
609
+ }
610
+ try {
611
+ const output = await callback();
612
+ const funcOutput = (0, serialization_1.serializeFunctionInputOutput)(output, [functionName, '<result>'], this.serializer);
613
+ await this.systemDatabase.recordOperationResult(workflowID, functionID, functionName, true, startTime, {
614
+ output: funcOutput.stringified,
615
+ childWorkflowID: childWfId,
616
+ });
617
+ return funcOutput.deserialized;
618
+ }
619
+ catch (e) {
620
+ await this.systemDatabase.recordOperationResult(workflowID, functionID, functionName, false, startTime, {
621
+ error: this.serializer.stringify((0, serialize_error_1.serializeError)(e)),
622
+ childWorkflowID: childWfId,
623
+ });
624
+ throw e;
625
+ }
626
+ }
627
+ async getWorkflowStatus(workflowID, callerID, callerFN) {
628
+ // use sysdb getWorkflowStatus directly in order to support caller ID/FN params
629
+ const status = await this.systemDatabase.getWorkflowStatus(workflowID, callerID, callerFN);
630
+ return status ? (0, workflow_management_1.toWorkflowStatus)(status, this.serializer) : null;
631
+ }
632
+ async listWorkflows(input) {
633
+ return (0, workflow_management_1.listWorkflows)(this.systemDatabase, input);
634
+ }
635
+ async listWorkflowSteps(workflowID) {
636
+ return (0, workflow_management_1.listWorkflowSteps)(this.systemDatabase, workflowID);
637
+ }
638
+ /* INTERNAL HELPERS */
639
+ /**
640
+ * A recovery process that by default runs during executor init time.
641
+ * It runs to completion all pending workflows that were executing when the previous executor failed.
642
+ */
643
+ async recoverPendingWorkflows(executorIDs = ['local']) {
644
+ if (this.#debugMode) {
645
+ throw new error_1.SolidActionsDebuggerError('Cannot recover pending workflows in debug mode.');
646
+ }
647
+ const handlerArray = [];
648
+ for (const execID of executorIDs) {
649
+ this.logger.debug(`Recovering workflows assigned to executor: ${execID}`);
650
+ const pendingWorkflows = await this.systemDatabase.getPendingWorkflows(execID, utils_1.globalParams.appVersion);
651
+ if (pendingWorkflows.length > 0) {
652
+ this.logger.info(`Recovering ${pendingWorkflows.length} workflows from application version ${utils_1.globalParams.appVersion}`);
653
+ }
654
+ else {
655
+ this.logger.info(`No workflows to recover from application version ${utils_1.globalParams.appVersion}`);
656
+ }
657
+ for (const pendingWorkflow of pendingWorkflows) {
658
+ this.logger.debug(`Recovering workflow: ${pendingWorkflow.workflowUUID}`);
659
+ try {
660
+ handlerArray.push(await this.executeWorkflowId(pendingWorkflow.workflowUUID, { isRecoveryDispatch: true }));
661
+ }
662
+ catch (e) {
663
+ this.logger.warn(`Recovery of workflow ${pendingWorkflow.workflowUUID} failed: ${e.message}`);
664
+ }
665
+ }
666
+ }
667
+ return handlerArray;
668
+ }
669
+ async initEventReceivers() {
670
+ for (const lcl of (0, decorators_1.getLifecycleListeners)()) {
671
+ await lcl.initialize?.();
672
+ }
673
+ }
674
+ async deactivateEventReceivers() {
675
+ this.logger.debug('Deactivating lifecycle listeners');
676
+ for (const lcl of (0, decorators_1.getLifecycleListeners)()) {
677
+ try {
678
+ await lcl.destroy?.();
679
+ }
680
+ catch (err) {
681
+ const e = err;
682
+ this.logger.warn(`Error destroying lifecycle listener: ${e.message}`);
683
+ }
684
+ }
685
+ }
686
+ async executeWorkflowId(workflowID, options) {
687
+ const wfStatus = await this.systemDatabase.getWorkflowStatus(workflowID);
688
+ if (!wfStatus) {
689
+ this.logger.error(`Failed to find workflow status for workflowUUID: ${workflowID}`);
690
+ throw new error_1.SolidActionsError(`Failed to find workflow status for workflow UUID: ${workflowID}`);
691
+ }
692
+ if (!wfStatus?.input) {
693
+ this.logger.error(`Failed to find inputs for workflowUUID: ${workflowID}`);
694
+ throw new error_1.SolidActionsError(`Failed to find inputs for workflow UUID: ${workflowID}`);
695
+ }
696
+ const inputs = this.serializer.parse(wfStatus.input);
697
+ const recoverCtx = this.#getRecoveryContext(workflowID, wfStatus);
698
+ const { methReg, configuredInst } = this.#getFunctionInfoFromWFStatus(wfStatus);
699
+ // If starting a new workflow, assign a new UUID. Otherwise, use the workflow's original UUID.
700
+ const workflowStartID = !!options?.startNewWorkflow ? undefined : workflowID;
701
+ if (methReg?.workflowConfig) {
702
+ return await (0, context_1.runWithTopContext)(recoverCtx, async () => {
703
+ return await this.workflow(methReg.registeredFunction, {
704
+ workflowUUID: workflowStartID,
705
+ configuredInstance: configuredInst,
706
+ queueName: wfStatus.queueName,
707
+ executeWorkflow: true,
708
+ deadlineEpochMS: wfStatus.deadlineEpochMS,
709
+ isRecoveryDispatch: !!options?.isRecoveryDispatch,
710
+ isQueueDispatch: !!options?.isQueueDispatch,
711
+ }, ...inputs);
712
+ });
713
+ }
714
+ // Should be temporary workflows. Parse the name of the workflow.
715
+ const wfName = wfStatus.workflowName;
716
+ const nameArr = wfName.split('-');
717
+ if (!nameArr[0].startsWith(SolidActionsExecutor.#tempWorkflowName)) {
718
+ throw new error_1.SolidActionsError(`Cannot find workflow function for a non-temporary workflow, ID ${workflowID}, class '${wfStatus.workflowClassName}', function '${wfName}'; did you change your code?`);
719
+ }
720
+ if (nameArr[1] === exports.TempWorkflowType.step) {
721
+ const stepReg = (0, decorators_1.getFunctionRegistrationByName)(wfStatus.workflowClassName, nameArr[2]);
722
+ if (!stepReg?.stepConfig) {
723
+ this.logger.error(`Cannot find step info for ID ${workflowID}, name ${nameArr[2]}`);
724
+ throw new error_1.SolidActionsNotRegisteredError(nameArr[2]);
725
+ }
726
+ return await (0, context_1.runWithTopContext)(recoverCtx, async () => {
727
+ return await this.startStepTempWF(stepReg.registeredFunction, {
728
+ workflowUUID: workflowStartID,
729
+ configuredInstance: configuredInst,
730
+ queueName: wfStatus.queueName, // Probably null
731
+ executeWorkflow: true,
732
+ isRecoveryDispatch: !!options?.isRecoveryDispatch,
733
+ isQueueDispatch: !!options?.isQueueDispatch,
734
+ }, undefined, undefined, ...inputs);
735
+ });
736
+ }
737
+ else if (nameArr[1] === exports.TempWorkflowType.send) {
738
+ const swf = async (destinationID, message, topic) => {
739
+ const ctx = (0, context_1.getCurrentContextStore)();
740
+ const functionID = (0, context_1.functionIDGetIncrement)();
741
+ await this.systemDatabase.send(ctx.workflowId, functionID, destinationID, this.serializer.stringify(message), topic);
742
+ };
743
+ const temp_workflow = swf;
744
+ return await (0, context_1.runWithTopContext)(recoverCtx, async () => {
745
+ return this.workflow(temp_workflow, {
746
+ tempWfName: nameArr[2],
747
+ tempWfType: exports.TempWorkflowType.send,
748
+ workflowUUID: workflowStartID,
749
+ queueName: wfStatus.queueName,
750
+ executeWorkflow: true,
751
+ isRecoveryDispatch: !!options?.isRecoveryDispatch,
752
+ isQueueDispatch: !!options?.isQueueDispatch,
753
+ }, ...inputs);
754
+ });
755
+ }
756
+ else {
757
+ this.logger.error(`Unrecognized temporary workflow! UUID ${workflowID}, name ${wfName}`);
758
+ throw new error_1.SolidActionsNotRegisteredError(wfName);
759
+ }
760
+ }
761
+ async getEventDispatchState(svc, wfn, key) {
762
+ return await this.systemDatabase.getEventDispatchState(svc, wfn, key);
763
+ }
764
+ async upsertEventDispatchState(state) {
765
+ return await this.systemDatabase.upsertEventDispatchState(state);
766
+ }
767
+ #getRecoveryContext(_workflowID, status) {
768
+ // Note: this doesn't inherit the original parent context's span.
769
+ const oc = {};
770
+ oc.request = status.request;
771
+ oc.authenticatedUser = status.authenticatedUser;
772
+ oc.authenticatedRoles = status.authenticatedRoles;
773
+ oc.assumedRole = status.assumedRole;
774
+ return oc;
775
+ }
776
+ async cancelWorkflow(workflowID) {
777
+ await this.systemDatabase.cancelWorkflow(workflowID);
778
+ this.logger.info(`Cancelling workflow ${workflowID}`);
779
+ }
780
+ async getWorkflowSteps(workflowID) {
781
+ const outputs = await this.systemDatabase.getAllOperationResults(workflowID);
782
+ return outputs.map((row) => {
783
+ return {
784
+ function_id: row.function_id,
785
+ function_name: row.function_name ?? '<unknown>',
786
+ child_workflow_id: row.child_workflow_id,
787
+ output: row.output !== null ? this.serializer.parse(row.output) : null,
788
+ error: row.error !== null ? (0, serialize_error_1.deserializeError)(this.serializer.parse(row.error)) : null,
789
+ };
790
+ });
791
+ }
792
+ async resumeWorkflow(workflowID) {
793
+ await this.systemDatabase.resumeWorkflow(workflowID);
794
+ }
795
+ /**
796
+ An application's version is computed from a hash of the source of its workflows.
797
+ This is guaranteed to be stable given identical source code because it uses an MD5 hash
798
+ and because it iterates through the workflows in sorted order.
799
+ This way, if the app's workflows are updated (which would break recovery), its version changes.
800
+ App version can be manually set through the SolidActions__APPVERSION environment variable.
801
+ */
802
+ computeAppVersion() {
803
+ const hasher = crypto.createHash('md5');
804
+ const sortedWorkflowSource = Array.from((0, decorators_1.getAllRegisteredFunctions)())
805
+ .filter((e) => e.workflowConfig)
806
+ .map((i) => i.origFunction.toString())
807
+ .sort();
808
+ // Different SolidActions versions should produce different hashes.
809
+ sortedWorkflowSource.push(utils_1.globalParams.solidActionsVersion);
810
+ for (const sourceCode of sortedWorkflowSource) {
811
+ hasher.update(sourceCode);
812
+ }
813
+ return hasher.digest('hex');
814
+ }
815
+ }
816
+ exports.SolidActionsExecutor = SolidActionsExecutor;
817
+ //# sourceMappingURL=solidactions-executor.js.map