@dbos-inc/dbos-sdk 3.0.23-preview → 3.0.37-preview.gfd7eaf193c

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 (76) hide show
  1. package/dist/src/authdecorators.d.ts +0 -7
  2. package/dist/src/authdecorators.d.ts.map +1 -1
  3. package/dist/src/authdecorators.js +1 -29
  4. package/dist/src/authdecorators.js.map +1 -1
  5. package/dist/src/context.d.ts +9 -43
  6. package/dist/src/context.d.ts.map +1 -1
  7. package/dist/src/context.js +28 -113
  8. package/dist/src/context.js.map +1 -1
  9. package/dist/src/datasource.d.ts +14 -3
  10. package/dist/src/datasource.d.ts.map +1 -1
  11. package/dist/src/datasource.js +12 -11
  12. package/dist/src/datasource.js.map +1 -1
  13. package/dist/src/dbos-executor.d.ts +37 -79
  14. package/dist/src/dbos-executor.d.ts.map +1 -1
  15. package/dist/src/dbos-executor.js +297 -498
  16. package/dist/src/dbos-executor.js.map +1 -1
  17. package/dist/src/dbos-runtime/cli.d.ts.map +1 -1
  18. package/dist/src/dbos-runtime/cli.js +1 -3
  19. package/dist/src/dbos-runtime/cli.js.map +1 -1
  20. package/dist/src/dbos-runtime/debug.d.ts +1 -1
  21. package/dist/src/dbos-runtime/debug.d.ts.map +1 -1
  22. package/dist/src/dbos-runtime/debug.js +2 -3
  23. package/dist/src/dbos-runtime/debug.js.map +1 -1
  24. package/dist/src/dbos-runtime/runtime.d.ts.map +1 -1
  25. package/dist/src/dbos-runtime/runtime.js +0 -9
  26. package/dist/src/dbos-runtime/runtime.js.map +1 -1
  27. package/dist/src/dbos.d.ts +9 -34
  28. package/dist/src/dbos.d.ts.map +1 -1
  29. package/dist/src/dbos.js +95 -273
  30. package/dist/src/dbos.js.map +1 -1
  31. package/dist/src/decorators.d.ts +35 -60
  32. package/dist/src/decorators.d.ts.map +1 -1
  33. package/dist/src/decorators.js +157 -184
  34. package/dist/src/decorators.js.map +1 -1
  35. package/dist/src/httpServer/handler.d.ts +1 -9
  36. package/dist/src/httpServer/handler.d.ts.map +1 -1
  37. package/dist/src/httpServer/handler.js +1 -1
  38. package/dist/src/httpServer/handler.js.map +1 -1
  39. package/dist/src/httpServer/server.d.ts.map +1 -1
  40. package/dist/src/httpServer/server.js +5 -7
  41. package/dist/src/httpServer/server.js.map +1 -1
  42. package/dist/src/index.d.ts +5 -8
  43. package/dist/src/index.d.ts.map +1 -1
  44. package/dist/src/index.js +7 -17
  45. package/dist/src/index.js.map +1 -1
  46. package/dist/src/paramdecorators.d.ts.map +1 -1
  47. package/dist/src/paramdecorators.js +0 -6
  48. package/dist/src/paramdecorators.js.map +1 -1
  49. package/dist/src/procedure.d.ts +0 -22
  50. package/dist/src/procedure.d.ts.map +1 -1
  51. package/dist/src/procedure.js +0 -16
  52. package/dist/src/procedure.js.map +1 -1
  53. package/dist/src/scheduler/scheduler.d.ts.map +1 -1
  54. package/dist/src/scheduler/scheduler.js +3 -2
  55. package/dist/src/scheduler/scheduler.js.map +1 -1
  56. package/dist/src/step.d.ts +0 -25
  57. package/dist/src/step.d.ts.map +1 -1
  58. package/dist/src/step.js +0 -20
  59. package/dist/src/step.js.map +1 -1
  60. package/dist/src/system_database.d.ts +1 -2
  61. package/dist/src/system_database.d.ts.map +1 -1
  62. package/dist/src/system_database.js.map +1 -1
  63. package/dist/src/transaction.d.ts +0 -25
  64. package/dist/src/transaction.d.ts.map +1 -1
  65. package/dist/src/transaction.js +1 -15
  66. package/dist/src/transaction.js.map +1 -1
  67. package/dist/src/workflow.d.ts +4 -148
  68. package/dist/src/workflow.d.ts.map +1 -1
  69. package/dist/src/workflow.js +7 -226
  70. package/dist/src/workflow.js.map +1 -1
  71. package/dist/tsconfig.tsbuildinfo +1 -1
  72. package/package.json +1 -1
  73. package/dist/src/eventreceiver.d.ts +0 -155
  74. package/dist/src/eventreceiver.d.ts.map +0 -1
  75. package/dist/src/eventreceiver.js +0 -3
  76. package/dist/src/eventreceiver.js.map +0 -1
@@ -26,11 +26,10 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
26
26
  return (mod && mod.__esModule) ? mod : { "default": mod };
27
27
  };
28
28
  Object.defineProperty(exports, "__esModule", { value: true });
29
- exports.DBOSExecutor = exports.TempWorkflowType = exports.OperationType = exports.DebugMode = exports.isDeprecatedDBOSConfig = exports.DBOS_QUEUE_MAX_PRIORITY = exports.DBOS_QUEUE_MIN_PRIORITY = exports.dbosNull = void 0;
29
+ exports.DBOSExecutor = exports.TempWorkflowType = exports.OperationType = exports.isDeprecatedDBOSConfig = exports.DBOS_QUEUE_MAX_PRIORITY = exports.DBOS_QUEUE_MIN_PRIORITY = exports.dbosNull = void 0;
30
30
  const error_1 = require("./error");
31
31
  const workflow_1 = require("./workflow");
32
32
  const transaction_1 = require("./transaction");
33
- const step_1 = require("./step");
34
33
  const collector_1 = require("./telemetry/collector");
35
34
  const traces_1 = require("./telemetry/traces");
36
35
  const logs_1 = require("./telemetry/logs");
@@ -46,7 +45,6 @@ const context_1 = require("./context");
46
45
  const serialize_error_1 = require("serialize-error");
47
46
  const utils_1 = require("./utils");
48
47
  const node_path_1 = __importDefault(require("node:path"));
49
- const procedure_1 = require("./procedure");
50
48
  const _1 = require(".");
51
49
  const lodash_1 = require("lodash");
52
50
  const wfqueue_1 = require("./wfqueue");
@@ -67,12 +65,6 @@ function isDeprecatedDBOSConfig(config) {
67
65
  return isDeprecated;
68
66
  }
69
67
  exports.isDeprecatedDBOSConfig = isDeprecatedDBOSConfig;
