@dbos-inc/dbos-sdk 3.0.45-preview.g34e483ff45 → 3.0.50-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 (38) hide show
  1. package/dist/src/context.d.ts +2 -4
  2. package/dist/src/context.d.ts.map +1 -1
  3. package/dist/src/context.js +2 -4
  4. package/dist/src/context.js.map +1 -1
  5. package/dist/src/datasource.d.ts.map +1 -1
  6. package/dist/src/datasource.js +18 -14
  7. package/dist/src/datasource.js.map +1 -1
  8. package/dist/src/dbos-executor.d.ts +5 -14
  9. package/dist/src/dbos-executor.d.ts.map +1 -1
  10. package/dist/src/dbos-executor.js +175 -129
  11. package/dist/src/dbos-executor.js.map +1 -1
  12. package/dist/src/dbos-runtime/config.d.ts.map +1 -1
  13. package/dist/src/dbos-runtime/config.js +4 -2
  14. package/dist/src/dbos-runtime/config.js.map +1 -1
  15. package/dist/src/dbos-runtime/workflow_management.d.ts +2 -2
  16. package/dist/src/dbos-runtime/workflow_management.d.ts.map +1 -1
  17. package/dist/src/dbos-runtime/workflow_management.js +5 -3
  18. package/dist/src/dbos-runtime/workflow_management.js.map +1 -1
  19. package/dist/src/dbos.d.ts +0 -9
  20. package/dist/src/dbos.d.ts.map +1 -1
  21. package/dist/src/dbos.js +50 -133
  22. package/dist/src/dbos.js.map +1 -1
  23. package/dist/src/httpServer/middleware.d.ts +0 -8
  24. package/dist/src/httpServer/middleware.d.ts.map +1 -1
  25. package/dist/src/httpServer/middleware.js +1 -153
  26. package/dist/src/httpServer/middleware.js.map +1 -1
  27. package/dist/src/httpServer/server.d.ts.map +1 -1
  28. package/dist/src/httpServer/server.js +41 -38
  29. package/dist/src/httpServer/server.js.map +1 -1
  30. package/dist/src/telemetry/traces.d.ts +2 -0
  31. package/dist/src/telemetry/traces.d.ts.map +1 -1
  32. package/dist/src/telemetry/traces.js +22 -1
  33. package/dist/src/telemetry/traces.js.map +1 -1
  34. package/dist/src/user_database.d.ts +1 -1
  35. package/dist/src/user_database.d.ts.map +1 -1
  36. package/dist/src/user_database.js.map +1 -1
  37. package/dist/tsconfig.tsbuildinfo +1 -1
  38. package/package.json +2 -5
