@dbos-inc/dbos-sdk 3.0.23-preview → 3.0.29-preview

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 (88) 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/client.d.ts.map +1 -1
  6. package/dist/src/client.js.map +1 -1
  7. package/dist/src/context.d.ts +10 -44
  8. package/dist/src/context.d.ts.map +1 -1
  9. package/dist/src/context.js +34 -114
  10. package/dist/src/context.js.map +1 -1
  11. package/dist/src/datasource.d.ts +14 -3
  12. package/dist/src/datasource.d.ts.map +1 -1
  13. package/dist/src/datasource.js +41 -18
  14. package/dist/src/datasource.js.map +1 -1
  15. package/dist/src/dbos-executor.d.ts +43 -84
  16. package/dist/src/dbos-executor.d.ts.map +1 -1
  17. package/dist/src/dbos-executor.js +313 -500
  18. package/dist/src/dbos-executor.js.map +1 -1
  19. package/dist/src/dbos-runtime/cli.d.ts.map +1 -1
  20. package/dist/src/dbos-runtime/cli.js +1 -3
  21. package/dist/src/dbos-runtime/cli.js.map +1 -1
  22. package/dist/src/dbos-runtime/debug.d.ts +1 -1
  23. package/dist/src/dbos-runtime/debug.d.ts.map +1 -1
  24. package/dist/src/dbos-runtime/debug.js +2 -3
  25. package/dist/src/dbos-runtime/debug.js.map +1 -1
  26. package/dist/src/dbos-runtime/runtime.d.ts.map +1 -1
  27. package/dist/src/dbos-runtime/runtime.js +0 -9
  28. package/dist/src/dbos-runtime/runtime.js.map +1 -1
  29. package/dist/src/dbos.d.ts +11 -42
  30. package/dist/src/dbos.d.ts.map +1 -1
  31. package/dist/src/dbos.js +103 -284
  32. package/dist/src/dbos.js.map +1 -1
  33. package/dist/src/decorators.d.ts +33 -60
  34. package/dist/src/decorators.d.ts.map +1 -1
  35. package/dist/src/decorators.js +154 -190
  36. package/dist/src/decorators.js.map +1 -1
  37. package/dist/src/httpServer/handler.d.ts +1 -9
  38. package/dist/src/httpServer/handler.d.ts.map +1 -1
  39. package/dist/src/httpServer/handler.js +1 -1
  40. package/dist/src/httpServer/handler.js.map +1 -1
  41. package/dist/src/httpServer/middleware.d.ts +2 -2
  42. package/dist/src/httpServer/middleware.d.ts.map +1 -1
  43. package/dist/src/httpServer/server.d.ts +3 -3
  44. package/dist/src/httpServer/server.d.ts.map +1 -1
  45. package/dist/src/httpServer/server.js +23 -24
  46. package/dist/src/httpServer/server.js.map +1 -1
  47. package/dist/src/index.d.ts +5 -8
  48. package/dist/src/index.d.ts.map +1 -1
  49. package/dist/src/index.js +7 -17
  50. package/dist/src/index.js.map +1 -1
  51. package/dist/src/paramdecorators.d.ts.map +1 -1
  52. package/dist/src/paramdecorators.js +0 -6
  53. package/dist/src/paramdecorators.js.map +1 -1
  54. package/dist/src/procedure.d.ts +0 -22
  55. package/dist/src/procedure.d.ts.map +1 -1
  56. package/dist/src/procedure.js +0 -16
  57. package/dist/src/procedure.js.map +1 -1
  58. package/dist/src/scheduler/scheduler.d.ts.map +1 -1
  59. package/dist/src/scheduler/scheduler.js +3 -2
  60. package/dist/src/scheduler/scheduler.js.map +1 -1
  61. package/dist/src/step.d.ts +0 -25
  62. package/dist/src/step.d.ts.map +1 -1
  63. package/dist/src/step.js +0 -20
  64. package/dist/src/step.js.map +1 -1
  65. package/dist/src/system_database.d.ts +9 -10
  66. package/dist/src/system_database.d.ts.map +1 -1
  67. package/dist/src/system_database.js.map +1 -1
  68. package/dist/src/telemetry/logs.d.ts +4 -8
  69. package/dist/src/telemetry/logs.d.ts.map +1 -1
  70. package/dist/src/telemetry/logs.js +25 -13
  71. package/dist/src/telemetry/logs.js.map +1 -1
  72. package/dist/src/transaction.d.ts +0 -25
  73. package/dist/src/transaction.d.ts.map +1 -1
  74. package/dist/src/transaction.js +1 -15
  75. package/dist/src/transaction.js.map +1 -1
  76. package/dist/src/user_database.d.ts +2 -2
  77. package/dist/src/user_database.d.ts.map +1 -1
  78. package/dist/src/user_database.js.map +1 -1
  79. package/dist/src/workflow.d.ts +4 -148
  80. package/dist/src/workflow.d.ts.map +1 -1
  81. package/dist/src/workflow.js +7 -226
  82. package/dist/src/workflow.js.map +1 -1
  83. package/dist/tsconfig.tsbuildinfo +1 -1
  84. package/package.json +1 -1
  85. package/dist/src/eventreceiver.d.ts +0 -155
  86. package/dist/src/eventreceiver.d.ts.map +0 -1
  87. package/dist/src/eventreceiver.js +0 -3
  88. 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,17 +65,11 @@ 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',
79
71
  TRANSACTION: 'transaction',
80
- COMMUNICATOR: 'communicator',
72
+ STEP: 'step',
81
73
  PROCEDURE: 'procedure',
82
74
  };