70
- var DebugMode;
71
- (function (DebugMode) {
72
- DebugMode[DebugMode["DISABLED"] = 0] = "DISABLED";
73
- DebugMode[DebugMode["ENABLED"] = 1] = "ENABLED";
74
- DebugMode[DebugMode["TIME_TRAVEL"] = 2] = "TIME_TRAVEL";
75
- })(DebugMode || (exports.DebugMode = DebugMode = {}));
76
68
  exports.OperationType = {
77
69
  HANDLER: 'handler',
78
70
  WORKFLOW: 'workflow',
@@ -96,51 +88,15 @@ class DBOSExecutor {
96
88
  procedurePool;
97
89
  // Temporary workflows are created by calling transaction/send/recv directly from the executor class
98
90
  static tempWorkflowName = 'temp_workflow';
99
- workflowInfoMap = new Map([
100
- // We initialize the map with an entry for temporary workflows.
101
- [
102
- DBOSExecutor.tempWorkflowName,
103
- {
104
- workflow: async () => {
105
- this.logger.error('UNREACHABLE: Indirect invoke of temp workflow');
106
- return Promise.resolve();
107
- },
108
- workflowOrigFunction: async () => {
109
- this.logger.error('UNREACHABLE: Indirect invoke of temp workflow');
110
- return Promise.resolve();
111
- },
112
- config: {},
113
- },
114
- ],
115
- ]);
116
- transactionInfoMap = new Map();
117
- stepInfoMap = new Map();
118
- procedureInfoMap = new Map();
119
- registeredOperations = [];
120
91
  telemetryCollector;
121
92
  static defaultNotificationTimeoutSec = 60;
122
93
  debugMode;
123
- get isDebugging() {
124
- switch (this.debugMode) {
125
- case DebugMode.DISABLED:
126
- return false;
127
- case DebugMode.ENABLED:
128
- case DebugMode.TIME_TRAVEL:
129
- return true;
130
- default: {
131
- const _never = this.debugMode;
132
- // eslint-disable-next-line @typescript-eslint/restrict-template-expressions
133
- throw new Error(`Unexpected DBOS debug mode: ${this.debugMode}`);
134
- }
135
- }
136
- }
137
94
  static systemDBSchemaName = 'dbos';
138
95
  logger;
139
96
  tracer;
140
97
  // eslint-disable-next-line @typescript-eslint/no-unsafe-function-type
141
98
  typeormEntities = [];
142
99
  drizzleEntities = {};
143
- eventReceivers = [];
144
100
  scheduler = undefined;
145
101
  wfqEnded = undefined;
146
102
  executorID = utils_1.globalParams.executorID;
@@ -148,7 +104,7 @@ class DBOSExecutor {
148
104
  /* WORKFLOW EXECUTOR LIFE CYCLE MANAGEMENT */
149
105
  constructor(config, { systemDatabase, debugMode } = {}) {
150
106
  this.config = config;
151
- this.debugMode = debugMode ?? DebugMode.DISABLED;
107
+ this.debugMode = debugMode ?? false;
152
108
  // Set configured environment variables
153
109
  if (config.env) {
154
110
  for (const [key, value] of Object.entries(config.env)) {
@@ -170,7 +126,7 @@ class DBOSExecutor {
170
126
  }
171
127
  this.logger = new logs_1.GlobalLogger(this.telemetryCollector, this.config.telemetry.logs);
172
128
  this.tracer = new traces_1.Tracer(this.telemetryCollector);
173
- if (this.isDebugging) {
129
+ if (this.debugMode) {
174
130
  this.logger.info('Running in debug mode!');
175
131
  }
176
132
  this.procedurePool = new pg_1.Pool(this.config.poolConfig);
@@ -253,39 +209,6 @@ class DBOSExecutor {
253
209
  this.logger.debug('Loaded Postgres user database');
254
210
  }
255
211
  }
256
- #registerClass(clsname) {
257
- const registeredClassOperations = (0, decorators_1.getRegisteredOperationsByClassname)(clsname);
258
- this.registeredOperations.push(...registeredClassOperations);
259
- for (const ro of registeredClassOperations) {
260
- if (ro.workflowConfig) {
261
- this.#registerWorkflow(ro);
262
- }
263
- else if (ro.txnConfig) {
264
- this.#registerTransaction(ro);
265
- }
266
- else if (ro.stepConfig) {
267
- this.#registerStep(ro);
268
- }
269
- else if (ro.procConfig) {
270
- this.#registerProcedure(ro);
271
- }
272
- for (const [evtRcvr, _cfg] of ro.eventReceiverInfo) {
273
- if (!this.eventReceivers.includes(evtRcvr))
274
- this.eventReceivers.push(evtRcvr);
275
- }
276
- }
277
- }
278
- getRegistrationsFor(obj) {
279
- const res = [];
280
- for (const r of this.registeredOperations) {
281
- if (!r.eventReceiverInfo.has(obj))
282
- continue;
283
- const methodConfig = r.eventReceiverInfo.get(obj);
284
- const classConfig = r.defaults?.eventReceiverInfo.get(obj) ?? {};
285
- res.push({ methodReg: r, methodConfig, classConfig });
286
- }
287
- return res;
288
- }
289
212
  async init(classes) {
290
213
  if (this.initialized) {
291
214
  this.logger.error('Workflow executor already initialized!');
@@ -318,7 +241,7 @@ class DBOSExecutor {
318
241
  }
319
242
  this.logger.debug(`Loaded ${length} ORM entities`);
320
243
  }
321
- if (!this.isDebugging) {
244
+ if (!this.debugMode) {
322
245
  await (0, user_database_1.createDBIfDoesNotExist)(this.config.poolConfig, this.logger);
323
246
  }
324
247
  this.configureDbClient();
@@ -326,12 +249,9 @@ class DBOSExecutor {
326
249
  this.logger.error('No user database configured!');
327
250
  throw new error_1.DBOSInitializationError('No user database configured!');
328
251
  }
329
- for (const cls of classnames) {
330
- this.#registerClass(cls);
331
- }
332
252
  // Debug mode doesn't need to initialize the DBs. Everything should appear to be read-only.
333
- await this.userDatabase.init(this.isDebugging);
334
- if (!this.isDebugging) {
253
+ await this.userDatabase.init(this.debugMode);
254
+ if (!this.debugMode) {
335
255
  await this.systemDatabase.init();
336
256
  }
337
257
  }
@@ -354,7 +274,7 @@ class DBOSExecutor {
354
274
  }
355
275
  this.initialized = true;
356
276
  // Only execute init code if under non-debug mode
357
- if (!this.isDebugging) {
277
+ if (!this.debugMode) {
358
278
  for (const cls of classnames) {
359
279
  // Init its configurations
360
280
  const creg = (0, decorators_1.getClassRegistrationByName)(cls);
@@ -362,7 +282,7 @@ class DBOSExecutor {
362
282
  await cfg.initialize(new _1.InitContext());
363
283
  }
364
284
  }
365
- for (const v of this.registeredOperations) {
285
+ for (const v of (0, decorators_1.getAllRegisteredFunctions)()) {
366
286
  const m = v;
367
287
  if (m.init === true) {
368
288
  this.logger.debug('Executing init method: ' + m.name);
@@ -422,109 +342,11 @@ class DBOSExecutor {
422
342
  throw err;
423
343
  }
424
344
  }
425
- /* WORKFLOW OPERATIONS */
426
- #registerWorkflow(ro) {
427
- const wf = ro.registeredFunction;
428
- if (wf.name === DBOSExecutor.tempWorkflowName) {
429
- throw new error_1.DBOSError(`Unexpected use of reserved workflow name: ${wf.name}`);
430
- }
431
- const wfn = ro.className + '.' + ro.name;
432
- if (this.workflowInfoMap.has(wfn)) {
433
- throw new error_1.DBOSError(`Repeated workflow name: ${wfn}`);
434
- }
435
- const workflowInfo = {
436
- workflow: wf,
437
- workflowOrigFunction: ro.origFunction,
438
- config: { ...ro.workflowConfig },
439
- registration: ro,
440
- };
441
- this.workflowInfoMap.set(wfn, workflowInfo);
442
- this.logger.debug(`Registered workflow ${wfn}`);
443
- }
444
- #registerTransaction(ro) {
445
- const txf = ro.registeredFunction;
446
- const tfn = ro.className + '.' + ro.name;
447
- if (this.transactionInfoMap.has(tfn)) {
448
- throw new error_1.DBOSError(`Repeated Transaction name: ${tfn}`);
449
- }
450
- const txnInfo = {
451
- transaction: txf,
452
- config: { ...ro.txnConfig },
453
- registration: ro,
454
- };
455
- this.transactionInfoMap.set(tfn, txnInfo);
456
- this.logger.debug(`Registered transaction ${tfn}`);
345
+ // This could return WF, or the function underlying a temp wf
346
+ #getFunctionInfoFromWFStatus(wf) {
347
+ const methReg = (0, decorators_1.getFunctionRegistrationByName)(wf.workflowClassName, wf.workflowName);
348
+ return { methReg, configuredInst: (0, decorators_1.getConfiguredInstance)(wf.workflowClassName, wf.workflowConfigName) };
457
349
  }
458
- #registerStep(ro) {
459
- const comm = ro.registeredFunction;
460
- const cfn = ro.className + '.' + ro.name;
461
- if (this.stepInfoMap.has(cfn)) {
462
- throw new error_1.DBOSError(`Repeated Commmunicator name: ${cfn}`);
463
- }
464
- const stepInfo = {
465
- step: comm,
466
- config: { ...ro.stepConfig },
467
- registration: ro,
468
- };
469
- this.stepInfoMap.set(cfn, stepInfo);
470
- this.logger.debug(`Registered step ${cfn}`);
471
- }
472
- #registerProcedure(ro) {
473
- const proc = ro.registeredFunction;
474
- const cfn = ro.className + '.' + ro.name;
475
- if (this.procedureInfoMap.has(cfn)) {
476
- throw new error_1.DBOSError(`Repeated Procedure name: ${cfn}`);
477
- }
478
- const procInfo = {
479
- procedure: proc,
480
- config: { ...ro.procConfig },
481
- registration: ro,
482
- };
483
- this.procedureInfoMap.set(cfn, procInfo);
484
- this.logger.debug(`Registered stored proc ${cfn}`);
485
- }
486
- getWorkflowInfo(wf) {
487
- const wfname = wf.name === DBOSExecutor.tempWorkflowName ? wf.name : (0, decorators_1.getRegisteredMethodClassName)(wf) + '.' + wf.name;
488
- return this.workflowInfoMap.get(wfname);
489
- }
490
- getWorkflowInfoByStatus(wf) {
491
- const wfname = wf.workflowClassName + '.' + wf.workflowName;
492
- const wfInfo = this.workflowInfoMap.get(wfname);
493
- // wfInfo may be undefined here, if this is a temp workflow
494
- return { wfInfo, configuredInst: (0, decorators_1.getConfiguredInstance)(wf.workflowClassName, wf.workflowConfigName) };
495
- }
496
- getTransactionInfo(tf) {
497
- const tfname = (0, decorators_1.getRegisteredMethodClassName)(tf) + '.' + tf.name;
498
- return this.transactionInfoMap.get(tfname);
499
- }
500
- getTransactionInfoByNames(className, functionName, cfgName) {
501
- const tfname = className + '.' + functionName;
502
- const txnInfo = this.transactionInfoMap.get(tfname);
503
- if (!txnInfo) {
504
- throw new error_1.DBOSNotRegisteredError(tfname, `Transaction function name '${tfname}' is not registered.`);
505
- }
506
- return { txnInfo, clsInst: (0, decorators_1.getConfiguredInstance)(className, cfgName) };
507
- }
508
- getStepInfo(cf) {
509
- const cfname = (0, decorators_1.getRegisteredMethodClassName)(cf) + '.' + cf.name;
510
- return this.stepInfoMap.get(cfname);
511
- }
512
- getStepInfoByNames(className, functionName, cfgName) {
513
- const cfname = className + '.' + functionName;
514
- const stepInfo = this.stepInfoMap.get(cfname);
515
- if (!stepInfo) {
516
- throw new error_1.DBOSNotRegisteredError(cfname, `Step function name '${cfname}' is not registered.`);
517
- }
518
- return { commInfo: stepInfo, clsInst: (0, decorators_1.getConfiguredInstance)(className, cfgName) };
519
- }
520
- getProcedureClassName(pf) {
521
- return (0, decorators_1.getRegisteredMethodClassName)(pf);
522
- }
523
- getProcedureInfo(pf) {
524
- const pfName = (0, decorators_1.getRegisteredMethodClassName)(pf) + '.' + pf.name;
525
- return this.procedureInfoMap.get(pfName);
526
- }
527
- // TODO: getProcedureInfoByNames??
528
350
  static reviveResultOrError(r, success) {
529
351
  if (success === true || !r.error) {
530
352
  return utils_1.DBOSJSON.parse(r.output ?? null);
@@ -536,7 +358,7 @@ class DBOSExecutor {
536
358
  async workflow(wf, params, ...args) {
537
359
  return this.internalWorkflow(wf, params, undefined, undefined, ...args);
538
360
  }
539
- // If callerUUID and functionID are set, it means the workflow is invoked from within a workflow.
361
+ // If callerWFID and functionID are set, it means the workflow is invoked from within a workflow.
540
362
  async internalWorkflow(wf, params, callerID, callerFunctionID, ...args) {
541
363
  const workflowID = params.workflowUUID ? params.workflowUUID : (0, node_crypto_1.randomUUID)();
542
364
  const presetID = params.workflowUUID ? true : false;
@@ -560,29 +382,42 @@ class DBOSExecutor {
560
382
  this.logger.warn(`Priority is not enabled for queue ${params.queueName}. Setting priority will not have any effect.`);
561
383
  }
562
384
  }
563
- const wInfo = this.getWorkflowInfo(wf);
564
- if (wInfo === undefined) {
565
- throw new error_1.DBOSNotRegisteredError(wf.name);
566
- }
567
- const wConfig = wInfo.config;
568
- const passContext = wInfo.registration?.passContext ?? true;
569
- const wCtxt = new workflow_1.WorkflowContextImpl(this, params.parentCtx, workflowID, wConfig, wf.name, presetID, timeoutMS, deadlineEpochMS, params.tempWfType, params.tempWfName);
385
+ const pctx = (0, context_1.getCurrentContextStore)();
386
+ let wConfig = {};
387
+ if (wf.name !== DBOSExecutor.tempWorkflowName) {
388
+ const wInfo = (0, decorators_1.getFunctionRegistration)(wf);
389
+ if (!wInfo || !wInfo.workflowConfig) {
390
+ throw new error_1.DBOSNotRegisteredError(wf.name);
391
+ }
392
+ wConfig = wInfo.workflowConfig;
393
+ }
394
+ const maxRecoveryAttempts = wConfig.maxRecoveryAttempts ? wConfig.maxRecoveryAttempts : 50;
395
+ const wfname = wf.name; // TODO: Should be what was registered in wfInfo...
396
+ const span = this.tracer.startSpan(wfname, {
397
+ status: workflow_1.StatusString.PENDING,
398
+ operationUUID: workflowID,
399
+ operationType: exports.OperationType.WORKFLOW,
400
+ authenticatedUser: pctx?.authenticatedUser ?? '',
401
+ authenticatedRoles: pctx?.authenticatedRoles ?? [],
402
+ assumedRole: pctx?.assumedRole ?? '',
403
+ }, pctx?.span);
404
+ const isTempWorkflow = DBOSExecutor.tempWorkflowName === wfname;
570
405
  const internalStatus = {
571
406
  workflowUUID: workflowID,
572
407
  status: params.queueName !== undefined ? workflow_1.StatusString.ENQUEUED : workflow_1.StatusString.PENDING,
573
- workflowName: wf.name,
574
- workflowClassName: wCtxt.isTempWorkflow ? '' : (0, decorators_1.getRegisteredMethodClassName)(wf),
408
+ workflowName: (0, decorators_1.getRegisteredFunctionName)(wf),
409
+ workflowClassName: isTempWorkflow ? '' : (0, decorators_1.getRegisteredFunctionClassName)(wf),
575
410
  workflowConfigName: params.configuredInstance?.name || '',
576
411
  queueName: params.queueName,
577
- authenticatedUser: wCtxt.authenticatedUser,
578
412
  output: null,
579
413
  error: null,
580
- assumedRole: wCtxt.assumedRole,
581
- authenticatedRoles: wCtxt.authenticatedRoles,
582
- request: wCtxt.request,
583
- executorId: wCtxt.executorID,
414
+ authenticatedUser: pctx?.authenticatedUser || '',
415
+ assumedRole: pctx?.assumedRole || '',
416
+ authenticatedRoles: pctx?.authenticatedRoles || [],
417
+ request: pctx?.request || {},
418
+ executorId: utils_1.globalParams.executorID,
584
419
  applicationVersion: utils_1.globalParams.appVersion,
585
- applicationID: wCtxt.applicationID,
420
+ applicationID: utils_1.globalParams.appID,
586
421
  createdAt: Date.now(), // Remember the start time of this workflow,
587
422
  timeoutMS: timeoutMS,
588
423
  deadlineEpochMS: deadlineEpochMS,
@@ -590,15 +425,15 @@ class DBOSExecutor {
590
425
  deduplicationID: params.enqueueOptions?.deduplicationID,
591
426
  priority: priority ?? 0,
592
427
  };
593
- if (wCtxt.isTempWorkflow) {
594
- internalStatus.workflowName = `${DBOSExecutor.tempWorkflowName}-${wCtxt.tempWfOperationType}-${wCtxt.tempWfOperationName}`;
428
+ if (isTempWorkflow) {
429
+ internalStatus.workflowName = `${DBOSExecutor.tempWorkflowName}-${params.tempWfType}-${params.tempWfName}`;
595
430
  internalStatus.workflowClassName = params.tempWfClass ?? '';
596
431
  }
597
432
  let status = undefined;
598
433
  let $deadlineEpochMS = undefined;
599
434
  // Synchronously set the workflow's status to PENDING and record workflow inputs.
600
435
  // We have to do it for all types of workflows because operation_outputs table has a foreign key constraint on workflow status table.
601
- if (this.isDebugging) {
436
+ if (this.debugMode) {
602
437
  const wfStatus = await this.systemDatabase.getWorkflowStatus(workflowID);
603
438
  if (!wfStatus) {
604
439
  throw new error_1.DBOSDebuggerError(`Failed to find inputs for workflow UUID ${workflowID}`);
@@ -616,7 +451,7 @@ class DBOSExecutor {
616
451
  return new workflow_1.RetrievedHandle(this.systemDatabase, result.childWorkflowID, callerID, callerFunctionID);
617
452
  }
618
453
  }
619
- const ires = await this.systemDatabase.initWorkflowStatus(internalStatus, wCtxt.maxRecoveryAttempts);
454
+ const ires = await this.systemDatabase.initWorkflowStatus(internalStatus, maxRecoveryAttempts);
620
455
  if (callerFunctionID !== undefined && callerID !== undefined) {
621
456
  await this.systemDatabase.recordOperationResult(callerID, callerFunctionID, internalStatus.workflowName, true, {
622
457
  childWorkflowID: workflowID,
@@ -654,19 +489,22 @@ class DBOSExecutor {
654
489
  e.dbos_already_logged = true;
655
490
  internalStatus.error = utils_1.DBOSJSON.stringify((0, serialize_error_1.serializeError)(e));
656
491
  internalStatus.status = workflow_1.StatusString.ERROR;
657
- if (!exec.isDebugging) {
492
+ if (!exec.debugMode) {
658
493
  await exec.systemDatabase.recordWorkflowError(workflowID, internalStatus);
659
494
  }
660
- wCtxt.span.setStatus({ code: api_1.SpanStatusCode.ERROR, message: e.message });
495
+ span.setStatus({ code: api_1.SpanStatusCode.ERROR, message: e.message });
661
496
  }
662
497
  const runWorkflow = async () => {
663
498
  let result;
664
499
  // Execute the workflow.
665
500
  try {
666
- const callResult = await (0, context_1.runWithWorkflowContext)(wCtxt, () => {
667
- const callPromise = passContext
668
- ? wf.call(params.configuredInstance, wCtxt, ...args)
669
- : wf.call(params.configuredInstance, ...args);
501
+ const callResult = await (0, context_1.runWithParentContext)(pctx, {
502
+ presetID,
503
+ timeoutMS,
504
+ deadlineEpochMS,
505
+ workflowId: workflowID,
506
+ }, () => {
507
+ const callPromise = wf.call(params.configuredInstance, ...args);
670
508
  if ($deadlineEpochMS === undefined) {
671
509
  return callPromise;
672
510
  }
@@ -674,7 +512,7 @@ class DBOSExecutor {
674
512
  return callPromiseWithTimeout(callPromise, $deadlineEpochMS, this.systemDatabase);
675
513
  }
676
514
  });
677
- if (this.isDebugging) {
515
+ if (this.debugMode) {
678
516
  const recordedResult = DBOSExecutor.reviveResultOrError((await this.systemDatabase.awaitWorkflowResult(workflowID)));
679
517
  if (!resultsMatch(recordedResult, callResult)) {
680
518
  this.logger.error(`Detect different output for the workflow UUID ${workflowID}!\n Received: ${utils_1.DBOSJSON.stringify(callResult)}\n Original: ${utils_1.DBOSJSON.stringify(recordedResult)}`);
@@ -692,21 +530,21 @@ class DBOSExecutor {
692
530
  }
693
531
  internalStatus.output = utils_1.DBOSJSON.stringify(result);
694
532
  internalStatus.status = workflow_1.StatusString.SUCCESS;
695
- if (!this.isDebugging) {
533
+ if (!this.debugMode) {
696
534
  await this.systemDatabase.recordWorkflowOutput(workflowID, internalStatus);
697
535
  }
698
- wCtxt.span.setStatus({ code: api_1.SpanStatusCode.OK });
536
+ span.setStatus({ code: api_1.SpanStatusCode.OK });
699
537
  }
700
538
  catch (err) {
701
539
  if (err instanceof error_1.DBOSWorkflowConflictError) {
702
540
  // Retrieve the handle and wait for the result.
703
541
  const retrievedHandle = this.retrieveWorkflow(workflowID);
704
542
  result = await retrievedHandle.getResult();
705
- wCtxt.span.setAttribute('cached', true);
706
- wCtxt.span.setStatus({ code: api_1.SpanStatusCode.OK });
543
+ span.setAttribute('cached', true);
544
+ span.setStatus({ code: api_1.SpanStatusCode.OK });
707
545
  }
708
546
  else if (err instanceof error_1.DBOSWorkflowCancelledError) {
709
- wCtxt.span.setStatus({ code: api_1.SpanStatusCode.ERROR, message: err.message });
547
+ span.setStatus({ code: api_1.SpanStatusCode.ERROR, message: err.message });
710
548
  internalStatus.error = err.message;
711
549
  if (err.workflowID === workflowID) {
712
550
  internalStatus.status = workflow_1.StatusString.CANCELLED;
@@ -724,11 +562,11 @@ class DBOSExecutor {
724
562
  }
725
563
  }
726
564
  finally {
727
- this.tracer.endSpan(wCtxt.span);
565
+ this.tracer.endSpan(span);
728
566
  }
729
567
  return result;
730
568
  };
731
- if (this.isDebugging ||
569
+ if (this.debugMode ||
732
570
  (status !== 'SUCCESS' && status !== 'ERROR' && (params.queueName === undefined || params.executeWorkflow))) {
733
571
  const workflowPromise = runWorkflow();
734
572
  this.systemDatabase.registerRunningWorkflow(workflowID, workflowPromise);
@@ -794,7 +632,7 @@ class DBOSExecutor {
794
632
  * Write a operation's output to the database.
795
633
  */
796
634
  async #recordOutput(query, workflowUUID, funcID, txnSnapshot, output, isKeyConflict, function_name) {
797
- if (this.isDebugging) {
635
+ if (this.debugMode) {
798
636
  throw new error_1.DBOSDebuggerError('Cannot record output in debug mode.');
799
637
  }
800
638
  try {
@@ -816,7 +654,7 @@ class DBOSExecutor {
816
654
  * Record an error in an operation to the database.
817
655
  */
818
656
  async #recordError(query, workflowUUID, funcID, txnSnapshot, err, isKeyConflict, function_name) {
819
- if (this.isDebugging) {
657
+ if (this.debugMode) {
820
658
  throw new error_1.DBOSDebuggerError('Cannot record error in debug mode.');
821
659
  }
822
660
  try {
@@ -841,70 +679,63 @@ class DBOSExecutor {
841
679
  }
842
680
  return rows;
843
681
  }
844
- async transaction(txn, params, ...args) {
682
+ async runTransactionTempWF(txn, params, ...args) {
845
683
  return await (await this.startTransactionTempWF(txn, params, undefined, undefined, ...args)).getResult();
846
684
  }
847
- async startTransactionTempWF(txn, params, callerUUID, callerFunctionID, ...args) {
685
+ async startTransactionTempWF(txn, params, callerWFID, callerFunctionID, ...args) {
848
686
  // Create a workflow and call transaction.
849
- const temp_workflow = async (ctxt, ...args) => {
850
- const ctxtImpl = ctxt;
851
- return await this.callTransactionFunction(txn, params.configuredInstance ?? null, ctxtImpl, ...args);
687
+ const temp_workflow = async (...args) => {
688
+ return await this.callTransactionFunction(txn, params.configuredInstance ?? null, ...args);
852
689
  };
853
690
  return await this.internalWorkflow(temp_workflow, {
854
691
  ...params,
855
692
  tempWfType: exports.TempWorkflowType.transaction,
856
- tempWfName: (0, decorators_1.getRegisteredMethodName)(txn),
857
- tempWfClass: (0, decorators_1.getRegisteredMethodClassName)(txn),
858
- }, callerUUID, callerFunctionID, ...args);
693
+ tempWfName: (0, decorators_1.getRegisteredFunctionName)(txn),
694
+ tempWfClass: (0, decorators_1.getRegisteredFunctionClassName)(txn),
695
+ }, callerWFID, callerFunctionID, ...args);
859
696
  }
860
- async callTransactionFunction(txn, clsinst, wfCtx, ...args) {
861
- const txnInfo = this.getTransactionInfo(txn);
862
- if (txnInfo === undefined) {
697
+ async callTransactionFunction(txn, clsinst, ...args) {
698
+ const txnReg = (0, decorators_1.getFunctionRegistration)(txn);
699
+ if (!txnReg || !txnReg.txnConfig) {
863
700
  throw new error_1.DBOSNotRegisteredError(txn.name);
864
701
  }
865
- await this.systemDatabase.checkIfCanceled(wfCtx.workflowUUID);
702
+ const pctx = (0, context_1.getCurrentContextStore)();
703
+ const wfid = pctx.workflowId;
704
+ await this.systemDatabase.checkIfCanceled(wfid);
866
705
  let retryWaitMillis = 1;
867
706
  const backoffFactor = 1.5;
868
707
  const maxRetryWaitMs = 2000; // Maximum wait 2 seconds.
869
- const funcId = wfCtx.functionIDGetIncrement();
708
+ const funcId = (0, context_1.functionIDGetIncrement)();
870
709
  const span = this.tracer.startSpan(txn.name, {
871
- operationUUID: wfCtx.workflowUUID,
710
+ operationUUID: wfid,
872
711
  operationType: exports.OperationType.TRANSACTION,
873
- authenticatedUser: wfCtx.authenticatedUser,
874
- assumedRole: wfCtx.assumedRole,
875
- authenticatedRoles: wfCtx.authenticatedRoles,
876
- isolationLevel: txnInfo.config.isolationLevel,
877
- }, wfCtx.span);
712
+ authenticatedUser: pctx.authenticatedUser,
713
+ assumedRole: pctx.assumedRole,
714
+ authenticatedRoles: pctx.authenticatedRoles,
715
+ isolationLevel: txnReg.txnConfig.isolationLevel,
716
+ }, pctx.span);
878
717
  while (true) {
879
- await this.systemDatabase.checkIfCanceled(wfCtx.workflowUUID);
718
+ await this.systemDatabase.checkIfCanceled(wfid);
880
719
  let txn_snapshot = 'invalid';
881
720
  let prevResultFound = false;
882
- const workflowUUID = wfCtx.workflowUUID;
883
721
  const wrappedTransaction = async (client) => {
884
- const tCtxt = new transaction_1.TransactionContextImpl(this.userDatabase.getName(), client, wfCtx, span, this.logger, funcId, txn.name);
885
722
  // If the UUID is preset, it is possible this execution previously happened. Check, and return its original result if it did.
886
723
  // Note: It is possible to retrieve a generated ID from a workflow handle, run a concurrent execution, and cause trouble for yourself. We recommend against this.
887
724
  let prevResult = exports.dbosNull;
888
725
  const queryFunc = (sql, args) => this.userDatabase.queryWithClient(client, sql, ...args);
889
- if (wfCtx.presetUUID) {
890
- const executionResult = await this.#checkExecution(queryFunc, workflowUUID, funcId, txn.name);
726
+ if (pctx.presetID) {
727
+ const executionResult = await this.#checkExecution(queryFunc, wfid, funcId, txn.name);
891
728
  prevResult = executionResult.result;
892
729
  txn_snapshot = executionResult.txn_snapshot;
893
730
  if (prevResult !== exports.dbosNull) {
894
731
  prevResultFound = true;
895
- tCtxt.span.setAttribute('cached', true);
896
- if (this.debugMode === DebugMode.TIME_TRAVEL) {
897
- // for time travel debugging, navigate the proxy to the time of this transaction's snapshot
898
- await queryFunc(`--proxy:${executionResult.txn_id ?? ''}:${txn_snapshot}`, []);
732
+ span.setAttribute('cached', true);
733
+ // Return/throw the previous result
734
+ if (prevResult instanceof Error) {
735
+ throw prevResult;
899
736
  }
900
737
  else {
901
- // otherwise, return/throw the previous result
902
- if (prevResult instanceof Error) {
903
- throw prevResult;
904
- }
905
- else {
906
- return prevResult;
907
- }
738
+ return prevResult;
908
739
  }
909
740
  }
910
741
  }
@@ -912,27 +743,29 @@ class DBOSExecutor {
912
743
  // Collect snapshot information for read-only transactions and non-preset UUID transactions, if not already collected above
913
744
  txn_snapshot = await DBOSExecutor.#retrieveSnapshot(queryFunc);
914
745
  }
915
- if (this.isDebugging && prevResult === exports.dbosNull) {
916
- throw new error_1.DBOSDebuggerError(`Failed to find the recorded output for the transaction: workflow UUID ${workflowUUID}, step number ${funcId}`);
746
+ if (this.debugMode && prevResult === exports.dbosNull) {
747
+ throw new error_1.DBOSDebuggerError(`Failed to find the recorded output for the transaction: workflow UUID ${wfid}, step number ${funcId}`);
917
748
  }
918
749
  // Execute the user's transaction.
919
750
  const result = await (async function () {
920
751
  try {
921
- return await (0, context_1.runWithTransactionContext)(tCtxt, async () => {
922
- if (txnInfo.registration.passContext) {
923
- return await txn.call(clsinst, tCtxt, ...args);
924
- }
925
- else {
926
- const tf = txn;
927
- return await tf.call(clsinst, ...args);
928
- }
752
+ return await (0, context_1.runWithParentContext)(pctx, {
753
+ authenticatedRoles: pctx?.authenticatedRoles,
754
+ authenticatedUser: pctx?.authenticatedUser,
755
+ workflowId: wfid,
756
+ curTxFunctionId: funcId,
757
+ parentCtx: pctx,
758
+ sqlClient: client,
759
+ }, async () => {
760
+ const tf = txn;
761
+ return await tf.call(clsinst, ...args);
929
762
  });
930
763
  }
931
764
  catch (e) {
932
765
  return e instanceof Error ? e : new Error(`${e}`);
933
766
  }
934
767
  })();
935
- if (this.isDebugging) {
768
+ if (this.debugMode) {
936
769
  if (prevResult instanceof Error) {
937
770
  throw prevResult;
938
771
  }
@@ -949,13 +782,13 @@ class DBOSExecutor {
949
782
  // Record the execution, commit, and return.
950
783
  try {
951
784
  // Synchronously record the output of write transactions and obtain the transaction ID.
952
- const pg_txn_id = await this.#recordOutput(queryFunc, wfCtx.workflowUUID, funcId, txn_snapshot, result, (error) => this.userDatabase.isKeyConflictError(error), txn.name);
953
- tCtxt.span.setAttribute('pg_txn_id', pg_txn_id);
785
+ const pg_txn_id = await this.#recordOutput(queryFunc, wfid, funcId, txn_snapshot, result, (error) => this.userDatabase.isKeyConflictError(error), txn.name);
786
+ span.setAttribute('pg_txn_id', pg_txn_id);
954
787
  }
955
788
  catch (error) {
956
789
  if (this.userDatabase.isFailedSqlTransactionError(error)) {
957
- this.logger.error(`Postgres aborted the ${txn.name} @DBOS.transaction of Workflow ${workflowUUID}, but the function did not raise an exception. Please ensure that the @DBOS.transaction method raises an exception if the database transaction is aborted.`);
958
- throw new error_1.DBOSFailedSqlTransactionError(workflowUUID, txn.name);
790
+ this.logger.error(`Postgres aborted the ${txn.name} @DBOS.transaction of Workflow ${wfid}, but the function did not raise an exception. Please ensure that the @DBOS.transaction method raises an exception if the database transaction is aborted.`);
791
+ throw new error_1.DBOSFailedSqlTransactionError(wfid, txn.name);
959
792
  }
960
793
  else {
961
794
  throw error;
@@ -964,7 +797,7 @@ class DBOSExecutor {
964
797
  return result;
965
798
  };
966
799
  try {
967
- const result = await this.userDatabase.transaction(wrappedTransaction, txnInfo.config);
800
+ const result = await this.userDatabase.transaction(wrappedTransaction, txnReg.txnConfig);
968
801
  span.setStatus({ code: api_1.SpanStatusCode.OK });
969
802
  this.tracer.endSpan(span);
970
803
  return result;
@@ -985,7 +818,7 @@ class DBOSExecutor {
985
818
  const e = err;
986
819
  await this.userDatabase.transaction(async (client) => {
987
820
  const func = (sql, args) => this.userDatabase.queryWithClient(client, sql, ...args);
988
- await this.#recordError(func, wfCtx.workflowUUID, funcId, txn_snapshot, e, (error) => this.userDatabase.isKeyConflictError(error), txn.name);
821
+ await this.#recordError(func, wfid, funcId, txn_snapshot, e, (error) => this.userDatabase.isKeyConflictError(error), txn.name);
989
822
  }, { isolationLevel: transaction_1.IsolationLevel.ReadCommitted });
990
823
  }
991
824
  span.setStatus({ code: api_1.SpanStatusCode.ERROR, message: e.message });
@@ -994,40 +827,42 @@ class DBOSExecutor {
994
827
  }
995
828
  }
996
829
  }
997
- async procedure(proc, params, ...args) {
830
+ async runProcedureTempWF(proc, params, ...args) {
998
831
  // Create a workflow and call procedure.
999
- const temp_workflow = async (ctxt, ...args) => {
1000
- const ctxtImpl = ctxt;
1001
- return this.callProcedureFunction(proc, ctxtImpl, ...args);
832
+ const temp_workflow = async (...args) => {
833
+ return this.callProcedureFunction(proc, ...args);
1002
834
  };
1003
835
  return await (await this.workflow(temp_workflow, {
1004
836
  ...params,
1005
837
  tempWfType: exports.TempWorkflowType.procedure,
1006
- tempWfName: (0, decorators_1.getRegisteredMethodName)(proc),
1007
- tempWfClass: (0, decorators_1.getRegisteredMethodClassName)(proc),
838
+ tempWfName: (0, decorators_1.getRegisteredFunctionName)(proc),
839
+ tempWfClass: (0, decorators_1.getRegisteredFunctionClassName)(proc),
1008
840
  }, ...args)).getResult();
1009
841
  }
1010
- async callProcedureFunction(proc, wfCtx, ...args) {
1011
- const procInfo = this.getProcedureInfo(proc);
1012
- if (procInfo === undefined) {
842
+ async callProcedureFunction(proc, ...args) {
843
+ const procInfo = (0, decorators_1.getFunctionRegistration)(proc);
844
+ if (!procInfo || !procInfo.procConfig) {
1013
845
  throw new error_1.DBOSNotRegisteredError(proc.name);
1014
846
  }
1015
- await this.systemDatabase.checkIfCanceled(wfCtx.workflowUUID);
1016
- const executeLocally = this.isDebugging || (procInfo.config.executeLocally ?? false);
1017
- const funcId = wfCtx.functionIDGetIncrement();
847
+ const procConfig = procInfo.procConfig;
848
+ const pctx = (0, context_1.getCurrentContextStore)();
849
+ const wfid = pctx.workflowId;
850
+ await this.systemDatabase.checkIfCanceled(wfid);
851
+ const executeLocally = this.debugMode || (procConfig.executeLocally ?? false);
852
+ const funcId = (0, context_1.functionIDGetIncrement)();
1018
853
  const span = this.tracer.startSpan(proc.name, {
1019
- operationUUID: wfCtx.workflowUUID,
854
+ operationUUID: wfid,
1020
855
  operationType: exports.OperationType.PROCEDURE,
1021
- authenticatedUser: wfCtx.authenticatedUser,
1022
- assumedRole: wfCtx.assumedRole,
1023
- authenticatedRoles: wfCtx.authenticatedRoles,
1024
- isolationLevel: procInfo.config.isolationLevel,
856
+ authenticatedUser: pctx.authenticatedUser,
857
+ assumedRole: pctx.assumedRole,
858
+ authenticatedRoles: pctx.authenticatedRoles,
859
+ isolationLevel: procConfig.isolationLevel,
1025
860
  executeLocally,
1026
- }, wfCtx.span);
861
+ }, pctx.span);
1027
862
  try {
1028
863
  const result = executeLocally
1029
- ? await this.#callProcedureFunctionLocal(proc, args, wfCtx, span, procInfo, funcId)
1030
- : await this.#callProcedureFunctionRemote(proc, args, wfCtx, span, procInfo.config, funcId);
864
+ ? await this.#callProcedureFunctionLocal(proc, args, span, procInfo, funcId)
865
+ : await this.#callProcedureFunctionRemote(proc, args, span, procConfig, funcId);
1031
866
  span.setStatus({ code: api_1.SpanStatusCode.OK });
1032
867
  return result;
1033
868
  }
@@ -1040,35 +875,30 @@ class DBOSExecutor {
1040
875
  this.tracer.endSpan(span);
1041
876
  }
1042
877
  }
1043
- async #callProcedureFunctionLocal(proc, args, wfCtx, span, procInfo, funcId) {
878
+ async #callProcedureFunctionLocal(proc, args, span, procInfo, funcId) {
1044
879
  let retryWaitMillis = 1;
1045
880
  const backoffFactor = 1.5;
1046
881
  const maxRetryWaitMs = 2000; // Maximum wait 2 seconds.
882
+ const pctx = (0, context_1.getCurrentContextStore)();
883
+ const wfid = pctx.workflowId;
1047
884
  while (true) {
1048
- await this.systemDatabase.checkIfCanceled(wfCtx.workflowUUID);
885
+ await this.systemDatabase.checkIfCanceled(wfid);
1049
886
  let txn_snapshot = 'invalid';
1050
887
  const wrappedProcedure = async (client) => {
1051
- const ctxt = new procedure_1.StoredProcedureContextImpl(client, wfCtx, span, this.logger, funcId, proc.name);
1052
888
  let prevResult = exports.dbosNull;
1053
889
  const queryFunc = (sql, args) => this.procedurePool.query(sql, args).then((v) => v.rows);
1054
- if (wfCtx.presetUUID) {
1055
- const executionResult = await this.#checkExecution(queryFunc, wfCtx.workflowUUID, funcId, wfCtx.operationName);
890
+ if (pctx.presetID) {
891
+ const executionResult = await this.#checkExecution(queryFunc, wfid, funcId, proc.name);
1056
892
  prevResult = executionResult.result;
1057
893
  txn_snapshot = executionResult.txn_snapshot;
1058
894
  if (prevResult !== exports.dbosNull) {
1059
- ctxt.span.setAttribute('cached', true);
1060
- if (this.debugMode === DebugMode.TIME_TRAVEL) {
1061
- // for time travel debugging, navigate the proxy to the time of this transaction's snapshot
1062
- await queryFunc(`--proxy:${executionResult.txn_id ?? ''}:${txn_snapshot}`, []);
895
+ span.setAttribute('cached', true);
896
+ // Return/throw the previous result
897
+ if (prevResult instanceof Error) {
898
+ throw prevResult;
1063
899
  }
1064
900
  else {
1065
- // otherwise, return/throw the previous result
1066
- if (prevResult instanceof Error) {
1067
- throw prevResult;
1068
- }
1069
- else {
1070
- return prevResult;
1071
- }
901
+ return prevResult;
1072
902
  }
1073
903
  }
1074
904
  }
@@ -1076,27 +906,33 @@ class DBOSExecutor {
1076
906
  // Collect snapshot information for read-only transactions and non-preset UUID transactions, if not already collected above
1077
907
  txn_snapshot = await DBOSExecutor.#retrieveSnapshot(queryFunc);
1078
908
  }
1079
- if (this.isDebugging && prevResult === exports.dbosNull) {
1080
- throw new error_1.DBOSDebuggerError(`Failed to find the recorded output for the procedure: workflow UUID ${wfCtx.workflowUUID}, step number ${funcId}`);
909
+ if (this.debugMode && prevResult === exports.dbosNull) {
910
+ throw new error_1.DBOSDebuggerError(`Failed to find the recorded output for the procedure: workflow UUID ${wfid}, step number ${funcId}`);
1081
911
  }
1082
912
  // Execute the user's transaction.
1083
913
  const result = await (async function () {
1084
914
  try {
1085
- return await (0, context_1.runWithStoredProcContext)(ctxt, async () => {
1086
- if (procInfo.registration.passContext) {
1087
- return await proc(ctxt, ...args);
1088
- }
1089
- else {
1090
- const pf = proc;
1091
- return await pf(...args);
1092
- }
915
+ // Check we are in a workflow context and not in a step / transaction already
916
+ const pctx = (0, context_1.getCurrentContextStore)();
917
+ if (!pctx)
918
+ throw new error_1.DBOSInvalidWorkflowTransitionError();
919
+ if (!(0, context_1.isInWorkflowCtx)(pctx))
920
+ throw new error_1.DBOSInvalidWorkflowTransitionError();
921
+ return await (0, context_1.runWithParentContext)(pctx, {
922
+ curTxFunctionId: funcId,
923
+ parentCtx: pctx,
924
+ isInStoredProc: true,
925
+ sqlClient: client,
926
+ }, async () => {
927
+ const pf = proc;
928
+ return await pf(...args);
1093
929
  });
1094
930
  }
1095
931
  catch (e) {
1096
932
  return e instanceof Error ? e : new Error(`${e}`);
1097
933
  }
1098
934
  })();
1099
- if (this.isDebugging) {
935
+ if (this.debugMode) {
1100
936
  if (prevResult instanceof Error) {
1101
937
  throw prevResult;
1102
938
  }
@@ -1112,20 +948,20 @@ class DBOSExecutor {
1112
948
  }
1113
949
  // Synchronously record the output of write transactions and obtain the transaction ID.
1114
950
  const func = (sql, args) => client.query(sql, args).then((v) => v.rows);
1115
- const pg_txn_id = await this.#recordOutput(func, wfCtx.workflowUUID, funcId, txn_snapshot, result, user_database_1.pgNodeIsKeyConflictError, wfCtx.operationName);
951
+ const pg_txn_id = await this.#recordOutput(func, wfid, funcId, txn_snapshot, result, user_database_1.pgNodeIsKeyConflictError, proc.name);
1116
952
  // const pg_txn_id = await wfCtx.recordOutputProc<R>(client, funcId, txn_snapshot, result);
1117
- ctxt.span.setAttribute('pg_txn_id', pg_txn_id);
953
+ span.setAttribute('pg_txn_id', pg_txn_id);
1118
954
  return result;
1119
955
  };
1120
956
  try {
1121
957
  const result = await this.invokeStoredProcFunction(wrappedProcedure, {
1122
- isolationLevel: procInfo.config.isolationLevel,
958
+ isolationLevel: procInfo.procConfig.isolationLevel,
1123
959
  });
1124
960
  span.setStatus({ code: api_1.SpanStatusCode.OK });
1125
961
  return result;
1126
962
  }
1127
963
  catch (err) {
1128
- if (!this.isDebugging) {
964
+ if (!this.debugMode) {
1129
965
  if (this.userDatabase.isRetriableTransactionError(err)) {
1130
966
  // serialization_failure in PostgreSQL
1131
967
  span.addEvent('TXN SERIALIZATION FAILURE', { retryWaitMillis: retryWaitMillis }, performance.now());
@@ -1139,32 +975,34 @@ class DBOSExecutor {
1139
975
  const e = err;
1140
976
  await this.invokeStoredProcFunction(async (client) => {
1141
977
  const func = (sql, args) => client.query(sql, args).then((v) => v.rows);
1142
- await this.#recordError(func, wfCtx.workflowUUID, funcId, txn_snapshot, e, user_database_1.pgNodeIsKeyConflictError, wfCtx.operationName);
978
+ await this.#recordError(func, wfid, funcId, txn_snapshot, e, user_database_1.pgNodeIsKeyConflictError, proc.name);
1143
979
  }, { isolationLevel: transaction_1.IsolationLevel.ReadCommitted });
1144
980
  await this.userDatabase.transaction(async (client) => {
1145
981
  const func = (sql, args) => this.userDatabase.queryWithClient(client, sql, ...args);
1146
- await this.#recordError(func, wfCtx.workflowUUID, funcId, txn_snapshot, e, (error) => this.userDatabase.isKeyConflictError(error), wfCtx.operationName);
982
+ await this.#recordError(func, wfid, funcId, txn_snapshot, e, (error) => this.userDatabase.isKeyConflictError(error), proc.name);
1147
983
  }, { isolationLevel: transaction_1.IsolationLevel.ReadCommitted });
1148
984
  }
1149
985
  throw err;
1150
986
  }
1151
987
  }
1152
988
  }
1153
- async #callProcedureFunctionRemote(proc, args, wfCtx, span, config, funcId) {
1154
- if (this.isDebugging) {
989
+ async #callProcedureFunctionRemote(proc, args, span, config, funcId) {
990
+ if (this.debugMode) {
1155
991
  throw new error_1.DBOSDebuggerError("Can't invoke stored procedure in debug mode.");
1156
992
  }
1157
- await this.systemDatabase.checkIfCanceled(wfCtx.workflowUUID);
993
+ const pctx = (0, context_1.getCurrentContextStore)();
994
+ const wfid = pctx.workflowId;
995
+ await this.systemDatabase.checkIfCanceled(wfid);
1158
996
  const $jsonCtx = {
1159
- request: wfCtx.request,
1160
- authenticatedUser: wfCtx.authenticatedUser,
1161
- authenticatedRoles: wfCtx.authenticatedRoles,
1162
- assumedRole: wfCtx.assumedRole,
997
+ request: pctx.request,
998
+ authenticatedUser: pctx.authenticatedUser,
999
+ authenticatedRoles: pctx.authenticatedRoles,
1000
+ assumedRole: pctx.assumedRole,
1163
1001
  };
1164
1002
  // TODO (Qian/Harry): remove this unshift when we remove the resultBuffer argument
1165
1003
  // Note, node-pg converts JS arrays to postgres array literals, so must call JSON.strigify on
1166
1004
  // args and bufferedResults before being passed to #invokeStoredProc
1167
- const $args = [wfCtx.workflowUUID, funcId, wfCtx.presetUUID, $jsonCtx, null, JSON.stringify(args)];
1005
+ const $args = [wfid, funcId, pctx.presetID, $jsonCtx, null, JSON.stringify(args)];
1168
1006
  const readonly = config.readOnly ?? false;
1169
1007
  if (!readonly) {
1170
1008
  $args.unshift(null);
@@ -1185,8 +1023,8 @@ class DBOSExecutor {
1185
1023
  async #invokeStoredProc(proc, args) {
1186
1024
  const client = await this.procedurePool.connect();
1187
1025
  const log = (msg) => this.#logNotice(msg);
1188
- const procClassName = this.getProcedureClassName(proc);
1189
- const plainProcName = `${procClassName}_${proc.name}_p`;
1026
+ const procname = (0, decorators_1.getRegisteredFunctionFullName)(proc);
1027
+ const plainProcName = `${procname.className}_${procname.name}_p`;
1190
1028
  const procName = utils_1.globalParams.wasComputed ? plainProcName : `v${utils_1.globalParams.appVersion}_${plainProcName}`;
1191
1029
  const sql = `CALL "${procName}"(${args.map((_v, i) => `$${i + 1}`).join()});`;
1192
1030
  try {
@@ -1219,106 +1057,98 @@ class DBOSExecutor {
1219
1057
  client.release();
1220
1058
  }
1221
1059
  }
1222
- async external(stepFn, params, ...args) {
1060
+ async runStepTempWF(stepFn, params, ...args) {
1223
1061
  return await (await this.startStepTempWF(stepFn, params, undefined, undefined, ...args)).getResult();
1224
1062
  }
1225
- async startStepTempWF(stepFn, params, callerUUID, callerFunctionID, ...args) {
1063
+ async startStepTempWF(stepFn, params, callerWFID, callerFunctionID, ...args) {
1226
1064
  // Create a workflow and call external.
1227
- const temp_workflow = async (ctxt, ...args) => {
1228
- const ctxtImpl = ctxt;
1229
- return await this.callStepFunction(stepFn, undefined, undefined, params.configuredInstance ?? null, ctxtImpl, ...args);
1065
+ const temp_workflow = async (...args) => {
1066
+ return await this.callStepFunction(stepFn, undefined, undefined, params.configuredInstance ?? null, ...args);
1230
1067
  };
1231
1068
  return await this.internalWorkflow(temp_workflow, {
1232
1069
  ...params,
1233
1070
  tempWfType: exports.TempWorkflowType.step,
1234
- tempWfName: (0, decorators_1.getRegisteredMethodName)(stepFn),
1235
- tempWfClass: (0, decorators_1.getRegisteredMethodClassName)(stepFn),
1236
- }, callerUUID, callerFunctionID, ...args);
1071
+ tempWfName: (0, decorators_1.getRegisteredFunctionName)(stepFn),
1072
+ tempWfClass: (0, decorators_1.getRegisteredFunctionClassName)(stepFn),
1073
+ }, callerWFID, callerFunctionID, ...args);
1237
1074
  }
1238
1075
  /**
1239
1076
  * Execute a step function.
1240
1077
  * If it encounters any error, retry according to its configured retry policy until the maximum number of attempts is reached, then throw an DBOSError.
1241
1078
  * The step may execute many times, but once it is complete, it will not re-execute.
1242
1079
  */
1243
- async callStepFunction(stepFn, stepFnName, stepConfig, clsInst, wfCtx, ...args) {
1080
+ async callStepFunction(stepFn, stepFnName, stepConfig, clsInst, ...args) {
1244
1081
  stepFnName = stepFnName ?? stepFn.name ?? '<unnamed>';
1245
- let passContext = false;
1246
1082
  if (!stepConfig) {
1247
- const stepReg = this.getStepInfo(stepFn);
1248
- stepConfig = stepReg?.config;
1249
- passContext = stepReg?.registration.passContext ?? true;
1083
+ const stepReg = (0, decorators_1.getFunctionRegistration)(stepFn);
1084
+ stepConfig = stepReg?.stepConfig;
1250
1085
  }
1251
1086
  if (stepConfig === undefined) {
1252
1087
  throw new error_1.DBOSNotRegisteredError(stepFnName);
1253
1088
  }
1254
- await this.systemDatabase.checkIfCanceled(wfCtx.workflowUUID);
1255
- const funcID = wfCtx.functionIDGetIncrement();
1089
+ const lctx = (0, context_1.getCurrentContextStore)();
1090
+ const wfid = lctx.workflowId;
1091
+ await this.systemDatabase.checkIfCanceled(wfid);
1092
+ const funcID = (0, context_1.functionIDGetIncrement)();
1256
1093
  const maxRetryIntervalSec = 3600; // Maximum retry interval: 1 hour
1257
1094
  const span = this.tracer.startSpan(stepFnName, {
1258
- operationUUID: wfCtx.workflowUUID,
1095
+ operationUUID: wfid,
1259
1096
  operationType: exports.OperationType.COMMUNICATOR,
1260
- authenticatedUser: wfCtx.authenticatedUser,
1261
- assumedRole: wfCtx.assumedRole,
1262
- authenticatedRoles: wfCtx.authenticatedRoles,
1097
+ authenticatedUser: lctx.authenticatedUser,
1098
+ assumedRole: lctx.assumedRole,
1099
+ authenticatedRoles: lctx.authenticatedRoles,
1263
1100
  retriesAllowed: stepConfig.retriesAllowed,
1264
1101
  intervalSeconds: stepConfig.intervalSeconds,
1265
1102
  maxAttempts: stepConfig.maxAttempts,
1266
1103
  backoffRate: stepConfig.backoffRate,
1267
- }, wfCtx.span);
1268
- const ctxt = new step_1.StepContextImpl(wfCtx, funcID, span, this.logger, stepConfig, stepFnName);
1104
+ }, lctx.span);
1269
1105
  // Check if this execution previously happened, returning its original result if it did.
1270
- const checkr = await this.systemDatabase.getOperationResultAndThrowIfCancelled(wfCtx.workflowUUID, ctxt.functionID);
1106
+ const checkr = await this.systemDatabase.getOperationResultAndThrowIfCancelled(wfid, funcID);
1271
1107
  if (checkr) {
1272
- if (checkr.functionName !== ctxt.operationName) {
1273
- throw new error_1.DBOSUnexpectedStepError(ctxt.workflowUUID, ctxt.functionID, ctxt.operationName, checkr.functionName ?? '?');
1108
+ if (checkr.functionName !== stepFnName) {
1109
+ throw new error_1.DBOSUnexpectedStepError(wfid, funcID, stepFnName, checkr.functionName ?? '?');
1274
1110
  }
1275
1111
  const check = DBOSExecutor.reviveResultOrError(checkr);
1276
- ctxt.span.setAttribute('cached', true);
1277
- ctxt.span.setStatus({ code: api_1.SpanStatusCode.OK });
1278
- this.tracer.endSpan(ctxt.span);
1112
+ span.setAttribute('cached', true);
1113
+ span.setStatus({ code: api_1.SpanStatusCode.OK });
1114
+ this.tracer.endSpan(span);
1279
1115
  return check;
1280
1116
  }
1281
- if (this.isDebugging) {
1282
- throw new error_1.DBOSDebuggerError(`Failed to find the recorded output for the step: workflow UUID: ${wfCtx.workflowUUID}, step number: ${funcID}`);
1117
+ if (this.debugMode) {
1118
+ throw new error_1.DBOSDebuggerError(`Failed to find the recorded output for the step: workflow UUID: ${wfid}, step number: ${funcID}`);
1283
1119
  }
1120
+ const maxAttempts = stepConfig.maxAttempts ?? 3;
1284
1121
  // Execute the step function. If it throws an exception, retry with exponential backoff.
1285
1122
  // After reaching the maximum number of retries, throw an DBOSError.
1286
1123
  let result = exports.dbosNull;
1287
1124
  let err = exports.dbosNull;
1288
1125
  const errors = [];
1289
- if (ctxt.retriesAllowed) {
1290
- let numAttempts = 0;
1291
- let intervalSeconds = ctxt.intervalSeconds;
1126
+ if (stepConfig.retriesAllowed) {
1127
+ let attemptNum = 0;
1128
+ let intervalSeconds = stepConfig.intervalSeconds ?? 1;
1292
1129
  if (intervalSeconds > maxRetryIntervalSec) {
1293
1130
  this.logger.warn(`Step config interval exceeds maximum allowed interval, capped to ${maxRetryIntervalSec} seconds!`);
1294
1131
  }
1295
- while (result === exports.dbosNull && numAttempts++ < ctxt.maxAttempts) {
1132
+ while (result === exports.dbosNull && attemptNum++ < (maxAttempts ?? 3)) {
1296
1133
  try {
1297
- await this.systemDatabase.checkIfCanceled(wfCtx.workflowUUID);
1134
+ await this.systemDatabase.checkIfCanceled(wfid);
1298
1135
  let cresult;
1299
- if (passContext) {
1300
- await (0, context_1.runWithStepContext)(ctxt, numAttempts, async () => {
1301
- cresult = await stepFn.call(clsInst, ctxt, ...args);
1302
- });
1303
- }
1304
- else {
1305
- await (0, context_1.runWithStepContext)(ctxt, numAttempts, async () => {
1306
- const sf = stepFn;
1307
- cresult = await sf.call(clsInst, ...args);
1308
- });
1309
- }
1136
+ await (0, context_1.runInStepContext)(lctx, funcID, maxAttempts, attemptNum, async () => {
1137
+ const sf = stepFn;
1138
+ cresult = await sf.call(clsInst, ...args);
1139
+ });
1310
1140
  result = cresult;
1311
1141
  }
1312
1142
  catch (error) {
1313
1143
  const e = error;
1314
1144
  errors.push(e);
1315
- this.logger.warn(`Error in step being automatically retried. Attempt ${numAttempts} of ${ctxt.maxAttempts}. ${e.stack}`);
1316
- span.addEvent(`Step attempt ${numAttempts + 1} failed`, { retryIntervalSeconds: intervalSeconds, error: error.message }, performance.now());
1317
- if (numAttempts < ctxt.maxAttempts) {
1145
+ this.logger.warn(`Error in step being automatically retried. Attempt ${attemptNum} of ${maxAttempts}. ${e.stack}`);
1146
+ span.addEvent(`Step attempt ${attemptNum + 1} failed`, { retryIntervalSeconds: intervalSeconds, error: error.message }, performance.now());
1147
+ if (attemptNum < maxAttempts) {
1318
1148
  // Sleep for an interval, then increase the interval by backoffRate.
1319
1149
  // Cap at the maximum allowed retry interval.
1320
1150
  await (0, utils_1.sleepms)(intervalSeconds * 1000);
1321
- intervalSeconds *= ctxt.backoffRate;
1151
+ intervalSeconds *= stepConfig.backoffRate ?? 2;
1322
1152
  intervalSeconds = intervalSeconds < maxRetryIntervalSec ? intervalSeconds : maxRetryIntervalSec;
1323
1153
  }
1324
1154
  }
@@ -1327,17 +1157,10 @@ class DBOSExecutor {
1327
1157
  else {
1328
1158
  try {
1329
1159
  let cresult;
1330
- if (passContext) {
1331
- await (0, context_1.runWithStepContext)(ctxt, undefined, async () => {
1332
- cresult = await stepFn.call(clsInst, ctxt, ...args);
1333
- });
1334
- }
1335
- else {
1336
- await (0, context_1.runWithStepContext)(ctxt, undefined, async () => {
1337
- const sf = stepFn;
1338
- cresult = await sf.call(clsInst, ...args);
1339
- });
1340
- }
1160
+ await (0, context_1.runInStepContext)(lctx, funcID, maxAttempts, undefined, async () => {
1161
+ const sf = stepFn;
1162
+ cresult = await sf.call(clsInst, ...args);
1163
+ });
1341
1164
  result = cresult;
1342
1165
  }
1343
1166
  catch (error) {
@@ -1347,35 +1170,37 @@ class DBOSExecutor {
1347
1170
  // `result` can only be dbosNull when the step timed out
1348
1171
  if (result === exports.dbosNull) {
1349
1172
  // Record the error, then throw it.
1350
- err = err === exports.dbosNull ? new error_1.DBOSMaxStepRetriesError(stepFnName, ctxt.maxAttempts, errors) : err;
1351
- await this.systemDatabase.recordOperationResult(wfCtx.workflowUUID, ctxt.functionID, ctxt.operationName, true, {
1173
+ err = err === exports.dbosNull ? new error_1.DBOSMaxStepRetriesError(stepFnName, maxAttempts, errors) : err;
1174
+ await this.systemDatabase.recordOperationResult(wfid, funcID, stepFnName, true, {
1352
1175
  error: utils_1.DBOSJSON.stringify((0, serialize_error_1.serializeError)(err)),
1353
1176
  });
1354
- ctxt.span.setStatus({ code: api_1.SpanStatusCode.ERROR, message: err.message });
1355
- this.tracer.endSpan(ctxt.span);
1177
+ span.setStatus({ code: api_1.SpanStatusCode.ERROR, message: err.message });
1178
+ this.tracer.endSpan(span);
1356
1179
  throw err;
1357
1180
  }
1358
1181
  else {
1359
1182
  // Record the execution and return.
1360
- await this.systemDatabase.recordOperationResult(wfCtx.workflowUUID, ctxt.functionID, ctxt.operationName, true, {
1183
+ await this.systemDatabase.recordOperationResult(wfid, funcID, stepFnName, true, {
1361
1184
  output: utils_1.DBOSJSON.stringify(result),
1362
1185
  });
1363
- ctxt.span.setStatus({ code: api_1.SpanStatusCode.OK });
1364
- this.tracer.endSpan(ctxt.span);
1186
+ span.setStatus({ code: api_1.SpanStatusCode.OK });
1187
+ this.tracer.endSpan(span);
1365
1188
  return result;
1366
1189
  }
1367
1190
  }
1368
- async send(destinationUUID, message, topic, idempotencyKey) {
1191
+ async runSendTempWF(destinationId, message, topic, idempotencyKey) {
1369
1192
  // Create a workflow and call send.
1370
- const temp_workflow = async (ctxt, destinationUUID, message, topic) => {
1371
- return await ctxt.send(destinationUUID, message, topic);
1193
+ const temp_workflow = async (destinationId, message, topic) => {
1194
+ const ctx = (0, context_1.getCurrentContextStore)();
1195
+ const functionID = (0, context_1.functionIDGetIncrement)();
1196
+ await this.systemDatabase.send(ctx.workflowId, functionID, destinationId, utils_1.DBOSJSON.stringify(message), topic);
1372
1197
  };
1373
- const workflowUUID = idempotencyKey ? destinationUUID + idempotencyKey : undefined;
1198
+ const workflowUUID = idempotencyKey ? destinationId + idempotencyKey : undefined;
1374
1199
  return (await this.workflow(temp_workflow, {
1375
1200
  workflowUUID: workflowUUID,
1376
1201
  tempWfType: exports.TempWorkflowType.send,
1377
1202
  configuredInstance: null,
1378
- }, destinationUUID, message, topic)).getResult();
1203
+ }, destinationId, message, topic)).getResult();
1379
1204
  }
1380
1205
  /**
1381
1206
  * Wait for a workflow to emit an event, then return its value.
@@ -1443,33 +1268,13 @@ class DBOSExecutor {
1443
1268
  return await this.userDatabase.query(sql);
1444
1269
  }
1445
1270
  }
1446
- async userDBListen(channels, callback) {
1447
- const notificationsClient = await this.procedurePool.connect();
1448
- for (const nname of channels) {
1449
- await notificationsClient.query(`LISTEN ${nname};`);
1450
- }
1451
- notificationsClient.on('notification', callback);
1452
- return {
1453
- close: async () => {
1454
- for (const nname of channels) {
1455
- try {
1456
- await notificationsClient.query(`UNLISTEN ${nname};`);
1457
- }
1458
- catch (e) {
1459
- this.logger.warn(e);
1460
- }
1461
- notificationsClient.release();
1462
- }
1463
- },
1464
- };
1465
- }
1466
1271
  /* INTERNAL HELPERS */
1467
1272
  /**
1468
1273
  * A recovery process that by default runs during executor init time.
1469
1274
  * It runs to completion all pending workflows that were executing when the previous executor failed.
1470
1275
  */
1471
1276
  async recoverPendingWorkflows(executorIDs = ['local']) {
1472
- if (this.isDebugging) {
1277
+ if (this.debugMode) {
1473
1278
  throw new error_1.DBOSDebuggerError('Cannot recover pending workflows in debug mode.');
1474
1279
  }
1475
1280
  const handlerArray = [];
@@ -1510,34 +1315,22 @@ class DBOSExecutor {
1510
1315
  this.scheduler = new scheduler_1.DBOSScheduler(this);
1511
1316
  this.scheduler.initScheduler();
1512
1317
  this.wfqEnded = wfqueue_1.wfQueueRunner.dispatchLoop(this);
1513
- for (const evtRcvr of this.eventReceivers) {
1514
- await evtRcvr.initialize(this);
1515
- }
1516
1318
  for (const lcl of (0, decorators_1.getLifecycleListeners)()) {
1517
- await lcl.initialize();
1319
+ await lcl.initialize?.();
1518
1320
  }
1519
1321
  }
1520
1322
  async deactivateEventReceivers(stopQueueThread = true) {
1521
1323
  this.logger.debug('Deactivating lifecycle listeners');
1522
1324
  for (const lcl of (0, decorators_1.getLifecycleListeners)()) {
1523
1325
  try {
1524
- await lcl.destroy();
1326
+ await lcl.destroy?.();
1525
1327
  }
1526
1328
  catch (err) {
1527
1329
  const e = err;
1528
1330
  this.logger.warn(`Error destroying lifecycle listener: ${e.message}`);
1529
1331
  }
1530
1332
  }
1531
- this.logger.debug('Deactivating event receivers');
1532
- for (const evtRcvr of this.eventReceivers || []) {
1533
- try {
1534
- await evtRcvr.destroy();
1535
- }
1536
- catch (err) {
1537
- const e = err;
1538
- this.logger.warn(`Error destroying event receiver: ${e.message}`);
1539
- }
1540
- }
1333
+ this.logger.debug('Deactivating scheduler');
1541
1334
  try {
1542
1335
  await this.scheduler?.destroyScheduler();
1543
1336
  }
@@ -1545,6 +1338,7 @@ class DBOSExecutor {
1545
1338
  const e = err;
1546
1339
  this.logger.warn(`Error destroying scheduler: ${e.message}`);
1547
1340
  }
1341
+ this.logger.debug('Deactivating queue runner');
1548
1342
  if (stopQueueThread) {
1549
1343
  try {
1550
1344
  wfqueue_1.wfQueueRunner.stop();
@@ -1567,67 +1361,72 @@ class DBOSExecutor {
1567
1361
  throw new error_1.DBOSError(`Failed to find inputs for workflow UUID: ${workflowID}`);
1568
1362
  }
1569
1363
  const inputs = utils_1.DBOSJSON.parse(wfStatus.input);
1570
- const parentCtx = this.#getRecoveryContext(workflowID, wfStatus);
1571
- const { wfInfo, configuredInst } = this.getWorkflowInfoByStatus(wfStatus);
1364
+ const recoverCtx = this.#getRecoveryContext(workflowID, wfStatus);
1365
+ const { methReg, configuredInst } = this.#getFunctionInfoFromWFStatus(wfStatus);
1572
1366
  // If starting a new workflow, assign a new UUID. Otherwise, use the workflow's original UUID.
1573
1367
  const workflowStartID = startNewWorkflow ? undefined : workflowID;
1574
- if (wfInfo) {
1575
- return this.workflow(wfInfo.workflow, {
1576
- workflowUUID: workflowStartID,
1577
- parentCtx: parentCtx,
1578
- configuredInstance: configuredInst,
1579
- queueName: wfStatus.queueName,
1580
- executeWorkflow: true,
1581
- deadlineEpochMS: wfStatus.deadlineEpochMS,
1582
- }, ...inputs);
1368
+ if (methReg?.workflowConfig) {
1369
+ return await (0, context_1.runWithTopContext)(recoverCtx, async () => {
1370
+ return await this.workflow(methReg.registeredFunction, {
1371
+ workflowUUID: workflowStartID,
1372
+ configuredInstance: configuredInst,
1373
+ queueName: wfStatus.queueName,
1374
+ executeWorkflow: true,
1375
+ deadlineEpochMS: wfStatus.deadlineEpochMS,
1376
+ }, ...inputs);
1377
+ });
1583
1378
  }
1584
1379
  // Should be temporary workflows. Parse the name of the workflow.
1585
1380
  const wfName = wfStatus.workflowName;
1586
1381
  const nameArr = wfName.split('-');
1587
1382
  if (!nameArr[0].startsWith(DBOSExecutor.tempWorkflowName)) {
1588
- // CB - Doesn't this happen if the user changed the function name in their code?
1589
- throw new error_1.DBOSError(`This should never happen! Cannot find workflow info for a non-temporary workflow! UUID ${workflowID}, name ${wfName}`);
1383
+ throw new error_1.DBOSError(`Cannot find workflow function for a non-temporary workflow, ID ${workflowID}, class '${wfStatus.workflowClassName}', function '${wfName}'; did you change your code?`);
1590
1384
  }
1591
- let temp_workflow;
1592
1385
  if (nameArr[1] === exports.TempWorkflowType.transaction) {
1593
- const { txnInfo, clsInst } = this.getTransactionInfoByNames(wfStatus.workflowClassName, nameArr[2], wfStatus.workflowConfigName);
1594
- if (!txnInfo) {
1595
- this.logger.error(`Cannot find transaction info for UUID ${workflowID}, name ${nameArr[2]}`);
1386
+ const txnReg = (0, decorators_1.getFunctionRegistrationByName)(wfStatus.workflowClassName, nameArr[2]);
1387
+ if (!txnReg?.txnConfig) {
1388
+ this.logger.error(`Cannot find transaction info for ID ${workflowID}, name ${nameArr[2]}`);
1596
1389
  throw new error_1.DBOSNotRegisteredError(nameArr[2]);
1597
1390
  }
1598
- return await this.startTransactionTempWF(txnInfo.transaction, {
1599
- workflowUUID: workflowStartID,
1600
- parentCtx: parentCtx ?? undefined,
1601
- configuredInstance: clsInst,
1602
- queueName: wfStatus.queueName,
1603
- executeWorkflow: true,
1604
- }, undefined, undefined, ...inputs);
1391
+ return await (0, context_1.runWithTopContext)(recoverCtx, async () => {
1392
+ return await this.startTransactionTempWF(txnReg.registeredFunction, {
1393
+ workflowUUID: workflowStartID,
1394
+ configuredInstance: configuredInst,
1395
+ queueName: wfStatus.queueName,
1396
+ executeWorkflow: true,
1397
+ }, undefined, undefined, ...inputs);
1398
+ });
1605
1399
  }
1606
1400
  else if (nameArr[1] === exports.TempWorkflowType.step) {
1607
- const { commInfo, clsInst } = this.getStepInfoByNames(wfStatus.workflowClassName, nameArr[2], wfStatus.workflowConfigName);
1608
- if (!commInfo) {
1609
- this.logger.error(`Cannot find step info for UUID ${workflowID}, name ${nameArr[2]}`);
1401
+ const stepReg = (0, decorators_1.getFunctionRegistrationByName)(wfStatus.workflowClassName, nameArr[2]);
1402
+ if (!stepReg?.stepConfig) {
1403
+ this.logger.error(`Cannot find step info for ID ${workflowID}, name ${nameArr[2]}`);
1610
1404
  throw new error_1.DBOSNotRegisteredError(nameArr[2]);
1611
1405
  }
1612
- return await this.startStepTempWF(commInfo.step, {
1613
- workflowUUID: workflowStartID,
1614
- parentCtx: parentCtx ?? undefined,
1615
- configuredInstance: clsInst,
1616
- queueName: wfStatus.queueName, // Probably null
1617
- executeWorkflow: true,
1618
- }, undefined, undefined, ...inputs);
1406
+ return await (0, context_1.runWithTopContext)(recoverCtx, async () => {
1407
+ return await this.startStepTempWF(stepReg.registeredFunction, {
1408
+ workflowUUID: workflowStartID,
1409
+ configuredInstance: configuredInst,
1410
+ queueName: wfStatus.queueName, // Probably null
1411
+ executeWorkflow: true,
1412
+ }, undefined, undefined, ...inputs);
1413
+ });
1619
1414
  }
1620
1415
  else if (nameArr[1] === exports.TempWorkflowType.send) {
1621
- temp_workflow = async (ctxt, ...args) => {
1622
- return await ctxt.send(args[0], args[1], args[2]); // id, value, topic
1416
+ const swf = async (destinationID, message, topic) => {
1417
+ const ctx = (0, context_1.getCurrentContextStore)();
1418
+ const functionID = (0, context_1.functionIDGetIncrement)();
1419
+ await this.systemDatabase.send(ctx.workflowId, functionID, destinationID, utils_1.DBOSJSON.stringify(message), topic);
1623
1420
  };
1624
- return this.workflow(temp_workflow, {
1625
- workflowUUID: workflowStartID,
1626
- parentCtx: parentCtx ?? undefined,
1627
- tempWfType: exports.TempWorkflowType.send,
1628
- queueName: wfStatus.queueName,
1629
- executeWorkflow: true,
1630
- }, ...inputs);
1421
+ const temp_workflow = swf;
1422
+ return await (0, context_1.runWithTopContext)(recoverCtx, async () => {
1423
+ return this.workflow(temp_workflow, {
1424
+ workflowUUID: workflowStartID,
1425
+ tempWfType: exports.TempWorkflowType.send,
1426
+ queueName: wfStatus.queueName,
1427
+ executeWorkflow: true,
1428
+ }, ...inputs);
1429
+ });
1631
1430
  }
1632
1431
  else {
1633
1432
  this.logger.error(`Unrecognized temporary workflow! UUID ${workflowID}, name ${wfName}`);
@@ -1640,14 +1439,13 @@ class DBOSExecutor {
1640
1439
  async upsertEventDispatchState(state) {
1641
1440
  return await this.systemDatabase.upsertEventDispatchState(state);
1642
1441
  }
1643
- #getRecoveryContext(workflowUUID, status) {
1442
+ #getRecoveryContext(_workflowID, status) {
1644
1443
  // Note: this doesn't inherit the original parent context's span.
1645
- const oc = new context_1.DBOSContextImpl(status.workflowName, undefined, this.logger);
1444
+ const oc = {};
1646
1445
  oc.request = status.request;
1647
1446
  oc.authenticatedUser = status.authenticatedUser;
1648
1447
  oc.authenticatedRoles = status.authenticatedRoles;
1649
1448
  oc.assumedRole = status.assumedRole;
1650
- oc.workflowUUID = workflowUUID;
1651
1449
  return oc;
1652
1450
  }
1653
1451
  async cancelWorkflow(workflowID) {
@@ -1671,7 +1469,7 @@ class DBOSExecutor {
1671
1469
  }
1672
1470
  logRegisteredHTTPUrls() {
1673
1471
  this.logger.info('HTTP endpoints supported:');
1674
- this.registeredOperations.forEach((registeredOperation) => {
1472
+ (0, decorators_1.getAllRegisteredFunctions)().forEach((registeredOperation) => {
1675
1473
  const ro = registeredOperation;
1676
1474
  if (ro.apiURL) {
1677
1475
  this.logger.info(' ' + ro.apiType.padEnd(6) + ' : ' + ro.apiURL);
@@ -1699,8 +1497,9 @@ class DBOSExecutor {
1699
1497
  */
1700
1498
  computeAppVersion() {
1701
1499
  const hasher = crypto.createHash('md5');
1702
- const sortedWorkflowSource = Array.from(this.workflowInfoMap.values())
1703
- .map((i) => i.workflowOrigFunction.toString())
1500
+ const sortedWorkflowSource = Array.from((0, decorators_1.getAllRegisteredFunctions)())
1501
+ .filter((e) => e.workflowConfig)
1502
+ .map((i) => i.origFunction.toString())
1704
1503
  .sort();
1705
1504
  // Different DBOS versions should produce different hashes.
1706
1505
  sortedWorkflowSource.push(utils_1.globalParams.dbosVersion);