@@ -72,30 +72,30 @@ class DBOSExecutor {
72
72
  config;
73
73
  initialized;
74
74
  // User Database
75
- userDatabase = null;
75
+ #userDatabase = undefined;
76
+ #procedurePool = undefined;
76
77
  // System Database
77
78
  systemDatabase;
78
- procedurePool;
79
79
  // Temporary workflows are created by calling transaction/send/recv directly from the executor class
80
- static tempWorkflowName = 'temp_workflow';
80
+ static #tempWorkflowName = 'temp_workflow';
81
81
  telemetryCollector;
82
82
  static defaultNotificationTimeoutSec = 60;
83
- debugMode;
83
+ #debugMode;
84
84
  static systemDBSchemaName = 'dbos';
85
85
  logger;
86
86
  ctxLogger;
87
87
  tracer;
88
88
  // eslint-disable-next-line @typescript-eslint/no-unsafe-function-type
89
- typeormEntities = [];
90
- drizzleEntities = {};
91
- scheduler = new scheduler_1.ScheduledReceiver();
92
- wfqEnded = undefined;
89
+ #typeormEntities = [];
90
+ #drizzleEntities = {};
91
+ #scheduler = new scheduler_1.ScheduledReceiver();
92
+ #wfqEnded = undefined;
93
93
  executorID = utils_1.globalParams.executorID;
94
94
  static globalInstance = undefined;
95
95
  /* WORKFLOW EXECUTOR LIFE CYCLE MANAGEMENT */
96
96
  constructor(config, { systemDatabase, debugMode } = {}) {
97
97
  this.config = config;
98
- this.debugMode = debugMode ?? false;
98
+ this.#debugMode = debugMode ?? false;
99
99
  if (config.telemetry.OTLPExporter) {
100
100
  const OTLPExporter = new exporters_1.TelemetryExporter(config.telemetry.OTLPExporter);
101
101
  this.telemetryCollector = new collector_1.TelemetryCollector(OTLPExporter);
@@ -105,12 +105,12 @@ class DBOSExecutor {
105
105
  this.telemetryCollector = new collector_1.TelemetryCollector();
106
106
  }
107
107
  this.logger = new logs_1.GlobalLogger(this.telemetryCollector, this.config.telemetry.logs);
108
- this.ctxLogger = new logs_1.DBOSContextualLogger(this.logger, () => (0, context_1.getCurrentContextStore)().span);
108
+ this.ctxLogger = new logs_1.DBOSContextualLogger(this.logger, () => api_1.trace.getActiveSpan());
109
109
  this.tracer = new traces_1.Tracer(this.telemetryCollector);
110
- if (this.debugMode) {
110
+ if (this.#debugMode) {
111
111
  this.logger.info('Running in debug mode!');
112
112
  }
113
- this.procedurePool = new pg_1.Pool((0, utils_2.getClientConfig)(this.config.databaseUrl));
113
+ this.#procedurePool = this.config.userDbClient ? new pg_1.Pool((0, utils_2.getClientConfig)(this.config.databaseUrl)) : undefined;
114
114
  if (systemDatabase) {
115
115
  this.logger.debug('Using provided system database'); // XXX print the name or something
116
116
  this.systemDatabase = systemDatabase;
@@ -122,7 +122,7 @@ class DBOSExecutor {
122
122
  this.initialized = false;
123
123
  DBOSExecutor.globalInstance = this;
124
124
  }
125
- configureDbClient() {
125
+ #configureDbClient() {
126
126
  const userDbClient = this.config.userDbClient;
127
127
  const userDBConfig = (0, utils_2.getClientConfig)(this.config.databaseUrl);
128
128
  userDBConfig.max = this.config.userDbPoolSize ?? 20;
@@ -130,7 +130,7 @@ class DBOSExecutor {
130
130
  // TODO: make Prisma work with debugger proxy.
131
131
  // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-require-imports
132
132
  const { PrismaClient } = require(node_path_1.default.join(process.cwd(), 'node_modules', '@prisma', 'client')); // Find the prisma client in the node_modules of the current project
133
- this.userDatabase = new user_database_1.PrismaUserDatabase(
133
+ this.#userDatabase = new user_database_1.PrismaUserDatabase(
134
134
  // eslint-disable-next-line @typescript-eslint/no-unsafe-argument, @typescript-eslint/no-unsafe-call
135
135
  new PrismaClient({
136
136
  datasources: {
@@ -145,13 +145,13 @@ class DBOSExecutor {
145
145
  // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-require-imports
146
146
  const DataSourceExports = require('typeorm');
147
147
  try {
148
- this.userDatabase = new user_database_1.TypeORMDatabase(
148
+ this.#userDatabase = new user_database_1.TypeORMDatabase(
149
149
  // eslint-disable-next-line @typescript-eslint/no-unsafe-argument, @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-member-access
150
150
  new DataSourceExports.DataSource({
151
151
  type: 'postgres',
152
152
  url: userDBConfig.connectionString,
153
153
  connectTimeoutMS: userDBConfig.connectionTimeoutMillis,
154
- entities: this.typeormEntities,
154
+ entities: this.#typeormEntities,
155
155
  poolSize: userDBConfig.max,
156
156
  }));
157
157
  }
@@ -170,7 +170,7 @@ class DBOSExecutor {
170
170
  max: userDBConfig.max,
171
171
  },
172
172
  };
173
- this.userDatabase = new user_database_1.KnexUserDatabase((0, knex_1.default)(knexConfig));
173
+ this.#userDatabase = new user_database_1.KnexUserDatabase((0, knex_1.default)(knexConfig));
174
174
  this.logger.debug('Loaded Knex user database');
175
175
  }
176
176
  else if (userDbClient === user_database_1.UserDatabaseName.DRIZZLE) {
@@ -178,13 +178,13 @@ class DBOSExecutor {
178
178
  const DrizzleExports = require('drizzle-orm/node-postgres');
179
179
  const drizzlePool = new pg_1.Pool(userDBConfig);
180
180
  // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-member-access
181
- const drizzle = DrizzleExports.drizzle(drizzlePool, { schema: this.drizzleEntities });
181
+ const drizzle = DrizzleExports.drizzle(drizzlePool, { schema: this.#drizzleEntities });
182
182
  // eslint-disable-next-line @typescript-eslint/no-unsafe-argument
183
- this.userDatabase = new user_database_1.DrizzleUserDatabase(drizzlePool, drizzle);
183
+ this.#userDatabase = new user_database_1.DrizzleUserDatabase(drizzlePool, drizzle);
184
184
  this.logger.debug('Loaded Drizzle user database');
185
185
  }
186
186
  else {
187
- this.userDatabase = new user_database_1.PGNodeUserDatabase(userDBConfig);
187
+ this.#userDatabase = new user_database_1.PGNodeUserDatabase(userDBConfig);
188
188
  this.logger.debug('Loaded Postgres user database');
189
189
  }
190
190
  }
@@ -208,29 +208,31 @@ class DBOSExecutor {
208
208
  * With TSORM, we take an array of entities (Function[]) and add them to this.entities:
209
209
  */
210
210
  if (Array.isArray(reg.ormEntities)) {
211
- this.typeormEntities = this.typeormEntities.concat(reg.ormEntities);
211
+ this.#typeormEntities = this.#typeormEntities.concat(reg.ormEntities);
212
212
  length = reg.ormEntities.length;
213
213
  }
214
214
  else {
215
215
  /**
216
216
  * With Drizzle, we need to take an object of entities, since the object keys are used to access the entities from ctx.client.query:
217
217
  */
218
- this.drizzleEntities = { ...this.drizzleEntities, ...reg.ormEntities };
218
+ this.#drizzleEntities = { ...this.#drizzleEntities, ...reg.ormEntities };
219
219
  length = Object.keys(reg.ormEntities).length;
220
220
  }
221
221
  this.logger.debug(`Loaded ${length} ORM entities`);
222
222
  }
223
- if (!this.debugMode) {
224
- await (0, user_database_1.createDBIfDoesNotExist)(this.config.databaseUrl, this.logger);
225
- }
226
- this.configureDbClient();
227
- if (!this.userDatabase) {
228
- this.logger.error('No user database configured!');
229
- throw new error_1.DBOSInitializationError('No user database configured!');
223
+ if (this.config.userDbClient) {
224
+ if (!this.#debugMode) {
225
+ await (0, user_database_1.createDBIfDoesNotExist)(this.config.databaseUrl, this.logger);
226
+ }
227
+ this.#configureDbClient();
228
+ if (!this.#userDatabase) {
229
+ this.logger.error('No user database configured!');
230
+ throw new error_1.DBOSInitializationError('No user database configured!');
231
+ }
232
+ // Debug mode doesn't need to initialize the DBs. Everything should appear to be read-only.
233
+ await this.#userDatabase.init(this.#debugMode);
230
234
  }
231
- // Debug mode doesn't need to initialize the DBs. Everything should appear to be read-only.
232
- await this.userDatabase.init(this.debugMode);
233
- if (!this.debugMode) {
235
+ if (!this.#debugMode) {
234
236
  await this.systemDatabase.init();
235
237
  }
236
238
  }
@@ -253,7 +255,7 @@ class DBOSExecutor {
253
255
  }
254
256
  this.initialized = true;
255
257
  // Only execute init code if under non-debug mode
256
- if (!this.debugMode) {
258
+ if (!this.#debugMode) {
257
259
  for (const cls of classnames) {
258
260
  // Init its configurations
259
261
  const creg = (0, decorators_1.getClassRegistrationByName)(cls);
@@ -306,10 +308,8 @@ class DBOSExecutor {
306
308
  try {
307
309
  await this.systemDatabase.awaitRunningWorkflows();
308
310
  await this.systemDatabase.destroy();
309
- if (this.userDatabase) {
310
- await this.userDatabase.destroy();
311
- }
312
- await this.procedurePool.end();
311
+ await this.#userDatabase?.destroy();
312
+ await this.#procedurePool?.end();
313
313
  await this.logger.destroy();
314
314
  if (DBOSExecutor.globalInstance === this) {
315
315
  DBOSExecutor.globalInstance = undefined;
@@ -321,6 +321,24 @@ class DBOSExecutor {
321
321
  throw err;
322
322
  }
323
323
  }
324
+ async createUserSchema() {
325
+ if (!this.#userDatabase) {
326
+ throw new Error('User database not enabled.');
327
+ }
328
+ await this.#userDatabase.createSchema();
329
+ }
330
+ async dropUserSchema() {
331
+ if (!this.#userDatabase) {
332
+ throw new Error('User database not enabled.');
333
+ }
334
+ await this.#userDatabase.dropSchema();
335
+ }
336
+ async queryUserDbFunction(queryFunction, ...params) {
337
+ if (!this.#userDatabase) {
338
+ throw new Error('User database not enabled.');
339
+ }
340
+ return await this.#userDatabase.queryFunction(queryFunction, ...params);
341
+ }
324
342
  // This could return WF, or the function underlying a temp wf
325
343
  #getFunctionInfoFromWFStatus(wf) {
326
344
  const methReg = (0, decorators_1.getFunctionRegistrationByName)(wf.workflowClassName, wf.workflowName);
@@ -364,7 +382,7 @@ class DBOSExecutor {
364
382
  const pctx = (0, context_1.getCurrentContextStore)();
365
383
  let wConfig = {};
366
384
  const wInfo = (0, decorators_1.getFunctionRegistration)(wf);
367
- if (wf.name !== DBOSExecutor.tempWorkflowName) {
385
+ if (wf.name !== DBOSExecutor.#tempWorkflowName) {
368
386
  if (!wInfo || !wInfo.workflowConfig) {
369
387
  throw new error_1.DBOSNotRegisteredError(wf.name);
370
388
  }
@@ -382,8 +400,8 @@ class DBOSExecutor {
382
400
  authenticatedUser: pctx?.authenticatedUser ?? '',
383
401
  authenticatedRoles: pctx?.authenticatedRoles ?? [],
384
402
  assumedRole: pctx?.assumedRole ?? '',
385
- }, pctx?.span);
386
- const isTempWorkflow = DBOSExecutor.tempWorkflowName === wfname;
403
+ });
404
+ const isTempWorkflow = DBOSExecutor.#tempWorkflowName === wfname;
387
405
  const internalStatus = {
388
406
  workflowUUID: workflowID,
389
407
  status: params.queueName !== undefined ? workflow_1.StatusString.ENQUEUED : workflow_1.StatusString.PENDING,
@@ -408,14 +426,14 @@ class DBOSExecutor {
408
426
  priority: priority ?? 0,
409
427
  };
410
428
  if (isTempWorkflow) {
411
- internalStatus.workflowName = `${DBOSExecutor.tempWorkflowName}-${params.tempWfType}-${params.tempWfName}`;
429
+ internalStatus.workflowName = `${DBOSExecutor.#tempWorkflowName}-${params.tempWfType}-${params.tempWfName}`;
412
430
  internalStatus.workflowClassName = params.tempWfClass ?? '';
413
431
  }
414
432
  let status = undefined;
415
433
  let $deadlineEpochMS = undefined;
416
434
  // Synchronously set the workflow's status to PENDING and record workflow inputs.
417
435
  // We have to do it for all types of workflows because operation_outputs table has a foreign key constraint on workflow status table.
418
- if (this.debugMode) {
436
+ if (this.#debugMode) {
419
437
  const wfStatus = await this.systemDatabase.getWorkflowStatus(workflowID);
420
438
  if (!wfStatus) {
421
439
  throw new error_1.DBOSDebuggerError(`Failed to find inputs for workflow UUID ${workflowID}`);
@@ -471,7 +489,7 @@ class DBOSExecutor {
471
489
  e.dbos_already_logged = true;
472
490
  internalStatus.error = utils_1.DBOSJSON.stringify((0, serialize_error_1.serializeError)(e));
473
491
  internalStatus.status = workflow_1.StatusString.ERROR;
474
- if (!exec.debugMode) {
492
+ if (!exec.#debugMode) {
475
493
  await exec.systemDatabase.recordWorkflowError(workflowID, internalStatus);
476
494
  }
477
495
  span.setStatus({ code: api_1.SpanStatusCode.ERROR, message: e.message });
@@ -480,23 +498,24 @@ class DBOSExecutor {
480
498
  let result;
481
499
  // Execute the workflow.
482
500
  try {
483
- const callResult = await (0, context_1.runWithParentContext)(pctx, {
484
- presetID,
485
- timeoutMS,
486
- deadlineEpochMS,
487
- workflowId: workflowID,
488
- span,
489
- logger: this.ctxLogger,
490
- }, () => {
491
- const callPromise = wf.call(params.configuredInstance, ...args);
492
- if ($deadlineEpochMS === undefined) {
493
- return callPromise;
494
- }
495
- else {
496
- return callPromiseWithTimeout(callPromise, $deadlineEpochMS, this.systemDatabase);
497
- }
501
+ const callResult = await api_1.context.with(api_1.trace.setSpan(api_1.context.active(), span), async () => {
502
+ return await (0, context_1.runWithParentContext)(pctx, {
503
+ presetID,
504
+ timeoutMS,
505
+ deadlineEpochMS,
506
+ workflowId: workflowID,
507
+ logger: this.ctxLogger,
508
+ }, () => {
509
+ const callPromise = wf.call(params.configuredInstance, ...args);
510
+ if ($deadlineEpochMS === undefined) {
511
+ return callPromise;
512
+ }
513
+ else {
514
+ return callPromiseWithTimeout(callPromise, $deadlineEpochMS, this.systemDatabase);
515
+ }
516
+ });
498
517
  });
499
- if (this.debugMode) {
518
+ if (this.#debugMode) {
500
519
  const recordedResult = DBOSExecutor.reviveResultOrError((await this.systemDatabase.awaitWorkflowResult(workflowID)));
501
520
  if (!resultsMatch(recordedResult, callResult)) {
502
521
  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)}`);
@@ -514,7 +533,7 @@ class DBOSExecutor {
514
533
  }
515
534
  internalStatus.output = utils_1.DBOSJSON.stringify(result);
516
535
  internalStatus.status = workflow_1.StatusString.SUCCESS;
517
- if (!this.debugMode) {
536
+ if (!this.#debugMode) {
518
537
  await this.systemDatabase.recordWorkflowOutput(workflowID, internalStatus);
519
538
  }
520
539
  span.setStatus({ code: api_1.SpanStatusCode.OK });
@@ -550,7 +569,7 @@ class DBOSExecutor {
550
569
  }
551
570
  return result;
552
571
  };
553
- if (this.debugMode ||
572
+ if (this.#debugMode ||
554
573
  (status !== 'SUCCESS' && status !== 'ERROR' && (params.queueName === undefined || params.executeWorkflow))) {
555
574
  const workflowPromise = runWorkflow();
556
575
  this.systemDatabase.registerRunningWorkflow(workflowID, workflowPromise);
@@ -616,7 +635,7 @@ class DBOSExecutor {
616
635
  * Write a operation's output to the database.
617
636
  */
618
637
  async #recordOutput(query, workflowUUID, funcID, txnSnapshot, output, isKeyConflict, function_name) {
619
- if (this.debugMode) {
638
+ if (this.#debugMode) {
620
639
  throw new error_1.DBOSDebuggerError('Cannot record output in debug mode.');
621
640
  }
622
641
  try {
@@ -638,7 +657,7 @@ class DBOSExecutor {
638
657
  * Record an error in an operation to the database.
639
658
  */
640
659
  async #recordError(query, workflowUUID, funcID, txnSnapshot, err, isKeyConflict, function_name) {
641
- if (this.debugMode) {
660
+ if (this.#debugMode) {
642
661
  throw new error_1.DBOSDebuggerError('Cannot record error in debug mode.');
643
662
  }
644
663
  try {
@@ -656,12 +675,17 @@ class DBOSExecutor {
656
675
  }
657
676
  }
658
677
  async getTransactions(workflowUUID) {
659
- const rows = await this.userDatabase.query(`SELECT function_id, function_name, output, error FROM ${DBOSExecutor.systemDBSchemaName}.transaction_outputs WHERE workflow_uuid=$1`, workflowUUID);
660
- for (const row of rows) {
661
- row.output = row.output !== null ? utils_1.DBOSJSON.parse(row.output) : null;
662
- row.error = row.error !== null ? (0, serialize_error_1.deserializeError)(utils_1.DBOSJSON.parse(row.error)) : null;
678
+ if (this.#userDatabase) {
679
+ const rows = await this.#userDatabase.query(`SELECT function_id, function_name, output, error FROM ${DBOSExecutor.systemDBSchemaName}.transaction_outputs WHERE workflow_uuid=$1`, workflowUUID);
680
+ for (const row of rows) {
681
+ row.output = row.output !== null ? utils_1.DBOSJSON.parse(row.output) : null;
682
+ row.error = row.error !== null ? (0, serialize_error_1.deserializeError)(utils_1.DBOSJSON.parse(row.error)) : null;
683
+ }
684
+ return rows;
685
+ }
686
+ else {
687
+ return [];
663
688
  }
664
- return rows;
665
689
  }
666
690
  async runTransactionTempWF(txn, params, ...args) {
667
691
  return await (await this.startTransactionTempWF(txn, params, undefined, undefined, ...args)).getResult();
@@ -679,6 +703,10 @@ class DBOSExecutor {
679
703
  }, callerWFID, callerFunctionID, ...args);
680
704
  }
681
705
  async callTransactionFunction(txn, clsinst, ...args) {
706
+ const userDB = this.#userDatabase;
707
+ if (!userDB) {
708
+ throw new Error('No user database configured for transactions.');
709
+ }
682
710
  const txnReg = (0, decorators_1.getFunctionRegistration)(txn);
683
711
  if (!txnReg || !txnReg.txnConfig) {
684
712
  throw new error_1.DBOSNotRegisteredError(txn.name);
@@ -698,7 +726,7 @@ class DBOSExecutor {
698
726
  assumedRole: pctx.assumedRole ?? '',
699
727
  authenticatedRoles: pctx.authenticatedRoles ?? [],
700
728
  isolationLevel: txnReg.txnConfig.isolationLevel,
701
- }, pctx.span);
729
+ });
702
730
  while (true) {
703
731
  await this.systemDatabase.checkIfCanceled(wfid);
704
732
  let txn_snapshot = 'invalid';
@@ -707,7 +735,7 @@ class DBOSExecutor {
707
735
  // If the UUID is preset, it is possible this execution previously happened. Check, and return its original result if it did.
708
736
  // 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.
709
737
  let prevResult = exports.dbosNull;
710
- const queryFunc = (sql, args) => this.userDatabase.queryWithClient(client, sql, ...args);
738
+ const queryFunc = (sql, args) => userDB.queryWithClient(client, sql, ...args);
711
739
  if (pctx.presetID) {
712
740
  const executionResult = await this.#checkExecution(queryFunc, wfid, funcId, txn.name);
713
741
  prevResult = executionResult.result;
@@ -728,32 +756,33 @@ class DBOSExecutor {
728
756
  // Collect snapshot information for read-only transactions and non-preset UUID transactions, if not already collected above
729
757
  txn_snapshot = await DBOSExecutor.#retrieveSnapshot(queryFunc);
730
758
  }
731
- if (this.debugMode && prevResult === exports.dbosNull) {
759
+ if (this.#debugMode && prevResult === exports.dbosNull) {
732
760
  throw new error_1.DBOSDebuggerError(`Failed to find the recorded output for the transaction: workflow UUID ${wfid}, step number ${funcId}`);
733
761
  }
734
762
  // Execute the user's transaction.
735
763
  const ctxlog = this.ctxLogger;
736
764
  const result = await (async function () {
737
765
  try {
738
- return await (0, context_1.runWithParentContext)(pctx, {
739
- authenticatedRoles: pctx?.authenticatedRoles,
740
- authenticatedUser: pctx?.authenticatedUser,
741
- workflowId: wfid,
742
- curTxFunctionId: funcId,
743
- parentCtx: pctx,
744
- sqlClient: client,
745
- logger: ctxlog,
746
- span,
747
- }, async () => {
748
- const tf = txn;
749
- return await tf.call(clsinst, ...args);
766
+ return await api_1.context.with(api_1.trace.setSpan(api_1.context.active(), span), async () => {
767
+ return await (0, context_1.runWithParentContext)(pctx, {
768
+ authenticatedRoles: pctx?.authenticatedRoles,
769
+ authenticatedUser: pctx?.authenticatedUser,
770
+ workflowId: wfid,
771
+ curTxFunctionId: funcId,
772
+ parentCtx: pctx,
773
+ sqlClient: client,
774
+ logger: ctxlog,
775
+ }, async () => {
776
+ const tf = txn;
777
+ return await tf.call(clsinst, ...args);
778
+ });
750
779
  });
751
780
  }
752
781
  catch (e) {
753
782
  return e instanceof Error ? e : new Error(`${e}`);
754
783
  }
755
784
  })();
756
- if (this.debugMode) {
785
+ if (this.#debugMode) {
757
786
  if (prevResult instanceof Error) {
758
787
  throw prevResult;
759
788
  }
@@ -770,11 +799,11 @@ class DBOSExecutor {
770
799
  // Record the execution, commit, and return.
771
800
  try {
772
801
  // Synchronously record the output of write transactions and obtain the transaction ID.
773
- const pg_txn_id = await this.#recordOutput(queryFunc, wfid, funcId, txn_snapshot, result, (error) => this.userDatabase.isKeyConflictError(error), txn.name);
802
+ const pg_txn_id = await this.#recordOutput(queryFunc, wfid, funcId, txn_snapshot, result, (error) => userDB.isKeyConflictError(error), txn.name);
774
803
  span.setAttribute('pg_txn_id', pg_txn_id);
775
804
  }
776
805
  catch (error) {
777
- if (this.userDatabase.isFailedSqlTransactionError(error)) {
806
+ if (userDB.isFailedSqlTransactionError(error)) {
778
807
  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.`);
779
808
  throw new error_1.DBOSFailedSqlTransactionError(wfid, txn.name);
780
809
  }
@@ -785,15 +814,15 @@ class DBOSExecutor {
785
814
  return result;
786
815
  };
787
816
  try {
788
- const result = await this.userDatabase.transaction(wrappedTransaction, txnReg.txnConfig);
817
+ const result = await userDB.transaction(wrappedTransaction, txnReg.txnConfig);
789
818
  span.setStatus({ code: api_1.SpanStatusCode.OK });
790
819
  this.tracer.endSpan(span);
791
820
  return result;
792
821
  }
793
822
  catch (err) {
794
823
  const e = err;
795
- if (!prevResultFound && !this.debugMode && !(e instanceof error_1.DBOSUnexpectedStepError)) {
796
- if (this.userDatabase.isRetriableTransactionError(err)) {
824
+ if (!prevResultFound && !this.#debugMode && !(e instanceof error_1.DBOSUnexpectedStepError)) {
825
+ if (userDB.isRetriableTransactionError(err)) {
797
826
  // serialization_failure in PostgreSQL
798
827
  span.addEvent('TXN SERIALIZATION FAILURE', { retryWaitMillis: retryWaitMillis }, performance.now());
799
828
  // Retry serialization failures.
@@ -804,9 +833,9 @@ class DBOSExecutor {
804
833
  }
805
834
  // Record and throw other errors.
806
835
  const e = err;
807
- await this.userDatabase.transaction(async (client) => {
808
- const func = (sql, args) => this.userDatabase.queryWithClient(client, sql, ...args);
809
- await this.#recordError(func, wfid, funcId, txn_snapshot, e, (error) => this.userDatabase.isKeyConflictError(error), txn.name);
836
+ await userDB.transaction(async (client) => {
837
+ const func = (sql, args) => userDB.queryWithClient(client, sql, ...args);
838
+ await this.#recordError(func, wfid, funcId, txn_snapshot, e, (error) => userDB.isKeyConflictError(error), txn.name);
810
839
  }, { isolationLevel: transaction_1.IsolationLevel.ReadCommitted });
811
840
  }
812
841
  span.setStatus({ code: api_1.SpanStatusCode.ERROR, message: e.message });
@@ -836,7 +865,7 @@ class DBOSExecutor {
836
865
  const pctx = (0, context_1.getCurrentContextStore)();
837
866
  const wfid = pctx.workflowId;
838
867
  await this.systemDatabase.checkIfCanceled(wfid);
839
- const executeLocally = this.debugMode || (procConfig.executeLocally ?? false);
868
+ const executeLocally = this.#debugMode || (procConfig.executeLocally ?? false);
840
869
  const funcId = (0, context_1.functionIDGetIncrement)();
841
870
  const span = this.tracer.startSpan(proc.name, {
842
871
  operationUUID: wfid,
@@ -847,7 +876,7 @@ class DBOSExecutor {
847
876
  authenticatedRoles: pctx.authenticatedRoles ?? [],
848
877
  isolationLevel: procInfo.procConfig.isolationLevel,
849
878
  executeLocally,
850
- }, pctx.span);
879
+ });
851
880
  try {
852
881
  const result = executeLocally
853
882
  ? await this.#callProcedureFunctionLocal(proc, args, span, procInfo, funcId)
@@ -865,6 +894,11 @@ class DBOSExecutor {
865
894
  }
866
895
  }
867
896
  async #callProcedureFunctionLocal(proc, args, span, procInfo, funcId) {
897
+ const procPool = this.#procedurePool;
898
+ const userDB = this.#userDatabase;
899
+ if (!procPool || !userDB) {
900
+ throw new Error('User database not enabled.');
901
+ }
868
902
  let retryWaitMillis = 1;
869
903
  const backoffFactor = 1.5;
870
904
  const maxRetryWaitMs = 2000; // Maximum wait 2 seconds.
@@ -875,7 +909,7 @@ class DBOSExecutor {
875
909
  let txn_snapshot = 'invalid';
876
910
  const wrappedProcedure = async (client) => {
877
911
  let prevResult = exports.dbosNull;
878
- const queryFunc = (sql, args) => this.procedurePool.query(sql, args).then((v) => v.rows);
912
+ const queryFunc = (sql, args) => procPool.query(sql, args).then((v) => v.rows);
879
913
  if (pctx.presetID) {
880
914
  const executionResult = await this.#checkExecution(queryFunc, wfid, funcId, proc.name);
881
915
  prevResult = executionResult.result;
@@ -895,7 +929,7 @@ class DBOSExecutor {
895
929
  // Collect snapshot information for read-only transactions and non-preset UUID transactions, if not already collected above
896
930
  txn_snapshot = await DBOSExecutor.#retrieveSnapshot(queryFunc);
897
931
  }
898
- if (this.debugMode && prevResult === exports.dbosNull) {
932
+ if (this.#debugMode && prevResult === exports.dbosNull) {
899
933
  throw new error_1.DBOSDebuggerError(`Failed to find the recorded output for the procedure: workflow UUID ${wfid}, step number ${funcId}`);
900
934
  }
901
935
  // Execute the user's transaction.
@@ -908,23 +942,24 @@ class DBOSExecutor {
908
942
  throw new error_1.DBOSInvalidWorkflowTransitionError();
909
943
  if (!(0, context_1.isInWorkflowCtx)(pctx))
910
944
  throw new error_1.DBOSInvalidWorkflowTransitionError();
911
- return await (0, context_1.runWithParentContext)(pctx, {
912
- curTxFunctionId: funcId,
913
- parentCtx: pctx,
914
- isInStoredProc: true,
915
- sqlClient: client,
916
- logger: ctxlog,
917
- span,
918
- }, async () => {
919
- const pf = proc;
920
- return await pf(...args);
945
+ return await api_1.context.with(api_1.trace.setSpan(api_1.context.active(), span), async () => {
946
+ return await (0, context_1.runWithParentContext)(pctx, {
947
+ curTxFunctionId: funcId,
948
+ parentCtx: pctx,
949
+ isInStoredProc: true,
950
+ sqlClient: client,
951
+ logger: ctxlog,
952
+ }, async () => {
953
+ const pf = proc;
954
+ return await pf(...args);
955
+ });
921
956
  });
922
957
  }
923
958
  catch (e) {
924
959
  return e instanceof Error ? e : new Error(`${e}`);
925
960
  }
926
961
  })();
927
- if (this.debugMode) {
962
+ if (this.#debugMode) {
928
963
  if (prevResult instanceof Error) {
929
964
  throw prevResult;
930
965
  }
@@ -953,8 +988,8 @@ class DBOSExecutor {
953
988
  return result;
954
989
  }
955
990
  catch (err) {
956
- if (!this.debugMode) {
957
- if (this.userDatabase.isRetriableTransactionError(err)) {
991
+ if (!this.#debugMode) {
992
+ if (userDB.isRetriableTransactionError(err)) {
958
993
  // serialization_failure in PostgreSQL
959
994
  span.addEvent('TXN SERIALIZATION FAILURE', { retryWaitMillis: retryWaitMillis }, performance.now());
960
995
  // Retry serialization failures.
@@ -969,9 +1004,9 @@ class DBOSExecutor {
969
1004
  const func = (sql, args) => client.query(sql, args).then((v) => v.rows);
970
1005
  await this.#recordError(func, wfid, funcId, txn_snapshot, e, user_database_1.pgNodeIsKeyConflictError, proc.name);
971
1006
  }, { isolationLevel: transaction_1.IsolationLevel.ReadCommitted });
972
- await this.userDatabase.transaction(async (client) => {
973
- const func = (sql, args) => this.userDatabase.queryWithClient(client, sql, ...args);
974
- await this.#recordError(func, wfid, funcId, txn_snapshot, e, (error) => this.userDatabase.isKeyConflictError(error), proc.name);
1007
+ await userDB.transaction(async (client) => {
1008
+ const func = (sql, args) => userDB.queryWithClient(client, sql, ...args);
1009
+ await this.#recordError(func, wfid, funcId, txn_snapshot, e, (error) => userDB.isKeyConflictError(error), proc.name);
975
1010
  }, { isolationLevel: transaction_1.IsolationLevel.ReadCommitted });
976
1011
  }
977
1012
  throw err;
@@ -979,7 +1014,7 @@ class DBOSExecutor {
979
1014
  }
980
1015
  }
981
1016
  async #callProcedureFunctionRemote(proc, args, span, config, funcId) {
982
- if (this.debugMode) {
1017
+ if (this.#debugMode) {
983
1018
  throw new error_1.DBOSDebuggerError("Can't invoke stored procedure in debug mode.");
984
1019
  }
985
1020
  const pctx = (0, context_1.getCurrentContextStore)();
@@ -1013,7 +1048,10 @@ class DBOSExecutor {
1013
1048
  return output;
1014
1049
  }
1015
1050
  async #invokeStoredProc(proc, args) {
1016
- const client = await this.procedurePool.connect();
1051
+ if (!this.#procedurePool) {
1052
+ throw new Error('User Database not enabled.');
1053
+ }
1054
+ const client = await this.#procedurePool.connect();
1017
1055
  const log = (msg) => this.#logNotice(msg);
1018
1056
  const procname = (0, decorators_1.getRegisteredFunctionFullName)(proc);
1019
1057
  const plainProcName = `${procname.className}_${procname.name}_p`;
@@ -1029,7 +1067,10 @@ class DBOSExecutor {
1029
1067
  }
1030
1068
  }
1031
1069
  async invokeStoredProcFunction(func, config) {
1032
- const client = await this.procedurePool.connect();
1070
+ if (!this.#procedurePool) {
1071
+ throw new Error('User Database not enabled.');
1072
+ }
1073
+ const client = await this.#procedurePool.connect();
1033
1074
  try {
1034
1075
  const readOnly = config.readOnly ?? false;
1035
1076
  const isolationLevel = config.isolationLevel ?? transaction_1.IsolationLevel.Serializable;
@@ -1094,7 +1135,7 @@ class DBOSExecutor {
1094
1135
  intervalSeconds: stepConfig.intervalSeconds,
1095
1136
  maxAttempts: stepConfig.maxAttempts,
1096
1137
  backoffRate: stepConfig.backoffRate,
1097
- }, lctx.span);
1138
+ });
1098
1139
  // Check if this execution previously happened, returning its original result if it did.
1099
1140
  const checkr = await this.systemDatabase.getOperationResultAndThrowIfCancelled(wfid, funcID);
1100
1141
  if (checkr) {
@@ -1107,7 +1148,7 @@ class DBOSExecutor {
1107
1148
  this.tracer.endSpan(span);
1108
1149
  return check;
1109
1150
  }
1110
- if (this.debugMode) {
1151
+ if (this.#debugMode) {
1111
1152
  throw new error_1.DBOSDebuggerError(`Failed to find the recorded output for the step: workflow UUID: ${wfid}, step number: ${funcID}`);
1112
1153
  }
1113
1154
  const maxAttempts = stepConfig.maxAttempts ?? 3;
@@ -1126,7 +1167,7 @@ class DBOSExecutor {
1126
1167
  try {
1127
1168
  await this.systemDatabase.checkIfCanceled(wfid);
1128
1169
  let cresult;
1129
- await (0, context_1.runInStepContext)(lctx, funcID, span, maxAttempts, attemptNum, async () => {
1170
+ await (0, context_1.runInStepContext)(lctx, funcID, maxAttempts, attemptNum, async () => {
1130
1171
  const sf = stepFn;
1131
1172
  cresult = await sf.call(clsInst, ...args);
1132
1173
  });
@@ -1150,9 +1191,11 @@ class DBOSExecutor {
1150
1191
  else {
1151
1192
  try {
1152
1193
  let cresult;
1153
- await (0, context_1.runInStepContext)(lctx, funcID, span, maxAttempts, undefined, async () => {
1154
- const sf = stepFn;
1155
- cresult = await sf.call(clsInst, ...args);
1194
+ await api_1.context.with(api_1.trace.setSpan(api_1.context.active(), span), async () => {
1195
+ await (0, context_1.runInStepContext)(lctx, funcID, maxAttempts, undefined, async () => {
1196
+ const sf = stepFn;
1197
+ cresult = await sf.call(clsInst, ...args);
1198
+ });
1156
1199
  });
1157
1200
  result = cresult;
1158
1201
  }
@@ -1207,7 +1250,7 @@ class DBOSExecutor {
1207
1250
  */
1208
1251
  forkWorkflow(workflowID, startStep, options = {}) {
1209
1252
  const newWorkflowID = options.newWorkflowID ?? (0, context_1.getNextWFID)(undefined);
1210
- return (0, workflow_management_1.forkWorkflow)(this.systemDatabase, this.userDatabase, workflowID, startStep, { ...options, newWorkflowID });
1253
+ return (0, workflow_management_1.forkWorkflow)(this.systemDatabase, this.#userDatabase, workflowID, startStep, { ...options, newWorkflowID });
1211
1254
  }
1212
1255
  /**
1213
1256
  * Retrieve a handle for a workflow UUID.
@@ -1251,14 +1294,17 @@ class DBOSExecutor {
1251
1294
  return (0, workflow_management_1.listQueuedWorkflows)(this.systemDatabase, input);
1252
1295
  }
1253
1296
  async listWorkflowSteps(workflowID) {
1254
- return (0, workflow_management_1.listWorkflowSteps)(this.systemDatabase, this.userDatabase, workflowID);
1297
+ return (0, workflow_management_1.listWorkflowSteps)(this.systemDatabase, this.#userDatabase, workflowID);
1255
1298
  }
1256
1299
  async queryUserDB(sql, params) {
1300
+ if (!this.#userDatabase) {
1301
+ throw new Error('User database not enabled.');
1302
+ }
1257
1303
  if (params !== undefined) {
1258
- return await this.userDatabase.query(sql, ...params);
1304
+ return await this.#userDatabase.query(sql, ...params);
1259
1305
  }
1260
1306
  else {
1261
- return await this.userDatabase.query(sql);
1307
+ return await this.#userDatabase.query(sql);
1262
1308
  }
1263
1309
  }
1264
1310
  /* INTERNAL HELPERS */
@@ -1267,7 +1313,7 @@ class DBOSExecutor {
1267
1313
  * It runs to completion all pending workflows that were executing when the previous executor failed.
1268
1314
  */
1269
1315
  async recoverPendingWorkflows(executorIDs = ['local']) {
1270
- if (this.debugMode) {
1316
+ if (this.#debugMode) {
1271
1317
  throw new error_1.DBOSDebuggerError('Cannot recover pending workflows in debug mode.');
1272
1318
  }
1273
1319
  const handlerArray = [];
@@ -1305,7 +1351,7 @@ class DBOSExecutor {
1305
1351
  return handlerArray;
1306
1352
  }
1307
1353
  async initEventReceivers() {
1308
- this.wfqEnded = wfqueue_1.wfQueueRunner.dispatchLoop(this);
1354
+ this.#wfqEnded = wfqueue_1.wfQueueRunner.dispatchLoop(this);
1309
1355
  for (const lcl of (0, decorators_1.getLifecycleListeners)()) {
1310
1356
  await lcl.initialize?.();
1311
1357
  }
@@ -1325,7 +1371,7 @@ class DBOSExecutor {
1325
1371
  if (stopQueueThread) {
1326
1372
  try {
1327
1373
  wfqueue_1.wfQueueRunner.stop();
1328
- await this.wfqEnded;
1374
+ await this.#wfqEnded;
1329
1375
  }
1330
1376
  catch (err) {
1331
1377
  const e = err;
@@ -1362,7 +1408,7 @@ class DBOSExecutor {
1362
1408
  // Should be temporary workflows. Parse the name of the workflow.
1363
1409
  const wfName = wfStatus.workflowName;
1364
1410
  const nameArr = wfName.split('-');
1365
- if (!nameArr[0].startsWith(DBOSExecutor.tempWorkflowName)) {
1411
+ if (!nameArr[0].startsWith(DBOSExecutor.#tempWorkflowName)) {
1366
1412
  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?`);
1367
1413
  }
1368
1414
  if (nameArr[1] === exports.TempWorkflowType.transaction) {