83
75
  exports.TempWorkflowType = {
@@ -96,51 +88,16 @@ 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;
96
+ ctxLogger;
139
97
  tracer;
140
98
  // eslint-disable-next-line @typescript-eslint/no-unsafe-function-type
141
99
  typeormEntities = [];
142
100
  drizzleEntities = {};
143
- eventReceivers = [];
144
101
  scheduler = undefined;
145
102
  wfqEnded = undefined;
146
103
  executorID = utils_1.globalParams.executorID;
@@ -148,7 +105,7 @@ class DBOSExecutor {
148
105
  /* WORKFLOW EXECUTOR LIFE CYCLE MANAGEMENT */
149
106
  constructor(config, { systemDatabase, debugMode } = {}) {
150
107
  this.config = config;
151
- this.debugMode = debugMode ?? DebugMode.DISABLED;
108
+ this.debugMode = debugMode ?? false;
152
109
  // Set configured environment variables
153
110
  if (config.env) {
154
111
  for (const [key, value] of Object.entries(config.env)) {
@@ -169,8 +126,9 @@ class DBOSExecutor {
169
126
  this.telemetryCollector = new collector_1.TelemetryCollector();
170
127
  }
171
128
  this.logger = new logs_1.GlobalLogger(this.telemetryCollector, this.config.telemetry.logs);
129
+ this.ctxLogger = new logs_1.DBOSContextualLogger(this.logger, () => (0, context_1.getCurrentContextStore)().span);
172
130
  this.tracer = new traces_1.Tracer(this.telemetryCollector);
173
- if (this.isDebugging) {
131
+ if (this.debugMode) {
174
132
  this.logger.info('Running in debug mode!');
175
133
  }
176
134
  this.procedurePool = new pg_1.Pool(this.config.poolConfig);
@@ -253,39 +211,6 @@ class DBOSExecutor {
253
211
  this.logger.debug('Loaded Postgres user database');
254
212
  }
255
213
  }
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
214
  async init(classes) {
290
215
  if (this.initialized) {
291
216
  this.logger.error('Workflow executor already initialized!');
@@ -318,7 +243,7 @@ class DBOSExecutor {
318
243
  }
319
244
  this.logger.debug(`Loaded ${length} ORM entities`);
320
245
  }
321
- if (!this.isDebugging) {
246
+ if (!this.debugMode) {
322
247
  await (0, user_database_1.createDBIfDoesNotExist)(this.config.poolConfig, this.logger);
323
248
  }
324
249
  this.configureDbClient();
@@ -326,12 +251,9 @@ class DBOSExecutor {
326
251
  this.logger.error('No user database configured!');
327
252
  throw new error_1.DBOSInitializationError('No user database configured!');
328
253
  }
329
- for (const cls of classnames) {
330
- this.#registerClass(cls);
331
- }
332
254
  // 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) {
255
+ await this.userDatabase.init(this.debugMode);
256
+ if (!this.debugMode) {
335
257
  await this.systemDatabase.init();
336
258
  }
337
259
  }
@@ -354,7 +276,7 @@ class DBOSExecutor {
354
276
  }
355
277
  this.initialized = true;
356
278
  // Only execute init code if under non-debug mode
357
- if (!this.isDebugging) {
279
+ if (!this.debugMode) {
358
280
  for (const cls of classnames) {
359
281
  // Init its configurations
360
282
  const creg = (0, decorators_1.getClassRegistrationByName)(cls);
@@ -362,7 +284,7 @@ class DBOSExecutor {
362
284
  await cfg.initialize(new _1.InitContext());
363
285
  }
364
286
  }
365
- for (const v of this.registeredOperations) {
287
+ for (const v of (0, decorators_1.getAllRegisteredFunctions)()) {
366
288
  const m = v;
367
289
  if (m.init === true) {
368
290
  this.logger.debug('Executing init method: ' + m.name);
@@ -422,109 +344,11 @@ class DBOSExecutor {
422
344
  throw err;
423
345
  }
424
346
  }
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}`);
347
+ // This could return WF, or the function underlying a temp wf
348
+ #getFunctionInfoFromWFStatus(wf) {
349
+ const methReg = (0, decorators_1.getFunctionRegistrationByName)(wf.workflowClassName, wf.workflowName);
350
+ return { methReg, configuredInst: (0, decorators_1.getConfiguredInstance)(wf.workflowClassName, wf.workflowConfigName) };
457
351
  }
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
352
  static reviveResultOrError(r, success) {
529
353
  if (success === true || !r.error) {
530
354
  return utils_1.DBOSJSON.parse(r.output ?? null);
@@ -536,7 +360,7 @@ class DBOSExecutor {
536
360
  async workflow(wf, params, ...args) {
537
361
  return this.internalWorkflow(wf, params, undefined, undefined, ...args);
538
362
  }
539
- // If callerUUID and functionID are set, it means the workflow is invoked from within a workflow.
363
+ // If callerWFID and functionID are set, it means the workflow is invoked from within a workflow.
540
364
  async internalWorkflow(wf, params, callerID, callerFunctionID, ...args) {
541
365
  const workflowID = params.workflowUUID ? params.workflowUUID : (0, node_crypto_1.randomUUID)();
542
366
  const presetID = params.workflowUUID ? true : false;
@@ -560,29 +384,43 @@ class DBOSExecutor {
560
384
  this.logger.warn(`Priority is not enabled for queue ${params.queueName}. Setting priority will not have any effect.`);
561
385
  }
562
386
  }
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);
387
+ const pctx = (0, context_1.getCurrentContextStore)();
388
+ let wConfig = {};
389
+ const wInfo = (0, decorators_1.getFunctionRegistration)(wf);
390
+ if (wf.name !== DBOSExecutor.tempWorkflowName) {
391
+ if (!wInfo || !wInfo.workflowConfig) {
392
+ throw new error_1.DBOSNotRegisteredError(wf.name);
393
+ }
394
+ wConfig = wInfo.workflowConfig;
395
+ }
396
+ const maxRecoveryAttempts = wConfig.maxRecoveryAttempts ? wConfig.maxRecoveryAttempts : 50;
397
+ const wfname = wf.name; // TODO: Should be what was registered in wfInfo...
398
+ const span = this.tracer.startSpan(wfname, {
399
+ status: workflow_1.StatusString.PENDING,
400
+ operationUUID: workflowID,
401
+ operationType: exports.OperationType.WORKFLOW,
402
+ operationName: wInfo?.name ?? wf.name,
403
+ authenticatedUser: pctx?.authenticatedUser ?? '',
404
+ authenticatedRoles: pctx?.authenticatedRoles ?? [],
405
+ assumedRole: pctx?.assumedRole ?? '',
406
+ }, pctx?.span);
407
+ const isTempWorkflow = DBOSExecutor.tempWorkflowName === wfname;
570
408
  const internalStatus = {
571
409
  workflowUUID: workflowID,
572
410
  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),
411
+ workflowName: (0, decorators_1.getRegisteredFunctionName)(wf),
412
+ workflowClassName: isTempWorkflow ? '' : (0, decorators_1.getRegisteredFunctionClassName)(wf),
575
413
  workflowConfigName: params.configuredInstance?.name || '',
576
414
  queueName: params.queueName,
577
- authenticatedUser: wCtxt.authenticatedUser,
578
415
  output: null,
579
416
  error: null,
580
- assumedRole: wCtxt.assumedRole,
581
- authenticatedRoles: wCtxt.authenticatedRoles,
582
- request: wCtxt.request,
583
- executorId: wCtxt.executorID,
417
+ authenticatedUser: pctx?.authenticatedUser || '',
418
+ assumedRole: pctx?.assumedRole || '',
419
+ authenticatedRoles: pctx?.authenticatedRoles || [],
420
+ request: pctx?.request || {},
421
+ executorId: utils_1.globalParams.executorID,
584
422
  applicationVersion: utils_1.globalParams.appVersion,
585
- applicationID: wCtxt.applicationID,
423
+ applicationID: utils_1.globalParams.appID,
586
424
  createdAt: Date.now(), // Remember the start time of this workflow,
587
425
  timeoutMS: timeoutMS,
588
426
  deadlineEpochMS: deadlineEpochMS,
@@ -590,15 +428,15 @@ class DBOSExecutor {
590
428
  deduplicationID: params.enqueueOptions?.deduplicationID,
591
429
  priority: priority ?? 0,
592
430
  };
593
- if (wCtxt.isTempWorkflow) {
594
- internalStatus.workflowName = `${DBOSExecutor.tempWorkflowName}-${wCtxt.tempWfOperationType}-${wCtxt.tempWfOperationName}`;
431
+ if (isTempWorkflow) {
432
+ internalStatus.workflowName = `${DBOSExecutor.tempWorkflowName}-${params.tempWfType}-${params.tempWfName}`;
595
433
  internalStatus.workflowClassName = params.tempWfClass ?? '';
596
434
  }
597
435
  let status = undefined;
598
436
  let $deadlineEpochMS = undefined;
599
437
  // Synchronously set the workflow's status to PENDING and record workflow inputs.
600
438
  // 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) {
439
+ if (this.debugMode) {
602
440
  const wfStatus = await this.systemDatabase.getWorkflowStatus(workflowID);
603
441
  if (!wfStatus) {
604
442
  throw new error_1.DBOSDebuggerError(`Failed to find inputs for workflow UUID ${workflowID}`);
@@ -616,7 +454,7 @@ class DBOSExecutor {
616
454
  return new workflow_1.RetrievedHandle(this.systemDatabase, result.childWorkflowID, callerID, callerFunctionID);
617
455
  }
618
456
  }
619
- const ires = await this.systemDatabase.initWorkflowStatus(internalStatus, wCtxt.maxRecoveryAttempts);
457
+ const ires = await this.systemDatabase.initWorkflowStatus(internalStatus, maxRecoveryAttempts);
620
458
  if (callerFunctionID !== undefined && callerID !== undefined) {
621
459
  await this.systemDatabase.recordOperationResult(callerID, callerFunctionID, internalStatus.workflowName, true, {
622
460
  childWorkflowID: workflowID,
@@ -654,19 +492,24 @@ class DBOSExecutor {
654
492
  e.dbos_already_logged = true;
655
493
  internalStatus.error = utils_1.DBOSJSON.stringify((0, serialize_error_1.serializeError)(e));
656
494
  internalStatus.status = workflow_1.StatusString.ERROR;
657
- if (!exec.isDebugging) {
495
+ if (!exec.debugMode) {
658
496
  await exec.systemDatabase.recordWorkflowError(workflowID, internalStatus);
659
497
  }
660
- wCtxt.span.setStatus({ code: api_1.SpanStatusCode.ERROR, message: e.message });
498
+ span.setStatus({ code: api_1.SpanStatusCode.ERROR, message: e.message });
661
499
  }
662
500
  const runWorkflow = async () => {
663
501
  let result;
664
502
  // Execute the workflow.
665
503
  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);
504
+ const callResult = await (0, context_1.runWithParentContext)(pctx, {
505
+ presetID,
506
+ timeoutMS,
507
+ deadlineEpochMS,
508
+ workflowId: workflowID,
509
+ span,
510
+ logger: this.ctxLogger,
511
+ }, () => {
512
+ const callPromise = wf.call(params.configuredInstance, ...args);
670
513
  if ($deadlineEpochMS === undefined) {
671
514
  return callPromise;
672
515
  }
@@ -674,7 +517,7 @@ class DBOSExecutor {
674
517
  return callPromiseWithTimeout(callPromise, $deadlineEpochMS, this.systemDatabase);
675
518
  }
676
519
  });
677
- if (this.isDebugging) {
520
+ if (this.debugMode) {
678
521
  const recordedResult = DBOSExecutor.reviveResultOrError((await this.systemDatabase.awaitWorkflowResult(workflowID)));
679
522
  if (!resultsMatch(recordedResult, callResult)) {
680
523
  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 +535,21 @@ class DBOSExecutor {
692
535
  }
693
536
  internalStatus.output = utils_1.DBOSJSON.stringify(result);
694
537
  internalStatus.status = workflow_1.StatusString.SUCCESS;
695
- if (!this.isDebugging) {
538
+ if (!this.debugMode) {
696
539
  await this.systemDatabase.recordWorkflowOutput(workflowID, internalStatus);
697
540
  }
698
- wCtxt.span.setStatus({ code: api_1.SpanStatusCode.OK });
541
+ span.setStatus({ code: api_1.SpanStatusCode.OK });
699
542
  }
700
543
  catch (err) {
701
544
  if (err instanceof error_1.DBOSWorkflowConflictError) {
702
545
  // Retrieve the handle and wait for the result.
703
546
  const retrievedHandle = this.retrieveWorkflow(workflowID);
704
547
  result = await retrievedHandle.getResult();
705
- wCtxt.span.setAttribute('cached', true);
706
- wCtxt.span.setStatus({ code: api_1.SpanStatusCode.OK });
548
+ span.setAttribute('cached', true);
549
+ span.setStatus({ code: api_1.SpanStatusCode.OK });
707
550
  }
708
551
  else if (err instanceof error_1.DBOSWorkflowCancelledError) {
709
- wCtxt.span.setStatus({ code: api_1.SpanStatusCode.ERROR, message: err.message });
552
+ span.setStatus({ code: api_1.SpanStatusCode.ERROR, message: err.message });
710
553
  internalStatus.error = err.message;
711
554
  if (err.workflowID === workflowID) {
712
555
  internalStatus.status = workflow_1.StatusString.CANCELLED;
@@ -724,11 +567,11 @@ class DBOSExecutor {
724
567
  }
725
568
  }
726
569
  finally {
727
- this.tracer.endSpan(wCtxt.span);
570
+ this.tracer.endSpan(span);
728
571
  }
729
572
  return result;
730
573
  };
731
- if (this.isDebugging ||
574
+ if (this.debugMode ||
732
575
  (status !== 'SUCCESS' && status !== 'ERROR' && (params.queueName === undefined || params.executeWorkflow))) {
733
576
  const workflowPromise = runWorkflow();
734
577
  this.systemDatabase.registerRunningWorkflow(workflowID, workflowPromise);
@@ -794,7 +637,7 @@ class DBOSExecutor {
794
637
  * Write a operation's output to the database.
795
638
  */
796
639
  async #recordOutput(query, workflowUUID, funcID, txnSnapshot, output, isKeyConflict, function_name) {
797
- if (this.isDebugging) {
640
+ if (this.debugMode) {
798
641
  throw new error_1.DBOSDebuggerError('Cannot record output in debug mode.');
799
642
  }
800
643
  try {
@@ -816,7 +659,7 @@ class DBOSExecutor {
816
659
  * Record an error in an operation to the database.
817
660
  */
818
661
  async #recordError(query, workflowUUID, funcID, txnSnapshot, err, isKeyConflict, function_name) {
819
- if (this.isDebugging) {
662
+ if (this.debugMode) {
820
663
  throw new error_1.DBOSDebuggerError('Cannot record error in debug mode.');
821
664
  }
822
665
  try {
@@ -841,70 +684,64 @@ class DBOSExecutor {
841
684
  }
842
685
  return rows;
843
686
  }
844
- async transaction(txn, params, ...args) {
687
+ async runTransactionTempWF(txn, params, ...args) {
845
688
  return await (await this.startTransactionTempWF(txn, params, undefined, undefined, ...args)).getResult();
846
689
  }
847
- async startTransactionTempWF(txn, params, callerUUID, callerFunctionID, ...args) {
690
+ async startTransactionTempWF(txn, params, callerWFID, callerFunctionID, ...args) {
848
691
  // 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);
692
+ const temp_workflow = async (...args) => {
693
+ return await this.callTransactionFunction(txn, params.configuredInstance ?? null, ...args);
852
694
  };
853
695
  return await this.internalWorkflow(temp_workflow, {
854
696
  ...params,
855
697
  tempWfType: exports.TempWorkflowType.transaction,
856
- tempWfName: (0, decorators_1.getRegisteredMethodName)(txn),
857
- tempWfClass: (0, decorators_1.getRegisteredMethodClassName)(txn),
858
- }, callerUUID, callerFunctionID, ...args);
698
+ tempWfName: (0, decorators_1.getRegisteredFunctionName)(txn),
699
+ tempWfClass: (0, decorators_1.getRegisteredFunctionClassName)(txn),
700
+ }, callerWFID, callerFunctionID, ...args);
859
701
  }
860
- async callTransactionFunction(txn, clsinst, wfCtx, ...args) {
861
- const txnInfo = this.getTransactionInfo(txn);
862
- if (txnInfo === undefined) {
702
+ async callTransactionFunction(txn, clsinst, ...args) {
703
+ const txnReg = (0, decorators_1.getFunctionRegistration)(txn);
704
+ if (!txnReg || !txnReg.txnConfig) {
863
705
  throw new error_1.DBOSNotRegisteredError(txn.name);
864
706
  }
865
- await this.systemDatabase.checkIfCanceled(wfCtx.workflowUUID);
707
+ const pctx = (0, context_1.getCurrentContextStore)();
708
+ const wfid = pctx.workflowId;
709
+ await this.systemDatabase.checkIfCanceled(wfid);
866
710
  let retryWaitMillis = 1;
867
711
  const backoffFactor = 1.5;
868
712
  const maxRetryWaitMs = 2000; // Maximum wait 2 seconds.
869
- const funcId = wfCtx.functionIDGetIncrement();
713
+ const funcId = (0, context_1.functionIDGetIncrement)();
870
714
  const span = this.tracer.startSpan(txn.name, {
871
- operationUUID: wfCtx.workflowUUID,
715
+ operationUUID: wfid,
872
716
  operationType: exports.OperationType.TRANSACTION,
873
- authenticatedUser: wfCtx.authenticatedUser,
874
- assumedRole: wfCtx.assumedRole,
875
- authenticatedRoles: wfCtx.authenticatedRoles,
876
- isolationLevel: txnInfo.config.isolationLevel,
877
- }, wfCtx.span);
717
+ operationName: txn.name,
718
+ authenticatedUser: pctx.authenticatedUser ?? '',
719
+ assumedRole: pctx.assumedRole ?? '',
720
+ authenticatedRoles: pctx.authenticatedRoles ?? [],
721
+ isolationLevel: txnReg.txnConfig.isolationLevel,
722
+ }, pctx.span);
878
723
  while (true) {
879
- await this.systemDatabase.checkIfCanceled(wfCtx.workflowUUID);
724
+ await this.systemDatabase.checkIfCanceled(wfid);
880
725
  let txn_snapshot = 'invalid';
881
726
  let prevResultFound = false;
882
- const workflowUUID = wfCtx.workflowUUID;
883
727
  const wrappedTransaction = async (client) => {
884
- const tCtxt = new transaction_1.TransactionContextImpl(this.userDatabase.getName(), client, wfCtx, span, this.logger, funcId, txn.name);
885
728
  // If the UUID is preset, it is possible this execution previously happened. Check, and return its original result if it did.
886
729
  // 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
730
  let prevResult = exports.dbosNull;
888
731
  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);
732
+ if (pctx.presetID) {
733
+ const executionResult = await this.#checkExecution(queryFunc, wfid, funcId, txn.name);
891
734
  prevResult = executionResult.result;
892
735
  txn_snapshot = executionResult.txn_snapshot;
893
736
  if (prevResult !== exports.dbosNull) {
894
737
  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}`, []);
738
+ span.setAttribute('cached', true);
739
+ // Return/throw the previous result
740
+ if (prevResult instanceof Error) {
741
+ throw prevResult;
899
742
  }
900
743
  else {
901
- // otherwise, return/throw the previous result
902
- if (prevResult instanceof Error) {
903
- throw prevResult;
904
- }
905
- else {
906
- return prevResult;
907
- }
744
+ return prevResult;
908
745
  }
909
746
  }
910
747
  }
@@ -912,27 +749,32 @@ class DBOSExecutor {
912
749
  // Collect snapshot information for read-only transactions and non-preset UUID transactions, if not already collected above
913
750
  txn_snapshot = await DBOSExecutor.#retrieveSnapshot(queryFunc);
914
751
  }
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}`);
752
+ if (this.debugMode && prevResult === exports.dbosNull) {
753
+ throw new error_1.DBOSDebuggerError(`Failed to find the recorded output for the transaction: workflow UUID ${wfid}, step number ${funcId}`);
917
754
  }
918
755
  // Execute the user's transaction.
756
+ const ctxlog = this.ctxLogger;
919
757
  const result = await (async function () {
920
758
  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
- }
759
+ return await (0, context_1.runWithParentContext)(pctx, {
760
+ authenticatedRoles: pctx?.authenticatedRoles,
761
+ authenticatedUser: pctx?.authenticatedUser,
762
+ workflowId: wfid,
763
+ curTxFunctionId: funcId,
764
+ parentCtx: pctx,
765
+ sqlClient: client,
766
+ logger: ctxlog,
767
+ span,
768
+ }, async () => {
769
+ const tf = txn;
770
+ return await tf.call(clsinst, ...args);
929
771
  });
930
772
  }
931
773
  catch (e) {
932
774
  return e instanceof Error ? e : new Error(`${e}`);
933
775
  }
934
776
  })();
935
- if (this.isDebugging) {
777
+ if (this.debugMode) {
936
778
  if (prevResult instanceof Error) {
937
779
  throw prevResult;
938
780
  }
@@ -949,13 +791,13 @@ class DBOSExecutor {
949
791
  // Record the execution, commit, and return.
950
792
  try {
951
793
  // 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);
794
+ const pg_txn_id = await this.#recordOutput(queryFunc, wfid, funcId, txn_snapshot, result, (error) => this.userDatabase.isKeyConflictError(error), txn.name);
795
+ span.setAttribute('pg_txn_id', pg_txn_id);
954
796
  }
955
797
  catch (error) {
956
798
  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);
799
+ 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.`);
800
+ throw new error_1.DBOSFailedSqlTransactionError(wfid, txn.name);
959
801
  }
960
802
  else {
961
803
  throw error;
@@ -964,7 +806,7 @@ class DBOSExecutor {
964
806
  return result;
965
807
  };
966
808
  try {
967
- const result = await this.userDatabase.transaction(wrappedTransaction, txnInfo.config);
809
+ const result = await this.userDatabase.transaction(wrappedTransaction, txnReg.txnConfig);
968
810
  span.setStatus({ code: api_1.SpanStatusCode.OK });
969
811
  this.tracer.endSpan(span);
970
812
  return result;
@@ -985,7 +827,7 @@ class DBOSExecutor {
985
827
  const e = err;
986
828
  await this.userDatabase.transaction(async (client) => {
987
829
  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);
830
+ await this.#recordError(func, wfid, funcId, txn_snapshot, e, (error) => this.userDatabase.isKeyConflictError(error), txn.name);
989
831
  }, { isolationLevel: transaction_1.IsolationLevel.ReadCommitted });
990
832
  }
991
833
  span.setStatus({ code: api_1.SpanStatusCode.ERROR, message: e.message });
@@ -994,40 +836,43 @@ class DBOSExecutor {
994
836
  }
995
837
  }
996
838
  }
997
- async procedure(proc, params, ...args) {
839
+ async runProcedureTempWF(proc, params, ...args) {
998
840
  // Create a workflow and call procedure.
999
- const temp_workflow = async (ctxt, ...args) => {
1000
- const ctxtImpl = ctxt;
1001
- return this.callProcedureFunction(proc, ctxtImpl, ...args);
841
+ const temp_workflow = async (...args) => {
842
+ return this.callProcedureFunction(proc, ...args);
1002
843
  };
1003
844
  return await (await this.workflow(temp_workflow, {
1004
845
  ...params,
1005
846
  tempWfType: exports.TempWorkflowType.procedure,
1006
- tempWfName: (0, decorators_1.getRegisteredMethodName)(proc),
1007
- tempWfClass: (0, decorators_1.getRegisteredMethodClassName)(proc),
847
+ tempWfName: (0, decorators_1.getRegisteredFunctionName)(proc),
848
+ tempWfClass: (0, decorators_1.getRegisteredFunctionClassName)(proc),
1008
849
  }, ...args)).getResult();
1009
850
  }
1010
- async callProcedureFunction(proc, wfCtx, ...args) {
1011
- const procInfo = this.getProcedureInfo(proc);
1012
- if (procInfo === undefined) {
851
+ async callProcedureFunction(proc, ...args) {
852
+ const procInfo = (0, decorators_1.getFunctionRegistration)(proc);
853
+ if (!procInfo || !procInfo.procConfig) {
1013
854
  throw new error_1.DBOSNotRegisteredError(proc.name);
1014
855
  }
1015
- await this.systemDatabase.checkIfCanceled(wfCtx.workflowUUID);
1016
- const executeLocally = this.isDebugging || (procInfo.config.executeLocally ?? false);
1017
- const funcId = wfCtx.functionIDGetIncrement();
856
+ const procConfig = procInfo.procConfig;
857
+ const pctx = (0, context_1.getCurrentContextStore)();
858
+ const wfid = pctx.workflowId;
859
+ await this.systemDatabase.checkIfCanceled(wfid);
860
+ const executeLocally = this.debugMode || (procConfig.executeLocally ?? false);
861
+ const funcId = (0, context_1.functionIDGetIncrement)();
1018
862
  const span = this.tracer.startSpan(proc.name, {
1019
- operationUUID: wfCtx.workflowUUID,
863
+ operationUUID: wfid,
1020
864
  operationType: exports.OperationType.PROCEDURE,
1021
- authenticatedUser: wfCtx.authenticatedUser,
1022
- assumedRole: wfCtx.assumedRole,
1023
- authenticatedRoles: wfCtx.authenticatedRoles,
1024
- isolationLevel: procInfo.config.isolationLevel,
865
+ operationName: proc.name,
866
+ authenticatedUser: pctx.authenticatedUser ?? '',
867
+ assumedRole: pctx.assumedRole ?? '',
868
+ authenticatedRoles: pctx.authenticatedRoles ?? [],
869
+ isolationLevel: procInfo.procConfig.isolationLevel,
1025
870
  executeLocally,
1026
- }, wfCtx.span);
871
+ }, pctx.span);
1027
872
  try {
1028
873
  const result = executeLocally
1029
- ? await this.#callProcedureFunctionLocal(proc, args, wfCtx, span, procInfo, funcId)
1030
- : await this.#callProcedureFunctionRemote(proc, args, wfCtx, span, procInfo.config, funcId);
874
+ ? await this.#callProcedureFunctionLocal(proc, args, span, procInfo, funcId)
875
+ : await this.#callProcedureFunctionRemote(proc, args, span, procConfig, funcId);
1031
876
  span.setStatus({ code: api_1.SpanStatusCode.OK });
1032
877
  return result;
1033
878
  }
@@ -1040,35 +885,30 @@ class DBOSExecutor {
1040
885
  this.tracer.endSpan(span);
1041
886
  }
1042
887
  }
1043
- async #callProcedureFunctionLocal(proc, args, wfCtx, span, procInfo, funcId) {
888
+ async #callProcedureFunctionLocal(proc, args, span, procInfo, funcId) {
1044
889
  let retryWaitMillis = 1;
1045
890
  const backoffFactor = 1.5;
1046
891
  const maxRetryWaitMs = 2000; // Maximum wait 2 seconds.
892
+ const pctx = (0, context_1.getCurrentContextStore)();
893
+ const wfid = pctx.workflowId;
1047
894
  while (true) {
1048
- await this.systemDatabase.checkIfCanceled(wfCtx.workflowUUID);
895
+ await this.systemDatabase.checkIfCanceled(wfid);
1049
896
  let txn_snapshot = 'invalid';
1050
897
  const wrappedProcedure = async (client) => {
1051
- const ctxt = new procedure_1.StoredProcedureContextImpl(client, wfCtx, span, this.logger, funcId, proc.name);
1052
898
  let prevResult = exports.dbosNull;
1053
899
  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);
900
+ if (pctx.presetID) {
901
+ const executionResult = await this.#checkExecution(queryFunc, wfid, funcId, proc.name);
1056
902
  prevResult = executionResult.result;
1057
903
  txn_snapshot = executionResult.txn_snapshot;
1058
904
  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}`, []);
905
+ span.setAttribute('cached', true);
906
+ // Return/throw the previous result
907
+ if (prevResult instanceof Error) {
908
+ throw prevResult;
1063
909
  }
1064
910
  else {
1065
- // otherwise, return/throw the previous result
1066
- if (prevResult instanceof Error) {
1067
- throw prevResult;
1068
- }
1069
- else {
1070
- return prevResult;
1071
- }
911
+ return prevResult;
1072
912
  }
1073
913
  }
1074
914
  }
@@ -1076,27 +916,36 @@ class DBOSExecutor {
1076
916
  // Collect snapshot information for read-only transactions and non-preset UUID transactions, if not already collected above
1077
917
  txn_snapshot = await DBOSExecutor.#retrieveSnapshot(queryFunc);
1078
918
  }
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}`);
919
+ if (this.debugMode && prevResult === exports.dbosNull) {
920
+ throw new error_1.DBOSDebuggerError(`Failed to find the recorded output for the procedure: workflow UUID ${wfid}, step number ${funcId}`);
1081
921
  }
1082
922
  // Execute the user's transaction.
923
+ const ctxlog = this.ctxLogger;
1083
924
  const result = await (async function () {
1084
925
  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
- }
926
+ // Check we are in a workflow context and not in a step / transaction already
927
+ const pctx = (0, context_1.getCurrentContextStore)();
928
+ if (!pctx)
929
+ throw new error_1.DBOSInvalidWorkflowTransitionError();
930
+ if (!(0, context_1.isInWorkflowCtx)(pctx))
931
+ throw new error_1.DBOSInvalidWorkflowTransitionError();
932
+ return await (0, context_1.runWithParentContext)(pctx, {
933
+ curTxFunctionId: funcId,
934
+ parentCtx: pctx,
935
+ isInStoredProc: true,
936
+ sqlClient: client,
937
+ logger: ctxlog,
938
+ span,
939
+ }, async () => {
940
+ const pf = proc;
941
+ return await pf(...args);
1093
942
  });
1094
943
  }
1095
944
  catch (e) {
1096
945
  return e instanceof Error ? e : new Error(`${e}`);
1097
946
  }
1098
947
  })();
1099
- if (this.isDebugging) {
948
+ if (this.debugMode) {
1100
949
  if (prevResult instanceof Error) {
1101
950
  throw prevResult;
1102
951
  }
@@ -1112,20 +961,20 @@ class DBOSExecutor {
1112
961
  }
1113
962
  // Synchronously record the output of write transactions and obtain the transaction ID.
1114
963
  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);
964
+ const pg_txn_id = await this.#recordOutput(func, wfid, funcId, txn_snapshot, result, user_database_1.pgNodeIsKeyConflictError, proc.name);
1116
965
  // const pg_txn_id = await wfCtx.recordOutputProc<R>(client, funcId, txn_snapshot, result);
1117
- ctxt.span.setAttribute('pg_txn_id', pg_txn_id);
966
+ span.setAttribute('pg_txn_id', pg_txn_id);
1118
967
  return result;
1119
968
  };
1120
969
  try {
1121
970
  const result = await this.invokeStoredProcFunction(wrappedProcedure, {
1122
- isolationLevel: procInfo.config.isolationLevel,
971
+ isolationLevel: procInfo.procConfig.isolationLevel,
1123
972
  });
1124
973
  span.setStatus({ code: api_1.SpanStatusCode.OK });
1125
974
  return result;
1126
975
  }
1127
976
  catch (err) {
1128
- if (!this.isDebugging) {
977
+ if (!this.debugMode) {
1129
978
  if (this.userDatabase.isRetriableTransactionError(err)) {
1130
979
  // serialization_failure in PostgreSQL
1131
980
  span.addEvent('TXN SERIALIZATION FAILURE', { retryWaitMillis: retryWaitMillis }, performance.now());
@@ -1139,32 +988,34 @@ class DBOSExecutor {
1139
988
  const e = err;
1140
989
  await this.invokeStoredProcFunction(async (client) => {
1141
990
  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);
991
+ await this.#recordError(func, wfid, funcId, txn_snapshot, e, user_database_1.pgNodeIsKeyConflictError, proc.name);
1143
992
  }, { isolationLevel: transaction_1.IsolationLevel.ReadCommitted });
1144
993
  await this.userDatabase.transaction(async (client) => {
1145
994
  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);
995
+ await this.#recordError(func, wfid, funcId, txn_snapshot, e, (error) => this.userDatabase.isKeyConflictError(error), proc.name);
1147
996
  }, { isolationLevel: transaction_1.IsolationLevel.ReadCommitted });
1148
997
  }
1149
998
  throw err;
1150
999
  }
1151
1000
  }
1152
1001
  }
1153
- async #callProcedureFunctionRemote(proc, args, wfCtx, span, config, funcId) {
1154
- if (this.isDebugging) {
1002
+ async #callProcedureFunctionRemote(proc, args, span, config, funcId) {
1003
+ if (this.debugMode) {
1155
1004
  throw new error_1.DBOSDebuggerError("Can't invoke stored procedure in debug mode.");
1156
1005
  }
1157
- await this.systemDatabase.checkIfCanceled(wfCtx.workflowUUID);
1006
+ const pctx = (0, context_1.getCurrentContextStore)();
1007
+ const wfid = pctx.workflowId;
1008
+ await this.systemDatabase.checkIfCanceled(wfid);
1158
1009
  const $jsonCtx = {
1159
- request: wfCtx.request,
1160
- authenticatedUser: wfCtx.authenticatedUser,
1161
- authenticatedRoles: wfCtx.authenticatedRoles,
1162
- assumedRole: wfCtx.assumedRole,
1010
+ request: pctx.request,
1011
+ authenticatedUser: pctx.authenticatedUser,
1012
+ authenticatedRoles: pctx.authenticatedRoles,
1013
+ assumedRole: pctx.assumedRole,
1163
1014
  };
1164
1015
  // TODO (Qian/Harry): remove this unshift when we remove the resultBuffer argument
1165
1016
  // Note, node-pg converts JS arrays to postgres array literals, so must call JSON.strigify on
1166
1017
  // args and bufferedResults before being passed to #invokeStoredProc
1167
- const $args = [wfCtx.workflowUUID, funcId, wfCtx.presetUUID, $jsonCtx, null, JSON.stringify(args)];
1018
+ const $args = [wfid, funcId, pctx.presetID, $jsonCtx, null, JSON.stringify(args)];
1168
1019
  const readonly = config.readOnly ?? false;
1169
1020
  if (!readonly) {
1170
1021
  $args.unshift(null);
@@ -1185,8 +1036,8 @@ class DBOSExecutor {
1185
1036
  async #invokeStoredProc(proc, args) {
1186
1037
  const client = await this.procedurePool.connect();
1187
1038
  const log = (msg) => this.#logNotice(msg);
1188
- const procClassName = this.getProcedureClassName(proc);
1189
- const plainProcName = `${procClassName}_${proc.name}_p`;
1039
+ const procname = (0, decorators_1.getRegisteredFunctionFullName)(proc);
1040
+ const plainProcName = `${procname.className}_${procname.name}_p`;
1190
1041
  const procName = utils_1.globalParams.wasComputed ? plainProcName : `v${utils_1.globalParams.appVersion}_${plainProcName}`;
1191
1042
  const sql = `CALL "${procName}"(${args.map((_v, i) => `$${i + 1}`).join()});`;
1192
1043
  try {
@@ -1219,106 +1070,99 @@ class DBOSExecutor {
1219
1070
  client.release();
1220
1071
  }
1221
1072
  }
1222
- async external(stepFn, params, ...args) {
1073
+ async runStepTempWF(stepFn, params, ...args) {
1223
1074
  return await (await this.startStepTempWF(stepFn, params, undefined, undefined, ...args)).getResult();
1224
1075
  }
1225
- async startStepTempWF(stepFn, params, callerUUID, callerFunctionID, ...args) {
1076
+ async startStepTempWF(stepFn, params, callerWFID, callerFunctionID, ...args) {
1226
1077
  // 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);
1078
+ const temp_workflow = async (...args) => {
1079
+ return await this.callStepFunction(stepFn, undefined, undefined, params.configuredInstance ?? null, ...args);
1230
1080
  };
1231
1081
  return await this.internalWorkflow(temp_workflow, {
1232
1082
  ...params,
1233
1083
  tempWfType: exports.TempWorkflowType.step,
1234
- tempWfName: (0, decorators_1.getRegisteredMethodName)(stepFn),
1235
- tempWfClass: (0, decorators_1.getRegisteredMethodClassName)(stepFn),
1236
- }, callerUUID, callerFunctionID, ...args);
1084
+ tempWfName: (0, decorators_1.getRegisteredFunctionName)(stepFn),
1085
+ tempWfClass: (0, decorators_1.getRegisteredFunctionClassName)(stepFn),
1086
+ }, callerWFID, callerFunctionID, ...args);
1237
1087
  }
1238
1088
  /**
1239
1089
  * Execute a step function.
1240
1090
  * 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
1091
  * The step may execute many times, but once it is complete, it will not re-execute.
1242
1092
  */
1243
- async callStepFunction(stepFn, stepFnName, stepConfig, clsInst, wfCtx, ...args) {
1093
+ async callStepFunction(stepFn, stepFnName, stepConfig, clsInst, ...args) {
1244
1094
  stepFnName = stepFnName ?? stepFn.name ?? '<unnamed>';
1245
- let passContext = false;
1246
1095
  if (!stepConfig) {
1247
- const stepReg = this.getStepInfo(stepFn);
1248
- stepConfig = stepReg?.config;
1249
- passContext = stepReg?.registration.passContext ?? true;
1096
+ const stepReg = (0, decorators_1.getFunctionRegistration)(stepFn);
1097
+ stepConfig = stepReg?.stepConfig;
1250
1098
  }
1251
1099
  if (stepConfig === undefined) {
1252
1100
  throw new error_1.DBOSNotRegisteredError(stepFnName);
1253
1101
  }
1254
- await this.systemDatabase.checkIfCanceled(wfCtx.workflowUUID);
1255
- const funcID = wfCtx.functionIDGetIncrement();
1102
+ const lctx = (0, context_1.getCurrentContextStore)();
1103
+ const wfid = lctx.workflowId;
1104
+ await this.systemDatabase.checkIfCanceled(wfid);
1105
+ const funcID = (0, context_1.functionIDGetIncrement)();
1256
1106
  const maxRetryIntervalSec = 3600; // Maximum retry interval: 1 hour
1257
1107
  const span = this.tracer.startSpan(stepFnName, {
1258
- operationUUID: wfCtx.workflowUUID,
1259
- operationType: exports.OperationType.COMMUNICATOR,
1260
- authenticatedUser: wfCtx.authenticatedUser,
1261
- assumedRole: wfCtx.assumedRole,
1262
- authenticatedRoles: wfCtx.authenticatedRoles,
1108
+ operationUUID: wfid,
1109
+ operationType: exports.OperationType.STEP,
1110
+ operationName: stepFnName,
1111
+ authenticatedUser: lctx.authenticatedUser ?? '',
1112
+ assumedRole: lctx.assumedRole ?? '',
1113
+ authenticatedRoles: lctx.authenticatedRoles ?? [],
1263
1114
  retriesAllowed: stepConfig.retriesAllowed,
1264
1115
  intervalSeconds: stepConfig.intervalSeconds,
1265
1116
  maxAttempts: stepConfig.maxAttempts,
1266
1117
  backoffRate: stepConfig.backoffRate,
1267
- }, wfCtx.span);
1268
- const ctxt = new step_1.StepContextImpl(wfCtx, funcID, span, this.logger, stepConfig, stepFnName);
1118
+ }, lctx.span);
1269
1119
  // Check if this execution previously happened, returning its original result if it did.
1270
- const checkr = await this.systemDatabase.getOperationResultAndThrowIfCancelled(wfCtx.workflowUUID, ctxt.functionID);
1120
+ const checkr = await this.systemDatabase.getOperationResultAndThrowIfCancelled(wfid, funcID);
1271
1121
  if (checkr) {
1272
- if (checkr.functionName !== ctxt.operationName) {
1273
- throw new error_1.DBOSUnexpectedStepError(ctxt.workflowUUID, ctxt.functionID, ctxt.operationName, checkr.functionName ?? '?');
1122
+ if (checkr.functionName !== stepFnName) {
1123
+ throw new error_1.DBOSUnexpectedStepError(wfid, funcID, stepFnName, checkr.functionName ?? '?');
1274
1124
  }
1275
1125
  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);
1126
+ span.setAttribute('cached', true);
1127
+ span.setStatus({ code: api_1.SpanStatusCode.OK });
1128
+ this.tracer.endSpan(span);
1279
1129
  return check;
1280
1130
  }
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}`);
1131
+ if (this.debugMode) {
1132
+ throw new error_1.DBOSDebuggerError(`Failed to find the recorded output for the step: workflow UUID: ${wfid}, step number: ${funcID}`);
1283
1133
  }
1134
+ const maxAttempts = stepConfig.maxAttempts ?? 3;
1284
1135
  // Execute the step function. If it throws an exception, retry with exponential backoff.
1285
1136
  // After reaching the maximum number of retries, throw an DBOSError.
1286
1137
  let result = exports.dbosNull;
1287
1138
  let err = exports.dbosNull;
1288
1139
  const errors = [];
1289
- if (ctxt.retriesAllowed) {
1290
- let numAttempts = 0;
1291
- let intervalSeconds = ctxt.intervalSeconds;
1140
+ if (stepConfig.retriesAllowed) {
1141
+ let attemptNum = 0;
1142
+ let intervalSeconds = stepConfig.intervalSeconds ?? 1;
1292
1143
  if (intervalSeconds > maxRetryIntervalSec) {
1293
1144
  this.logger.warn(`Step config interval exceeds maximum allowed interval, capped to ${maxRetryIntervalSec} seconds!`);
1294
1145
  }
1295
- while (result === exports.dbosNull && numAttempts++ < ctxt.maxAttempts) {
1146
+ while (result === exports.dbosNull && attemptNum++ < (maxAttempts ?? 3)) {
1296
1147
  try {
1297
- await this.systemDatabase.checkIfCanceled(wfCtx.workflowUUID);
1148
+ await this.systemDatabase.checkIfCanceled(wfid);
1298
1149
  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
- }
1150
+ await (0, context_1.runInStepContext)(lctx, funcID, span, maxAttempts, attemptNum, async () => {
1151
+ const sf = stepFn;
1152
+ cresult = await sf.call(clsInst, ...args);
1153
+ });
1310
1154
  result = cresult;
1311
1155
  }
1312
1156
  catch (error) {
1313
1157
  const e = error;
1314
1158
  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) {
1159
+ this.logger.warn(`Error in step being automatically retried. Attempt ${attemptNum} of ${maxAttempts}. ${e.stack}`);
1160
+ span.addEvent(`Step attempt ${attemptNum + 1} failed`, { retryIntervalSeconds: intervalSeconds, error: error.message }, performance.now());
1161
+ if (attemptNum < maxAttempts) {
1318
1162
  // Sleep for an interval, then increase the interval by backoffRate.
1319
1163
  // Cap at the maximum allowed retry interval.
1320
1164
  await (0, utils_1.sleepms)(intervalSeconds * 1000);
1321
- intervalSeconds *= ctxt.backoffRate;
1165
+ intervalSeconds *= stepConfig.backoffRate ?? 2;
1322
1166
  intervalSeconds = intervalSeconds < maxRetryIntervalSec ? intervalSeconds : maxRetryIntervalSec;
1323
1167
  }
1324
1168
  }
@@ -1327,17 +1171,10 @@ class DBOSExecutor {
1327
1171
  else {
1328
1172
  try {
1329
1173
  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
- }
1174
+ await (0, context_1.runInStepContext)(lctx, funcID, span, maxAttempts, undefined, async () => {
1175
+ const sf = stepFn;
1176
+ cresult = await sf.call(clsInst, ...args);
1177
+ });
1341
1178
  result = cresult;
1342
1179
  }
1343
1180
  catch (error) {
@@ -1347,35 +1184,37 @@ class DBOSExecutor {
1347
1184
  // `result` can only be dbosNull when the step timed out
1348
1185
  if (result === exports.dbosNull) {
1349
1186
  // 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, {
1187
+ err = err === exports.dbosNull ? new error_1.DBOSMaxStepRetriesError(stepFnName, maxAttempts, errors) : err;
1188
+ await this.systemDatabase.recordOperationResult(wfid, funcID, stepFnName, true, {
1352
1189
  error: utils_1.DBOSJSON.stringify((0, serialize_error_1.serializeError)(err)),
1353
1190
  });
1354
- ctxt.span.setStatus({ code: api_1.SpanStatusCode.ERROR, message: err.message });
1355
- this.tracer.endSpan(ctxt.span);
1191
+ span.setStatus({ code: api_1.SpanStatusCode.ERROR, message: err.message });
1192
+ this.tracer.endSpan(span);
1356
1193
  throw err;
1357
1194
  }
1358
1195
  else {
1359
1196
  // Record the execution and return.
1360
- await this.systemDatabase.recordOperationResult(wfCtx.workflowUUID, ctxt.functionID, ctxt.operationName, true, {
1197
+ await this.systemDatabase.recordOperationResult(wfid, funcID, stepFnName, true, {
1361
1198
  output: utils_1.DBOSJSON.stringify(result),
1362
1199
  });
1363
- ctxt.span.setStatus({ code: api_1.SpanStatusCode.OK });
1364
- this.tracer.endSpan(ctxt.span);
1200
+ span.setStatus({ code: api_1.SpanStatusCode.OK });
1201
+ this.tracer.endSpan(span);
1365
1202
  return result;
1366
1203
  }
1367
1204
  }
1368
- async send(destinationUUID, message, topic, idempotencyKey) {
1205
+ async runSendTempWF(destinationId, message, topic, idempotencyKey) {
1369
1206
  // Create a workflow and call send.
1370
- const temp_workflow = async (ctxt, destinationUUID, message, topic) => {
1371
- return await ctxt.send(destinationUUID, message, topic);
1207
+ const temp_workflow = async (destinationId, message, topic) => {
1208
+ const ctx = (0, context_1.getCurrentContextStore)();
1209
+ const functionID = (0, context_1.functionIDGetIncrement)();
1210
+ await this.systemDatabase.send(ctx.workflowId, functionID, destinationId, utils_1.DBOSJSON.stringify(message), topic);
1372
1211
  };
1373
- const workflowUUID = idempotencyKey ? destinationUUID + idempotencyKey : undefined;
1212
+ const workflowUUID = idempotencyKey ? destinationId + idempotencyKey : undefined;
1374
1213
  return (await this.workflow(temp_workflow, {
1375
1214
  workflowUUID: workflowUUID,
1376
1215
  tempWfType: exports.TempWorkflowType.send,
1377
1216
  configuredInstance: null,
1378
- }, destinationUUID, message, topic)).getResult();
1217
+ }, destinationId, message, topic)).getResult();
1379
1218
  }
1380
1219
  /**
1381
1220
  * Wait for a workflow to emit an event, then return its value.
@@ -1443,33 +1282,13 @@ class DBOSExecutor {
1443
1282
  return await this.userDatabase.query(sql);
1444
1283
  }
1445
1284
  }
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
1285
  /* INTERNAL HELPERS */
1467
1286
  /**
1468
1287
  * A recovery process that by default runs during executor init time.
1469
1288
  * It runs to completion all pending workflows that were executing when the previous executor failed.
1470
1289
  */
1471
1290
  async recoverPendingWorkflows(executorIDs = ['local']) {
1472
- if (this.isDebugging) {
1291
+ if (this.debugMode) {
1473
1292
  throw new error_1.DBOSDebuggerError('Cannot recover pending workflows in debug mode.');
1474
1293
  }
1475
1294
  const handlerArray = [];
@@ -1510,34 +1329,22 @@ class DBOSExecutor {
1510
1329
  this.scheduler = new scheduler_1.DBOSScheduler(this);
1511
1330
  this.scheduler.initScheduler();
1512
1331
  this.wfqEnded = wfqueue_1.wfQueueRunner.dispatchLoop(this);
1513
- for (const evtRcvr of this.eventReceivers) {
1514
- await evtRcvr.initialize(this);
1515
- }
1516
1332
  for (const lcl of (0, decorators_1.getLifecycleListeners)()) {
1517
- await lcl.initialize();
1333
+ await lcl.initialize?.();
1518
1334
  }
1519
1335
  }
1520
1336
  async deactivateEventReceivers(stopQueueThread = true) {
1521
1337
  this.logger.debug('Deactivating lifecycle listeners');
1522
1338
  for (const lcl of (0, decorators_1.getLifecycleListeners)()) {
1523
1339
  try {
1524
- await lcl.destroy();
1340
+ await lcl.destroy?.();
1525
1341
  }
1526
1342
  catch (err) {
1527
1343
  const e = err;
1528
1344
  this.logger.warn(`Error destroying lifecycle listener: ${e.message}`);
1529
1345
  }
1530
1346
  }
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
- }
1347
+ this.logger.debug('Deactivating scheduler');
1541
1348
  try {
1542
1349
  await this.scheduler?.destroyScheduler();
1543
1350
  }
@@ -1545,6 +1352,7 @@ class DBOSExecutor {
1545
1352
  const e = err;
1546
1353
  this.logger.warn(`Error destroying scheduler: ${e.message}`);
1547
1354
  }
1355
+ this.logger.debug('Deactivating queue runner');
1548
1356
  if (stopQueueThread) {
1549
1357
  try {
1550
1358
  wfqueue_1.wfQueueRunner.stop();
@@ -1567,67 +1375,72 @@ class DBOSExecutor {
1567
1375
  throw new error_1.DBOSError(`Failed to find inputs for workflow UUID: ${workflowID}`);
1568
1376
  }
1569
1377
  const inputs = utils_1.DBOSJSON.parse(wfStatus.input);
1570
- const parentCtx = this.#getRecoveryContext(workflowID, wfStatus);
1571
- const { wfInfo, configuredInst } = this.getWorkflowInfoByStatus(wfStatus);
1378
+ const recoverCtx = this.#getRecoveryContext(workflowID, wfStatus);
1379
+ const { methReg, configuredInst } = this.#getFunctionInfoFromWFStatus(wfStatus);
1572
1380
  // If starting a new workflow, assign a new UUID. Otherwise, use the workflow's original UUID.
1573
1381
  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);
1382
+ if (methReg?.workflowConfig) {
1383
+ return await (0, context_1.runWithTopContext)(recoverCtx, async () => {
1384
+ return await this.workflow(methReg.registeredFunction, {
1385
+ workflowUUID: workflowStartID,
1386
+ configuredInstance: configuredInst,
1387
+ queueName: wfStatus.queueName,
1388
+ executeWorkflow: true,
1389
+ deadlineEpochMS: wfStatus.deadlineEpochMS,
1390
+ }, ...inputs);
1391
+ });
1583
1392
  }
1584
1393
  // Should be temporary workflows. Parse the name of the workflow.
1585
1394
  const wfName = wfStatus.workflowName;
1586
1395
  const nameArr = wfName.split('-');
1587
1396
  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}`);
1397
+ 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
1398
  }
1591
- let temp_workflow;
1592
1399
  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]}`);
1400
+ const txnReg = (0, decorators_1.getFunctionRegistrationByName)(wfStatus.workflowClassName, nameArr[2]);
1401
+ if (!txnReg?.txnConfig) {
1402
+ this.logger.error(`Cannot find transaction info for ID ${workflowID}, name ${nameArr[2]}`);
1596
1403
  throw new error_1.DBOSNotRegisteredError(nameArr[2]);
1597
1404
  }
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);
1405
+ return await (0, context_1.runWithTopContext)(recoverCtx, async () => {
1406
+ return await this.startTransactionTempWF(txnReg.registeredFunction, {
1407
+ workflowUUID: workflowStartID,
1408
+ configuredInstance: configuredInst,
1409
+ queueName: wfStatus.queueName,
1410
+ executeWorkflow: true,
1411
+ }, undefined, undefined, ...inputs);
1412
+ });
1605
1413
  }
1606
1414
  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]}`);
1415
+ const stepReg = (0, decorators_1.getFunctionRegistrationByName)(wfStatus.workflowClassName, nameArr[2]);
1416
+ if (!stepReg?.stepConfig) {
1417
+ this.logger.error(`Cannot find step info for ID ${workflowID}, name ${nameArr[2]}`);
1610
1418
  throw new error_1.DBOSNotRegisteredError(nameArr[2]);
1611
1419
  }
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);
1420
+ return await (0, context_1.runWithTopContext)(recoverCtx, async () => {
1421
+ return await this.startStepTempWF(stepReg.registeredFunction, {
1422
+ workflowUUID: workflowStartID,
1423
+ configuredInstance: configuredInst,
1424
+ queueName: wfStatus.queueName, // Probably null
1425
+ executeWorkflow: true,
1426
+ }, undefined, undefined, ...inputs);
1427
+ });
1619
1428
  }
1620
1429
  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
1430
+ const swf = async (destinationID, message, topic) => {
1431
+ const ctx = (0, context_1.getCurrentContextStore)();
1432
+ const functionID = (0, context_1.functionIDGetIncrement)();
1433
+ await this.systemDatabase.send(ctx.workflowId, functionID, destinationID, utils_1.DBOSJSON.stringify(message), topic);
1623
1434
  };
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);
1435
+ const temp_workflow = swf;
1436
+ return await (0, context_1.runWithTopContext)(recoverCtx, async () => {
1437
+ return this.workflow(temp_workflow, {
1438
+ workflowUUID: workflowStartID,
1439
+ tempWfType: exports.TempWorkflowType.send,
1440
+ queueName: wfStatus.queueName,
1441
+ executeWorkflow: true,
1442
+ }, ...inputs);
1443
+ });
1631
1444
  }
1632
1445
  else {
1633
1446
  this.logger.error(`Unrecognized temporary workflow! UUID ${workflowID}, name ${wfName}`);
@@ -1640,14 +1453,13 @@ class DBOSExecutor {
1640
1453
  async upsertEventDispatchState(state) {
1641
1454
  return await this.systemDatabase.upsertEventDispatchState(state);
1642
1455
  }
1643
- #getRecoveryContext(workflowUUID, status) {
1456
+ #getRecoveryContext(_workflowID, status) {
1644
1457
  // Note: this doesn't inherit the original parent context's span.
1645
- const oc = new context_1.DBOSContextImpl(status.workflowName, undefined, this.logger);
1458
+ const oc = {};
1646
1459
  oc.request = status.request;
1647
1460
  oc.authenticatedUser = status.authenticatedUser;
1648
1461
  oc.authenticatedRoles = status.authenticatedRoles;
1649
1462
  oc.assumedRole = status.assumedRole;
1650
- oc.workflowUUID = workflowUUID;
1651
1463
  return oc;
1652
1464
  }
1653
1465
  async cancelWorkflow(workflowID) {
@@ -1671,7 +1483,7 @@ class DBOSExecutor {
1671
1483
  }
1672
1484
  logRegisteredHTTPUrls() {
1673
1485
  this.logger.info('HTTP endpoints supported:');
1674
- this.registeredOperations.forEach((registeredOperation) => {
1486
+ (0, decorators_1.getAllRegisteredFunctions)().forEach((registeredOperation) => {
1675
1487
  const ro = registeredOperation;
1676
1488
  if (ro.apiURL) {
1677
1489
  this.logger.info(' ' + ro.apiType.padEnd(6) + ' : ' + ro.apiURL);
@@ -1699,8 +1511,9 @@ class DBOSExecutor {
1699
1511
  */
1700
1512
  computeAppVersion() {
1701
1513
  const hasher = crypto.createHash('md5');
1702
- const sortedWorkflowSource = Array.from(this.workflowInfoMap.values())
1703
- .map((i) => i.workflowOrigFunction.toString())
1514
+ const sortedWorkflowSource = Array.from((0, decorators_1.getAllRegisteredFunctions)())
1515
+ .filter((e) => e.workflowConfig)
1516
+ .map((i) => i.origFunction.toString())
1704
1517
  .sort();
1705
1518
  // Different DBOS versions should produce different hashes.
1706
1519
  sortedWorkflowSource.push(utils_1.globalParams.dbosVersion);