@dbos-inc/dbos-sdk 2.2.10-preview.g90e74a1e32 → 2.3.7-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 (175) hide show
  1. package/.husky/pre-commit +1 -0
  2. package/.prettierignore +3 -0
  3. package/.prettierrc +9 -0
  4. package/CODE_OF_CONDUCT.md +24 -18
  5. package/CONTRIBUTING.md +12 -10
  6. package/README.md +2 -2
  7. package/compose.yaml +17 -17
  8. package/dbos-config.schema.json +4 -13
  9. package/dist/schemas/user_db_schema.d.ts.map +1 -1
  10. package/dist/schemas/user_db_schema.js.map +1 -1
  11. package/dist/src/context.d.ts +12 -12
  12. package/dist/src/context.d.ts.map +1 -1
  13. package/dist/src/context.js +9 -9
  14. package/dist/src/context.js.map +1 -1
  15. package/dist/src/data_validation.d.ts +1 -1
  16. package/dist/src/data_validation.d.ts.map +1 -1
  17. package/dist/src/data_validation.js +14 -8
  18. package/dist/src/data_validation.js.map +1 -1
  19. package/dist/src/dbos-executor.d.ts +4 -2
  20. package/dist/src/dbos-executor.d.ts.map +1 -1
  21. package/dist/src/dbos-executor.js +131 -114
  22. package/dist/src/dbos-executor.js.map +1 -1
  23. package/dist/src/dbos-runtime/cli.d.ts +3 -3
  24. package/dist/src/dbos-runtime/cli.d.ts.map +1 -1
  25. package/dist/src/dbos-runtime/cli.js +79 -38
  26. package/dist/src/dbos-runtime/cli.js.map +1 -1
  27. package/dist/src/dbos-runtime/cloudutils/authentication.d.ts +1 -1
  28. package/dist/src/dbos-runtime/cloudutils/authentication.d.ts.map +1 -1
  29. package/dist/src/dbos-runtime/cloudutils/authentication.js +14 -14
  30. package/dist/src/dbos-runtime/cloudutils/authentication.js.map +1 -1
  31. package/dist/src/dbos-runtime/cloudutils/cloudutils.d.ts +2 -2
  32. package/dist/src/dbos-runtime/cloudutils/cloudutils.d.ts.map +1 -1
  33. package/dist/src/dbos-runtime/cloudutils/cloudutils.js +32 -32
  34. package/dist/src/dbos-runtime/cloudutils/cloudutils.js.map +1 -1
  35. package/dist/src/dbos-runtime/cloudutils/databases.d.ts +2 -2
  36. package/dist/src/dbos-runtime/cloudutils/databases.d.ts.map +1 -1
  37. package/dist/src/dbos-runtime/cloudutils/databases.js +25 -21
  38. package/dist/src/dbos-runtime/cloudutils/databases.js.map +1 -1
  39. package/dist/src/dbos-runtime/commands.d.ts +1 -1
  40. package/dist/src/dbos-runtime/commands.js +9 -9
  41. package/dist/src/dbos-runtime/config.d.ts +7 -7
  42. package/dist/src/dbos-runtime/config.d.ts.map +1 -1
  43. package/dist/src/dbos-runtime/config.js +30 -23
  44. package/dist/src/dbos-runtime/config.js.map +1 -1
  45. package/dist/src/dbos-runtime/configure.d.ts.map +1 -1
  46. package/dist/src/dbos-runtime/configure.js.map +1 -1
  47. package/dist/src/dbos-runtime/db_connection.d.ts.map +1 -1
  48. package/dist/src/dbos-runtime/db_connection.js +2 -2
  49. package/dist/src/dbos-runtime/db_connection.js.map +1 -1
  50. package/dist/src/dbos-runtime/db_wizard.d.ts +1 -1
  51. package/dist/src/dbos-runtime/db_wizard.d.ts.map +1 -1
  52. package/dist/src/dbos-runtime/db_wizard.js +18 -18
  53. package/dist/src/dbos-runtime/db_wizard.js.map +1 -1
  54. package/dist/src/dbos-runtime/debug.d.ts +2 -2
  55. package/dist/src/dbos-runtime/debug.d.ts.map +1 -1
  56. package/dist/src/dbos-runtime/debug.js +4 -4
  57. package/dist/src/dbos-runtime/debug.js.map +1 -1
  58. package/dist/src/dbos-runtime/migrate.d.ts +2 -2
  59. package/dist/src/dbos-runtime/migrate.d.ts.map +1 -1
  60. package/dist/src/dbos-runtime/migrate.js +14 -10
  61. package/dist/src/dbos-runtime/migrate.js.map +1 -1
  62. package/dist/src/dbos-runtime/reset.d.ts +2 -2
  63. package/dist/src/dbos-runtime/reset.js +2 -2
  64. package/dist/src/dbos-runtime/reset.js.map +1 -1
  65. package/dist/src/dbos-runtime/runtime.d.ts.map +1 -1
  66. package/dist/src/dbos-runtime/runtime.js +4 -4
  67. package/dist/src/dbos-runtime/runtime.js.map +1 -1
  68. package/dist/src/dbos-runtime/workflow_management.d.ts +5 -4
  69. package/dist/src/dbos-runtime/workflow_management.d.ts.map +1 -1
  70. package/dist/src/dbos-runtime/workflow_management.js +34 -14
  71. package/dist/src/dbos-runtime/workflow_management.js.map +1 -1
  72. package/dist/src/dbos.d.ts +23 -23
  73. package/dist/src/dbos.d.ts.map +1 -1
  74. package/dist/src/dbos.js +59 -59
  75. package/dist/src/dbos.js.map +1 -1
  76. package/dist/src/debugpoint.d.ts.map +1 -1
  77. package/dist/src/debugpoint.js +4 -4
  78. package/dist/src/debugpoint.js.map +1 -1
  79. package/dist/src/decorators.d.ts +8 -8
  80. package/dist/src/decorators.d.ts.map +1 -1
  81. package/dist/src/decorators.js +36 -33
  82. package/dist/src/decorators.js.map +1 -1
  83. package/dist/src/error.d.ts.map +1 -1
  84. package/dist/src/error.js +6 -5
  85. package/dist/src/error.js.map +1 -1
  86. package/dist/src/eventreceiver.d.ts +1 -1
  87. package/dist/src/eventreceiver.d.ts.map +1 -1
  88. package/dist/src/httpServer/handler.d.ts +8 -8
  89. package/dist/src/httpServer/handler.d.ts.map +1 -1
  90. package/dist/src/httpServer/handler.js.map +1 -1
  91. package/dist/src/httpServer/handlerTypes.d.ts.map +1 -1
  92. package/dist/src/httpServer/handlerTypes.js.map +1 -1
  93. package/dist/src/httpServer/middleware.d.ts +9 -9
  94. package/dist/src/httpServer/middleware.d.ts.map +1 -1
  95. package/dist/src/httpServer/middleware.js +6 -6
  96. package/dist/src/httpServer/middleware.js.map +1 -1
  97. package/dist/src/httpServer/server.d.ts +2 -2
  98. package/dist/src/httpServer/server.d.ts.map +1 -1
  99. package/dist/src/httpServer/server.js +27 -33
  100. package/dist/src/httpServer/server.js.map +1 -1
  101. package/dist/src/index.d.ts +16 -16
  102. package/dist/src/index.d.ts.map +1 -1
  103. package/dist/src/index.js.map +1 -1
  104. package/dist/src/kafka/kafka.d.ts.map +1 -1
  105. package/dist/src/kafka/kafka.js +2 -2
  106. package/dist/src/kafka/kafka.js.map +1 -1
  107. package/dist/src/procedure.d.ts +6 -6
  108. package/dist/src/procedure.d.ts.map +1 -1
  109. package/dist/src/procedure.js.map +1 -1
  110. package/dist/src/scheduler/crontab.d.ts.map +1 -1
  111. package/dist/src/scheduler/crontab.js +54 -33
  112. package/dist/src/scheduler/crontab.js.map +1 -1
  113. package/dist/src/scheduler/scheduler.d.ts +3 -3
  114. package/dist/src/scheduler/scheduler.d.ts.map +1 -1
  115. package/dist/src/scheduler/scheduler.js +7 -7
  116. package/dist/src/scheduler/scheduler.js.map +1 -1
  117. package/dist/src/step.d.ts +4 -4
  118. package/dist/src/step.d.ts.map +1 -1
  119. package/dist/src/step.js.map +1 -1
  120. package/dist/src/system_database.d.ts +16 -11
  121. package/dist/src/system_database.d.ts.map +1 -1
  122. package/dist/src/system_database.js +136 -56
  123. package/dist/src/system_database.js.map +1 -1
  124. package/dist/src/telemetry/collector.d.ts +3 -3
  125. package/dist/src/telemetry/exporters.d.ts +1 -1
  126. package/dist/src/telemetry/exporters.js.map +1 -1
  127. package/dist/src/telemetry/index.d.ts +5 -5
  128. package/dist/src/telemetry/logs.d.ts +4 -4
  129. package/dist/src/telemetry/logs.d.ts.map +1 -1
  130. package/dist/src/telemetry/logs.js +18 -18
  131. package/dist/src/telemetry/logs.js.map +1 -1
  132. package/dist/src/telemetry/traces.d.ts +3 -3
  133. package/dist/src/telemetry/traces.js +7 -7
  134. package/dist/src/testing/testing_runtime.d.ts +11 -11
  135. package/dist/src/testing/testing_runtime.d.ts.map +1 -1
  136. package/dist/src/testing/testing_runtime.js +15 -8
  137. package/dist/src/testing/testing_runtime.js.map +1 -1
  138. package/dist/src/transaction.d.ts +6 -6
  139. package/dist/src/transaction.d.ts.map +1 -1
  140. package/dist/src/transaction.js +4 -4
  141. package/dist/src/transaction.js.map +1 -1
  142. package/dist/src/user_database.d.ts +4 -4
  143. package/dist/src/user_database.d.ts.map +1 -1
  144. package/dist/src/user_database.js +45 -45
  145. package/dist/src/user_database.js.map +1 -1
  146. package/dist/src/utils.d.ts.map +1 -1
  147. package/dist/src/utils.js +6 -12
  148. package/dist/src/utils.js.map +1 -1
  149. package/dist/src/wfqueue.d.ts +1 -1
  150. package/dist/src/wfqueue.d.ts.map +1 -1
  151. package/dist/src/wfqueue.js +5 -7
  152. package/dist/src/wfqueue.js.map +1 -1
  153. package/dist/src/workflow.d.ts +17 -10
  154. package/dist/src/workflow.d.ts.map +1 -1
  155. package/dist/src/workflow.js +19 -18
  156. package/dist/src/workflow.js.map +1 -1
  157. package/dist/tsconfig.build.tsbuildinfo +1 -1
  158. package/eslint.config.js +29 -27
  159. package/migrations/20240123182943_schema.js +7 -8
  160. package/migrations/20240123183021_tables.js +52 -48
  161. package/migrations/20240123183025_indexes.js +11 -14
  162. package/migrations/20240123183030_triggers.js +7 -8
  163. package/migrations/20240124015239_status_timestamp.js +12 -18
  164. package/migrations/20240201213211_replica_identity.js +8 -11
  165. package/migrations/20240205223925_foreign_keys.js +40 -18
  166. package/migrations/20240207192338_executor_id_index.js +8 -10
  167. package/migrations/20240430090000_tables.js +8 -10
  168. package/migrations/20240516004341_application_version.js +10 -12
  169. package/migrations/20240517000000_status_class_config.js +10 -14
  170. package/migrations/20240621000000_workflow_tries.js +8 -12
  171. package/migrations/20240924000000_workflowqueue.js +32 -23
  172. package/migrations/20241009150000_event_dispatch_kv.js +12 -14
  173. package/migrations/20252101000000_workflow_queues_executor_id.js +7 -9
  174. package/package.json +9 -2
  175. package/src/dbos-runtime/cloudutils/README.md +1 -1
@@ -29,17 +29,17 @@ const wfqueue_1 = require("./wfqueue");
29
29
  const debugpoint_1 = require("./debugpoint");
30
30
  exports.dbosNull = {};
31
31
  exports.OperationType = {
32
- HANDLER: "handler",
33
- WORKFLOW: "workflow",
34
- TRANSACTION: "transaction",
35
- COMMUNICATOR: "communicator",
36
- PROCEDURE: "procedure",
32
+ HANDLER: 'handler',
33
+ WORKFLOW: 'workflow',
34
+ TRANSACTION: 'transaction',
35
+ COMMUNICATOR: 'communicator',
36
+ PROCEDURE: 'procedure',
37
37
  };
38
38
  const TempWorkflowType = {
39
- transaction: "transaction",
40
- procedure: "procedure",
41
- external: "external",
42
- send: "send",
39
+ transaction: 'transaction',
40
+ procedure: 'procedure',
41
+ external: 'external',
42
+ send: 'send',
43
43
  };
44
44
  class DBOSExecutor {
45
45
  config;
@@ -50,14 +50,14 @@ class DBOSExecutor {
50
50
  systemDatabase;
51
51
  procedurePool;
52
52
  // Temporary workflows are created by calling transaction/send/recv directly from the executor class
53
- static tempWorkflowName = "temp_workflow";
53
+ static tempWorkflowName = 'temp_workflow';
54
54
  workflowInfoMap = new Map([
55
55
  // We initialize the map with an entry for temporary workflows.
56
56
  [
57
57
  DBOSExecutor.tempWorkflowName,
58
58
  {
59
59
  workflow: async () => {
60
- this.logger.error("UNREACHABLE: Indirect invoke of temp workflow");
60
+ this.logger.error('UNREACHABLE: Indirect invoke of temp workflow');
61
61
  return Promise.resolve();
62
62
  },
63
63
  config: {},
@@ -77,7 +77,7 @@ class DBOSExecutor {
77
77
  static defaultNotificationTimeoutSec = 60;
78
78
  debugMode;
79
79
  debugProxy;
80
- static systemDBSchemaName = "dbos";
80
+ static systemDBSchemaName = 'dbos';
81
81
  logger;
82
82
  tracer;
83
83
  // eslint-disable-next-line @typescript-eslint/ban-types
@@ -86,7 +86,7 @@ class DBOSExecutor {
86
86
  eventReceivers = [];
87
87
  scheduler = undefined;
88
88
  wfqEnded = undefined;
89
- executorID = process.env.DBOS__VMID || "local";
89
+ executorID = process.env.DBOS__VMID || 'local';
90
90
  static globalInstance = undefined;
91
91
  /* WORKFLOW EXECUTOR LIFE CYCLE MANAGEMENT */
92
92
  constructor(config, systemDatabase) {
@@ -96,7 +96,7 @@ class DBOSExecutor {
96
96
  // Set configured environment variables
97
97
  if (config.env) {
98
98
  for (const [key, value] of Object.entries(config.env)) {
99
- if (typeof value === "string") {
99
+ if (typeof value === 'string') {
100
100
  process.env[key] = value;
101
101
  }
102
102
  else {
@@ -115,7 +115,7 @@ class DBOSExecutor {
115
115
  this.logger = new logs_1.GlobalLogger(this.telemetryCollector, this.config.telemetry?.logs);
116
116
  this.tracer = new traces_1.Tracer(this.telemetryCollector);
117
117
  if (this.debugMode) {
118
- this.logger.info("Running in debug mode!");
118
+ this.logger.info('Running in debug mode!');
119
119
  if (this.debugProxy) {
120
120
  try {
121
121
  const url = new URL(this.config.debugProxy);
@@ -131,11 +131,11 @@ class DBOSExecutor {
131
131
  }
132
132
  this.procedurePool = new pg_1.Pool(this.config.poolConfig);
133
133
  if (systemDatabase) {
134
- this.logger.debug("Using provided system database"); // XXX print the name or something
134
+ this.logger.debug('Using provided system database'); // XXX print the name or something
135
135
  this.systemDatabase = systemDatabase;
136
136
  }
137
137
  else {
138
- this.logger.debug("Using Postgres system database");
138
+ this.logger.debug('Using Postgres system database');
139
139
  this.systemDatabase = new system_database_1.PostgresSystemDatabase(this.config.poolConfig, this.config.system_database, this.logger);
140
140
  }
141
141
  this.flushBufferID = setInterval(() => {
@@ -144,7 +144,7 @@ class DBOSExecutor {
144
144
  void this.flushWorkflowBuffers();
145
145
  }
146
146
  }, this.flushBufferIntervalMs);
147
- this.logger.debug("Started workflow status buffer worker");
147
+ this.logger.debug('Started workflow status buffer worker');
148
148
  this.initialized = false;
149
149
  DBOSExecutor.globalInstance = this;
150
150
  }
@@ -154,25 +154,26 @@ class DBOSExecutor {
154
154
  if (userDbClient === user_database_1.UserDatabaseName.PRISMA) {
155
155
  // TODO: make Prisma work with debugger proxy.
156
156
  // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-require-imports
157
- 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
157
+ 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
158
+ this.userDatabase = new user_database_1.PrismaUserDatabase(
158
159
  // eslint-disable-next-line @typescript-eslint/no-unsafe-argument, @typescript-eslint/no-unsafe-call
159
- this.userDatabase = new user_database_1.PrismaUserDatabase(new PrismaClient({
160
+ new PrismaClient({
160
161
  datasources: {
161
162
  db: {
162
163
  url: `postgresql://${userDBConfig.user}:${userDBConfig.password}@${userDBConfig.host}:${userDBConfig.port}/${userDBConfig.database}`,
163
164
  },
164
- }
165
+ },
165
166
  }));
166
- this.logger.debug("Loaded Prisma user database");
167
+ this.logger.debug('Loaded Prisma user database');
167
168
  }
168
169
  else if (userDbClient === user_database_1.UserDatabaseName.TYPEORM) {
169
170
  // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-require-imports
170
- const DataSourceExports = require("typeorm");
171
+ const DataSourceExports = require('typeorm');
171
172
  try {
172
173
  this.userDatabase = new user_database_1.TypeORMDatabase(
173
174
  // eslint-disable-next-line @typescript-eslint/no-unsafe-argument, @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-member-access
174
175
  new DataSourceExports.DataSource({
175
- type: "postgres", // perhaps should move to config file
176
+ type: 'postgres', // perhaps should move to config file
176
177
  host: userDBConfig.host,
177
178
  port: userDBConfig.port,
178
179
  username: userDBConfig.user,
@@ -186,11 +187,11 @@ class DBOSExecutor {
186
187
  s.message = `Error loading TypeORM user database: ${s.message}`;
187
188
  this.logger.error(s);
188
189
  }
189
- this.logger.debug("Loaded TypeORM user database");
190
+ this.logger.debug('Loaded TypeORM user database');
190
191
  }
191
192
  else if (userDbClient === user_database_1.UserDatabaseName.KNEX) {
192
193
  const knexConfig = {
193
- client: "postgres",
194
+ client: 'postgres',
194
195
  connection: {
195
196
  host: userDBConfig.host,
196
197
  port: userDBConfig.port,
@@ -201,21 +202,21 @@ class DBOSExecutor {
201
202
  },
202
203
  };
203
204
  this.userDatabase = new user_database_1.KnexUserDatabase((0, knex_1.default)(knexConfig));
204
- this.logger.debug("Loaded Knex user database");
205
+ this.logger.debug('Loaded Knex user database');
205
206
  }
206
207
  else if (userDbClient === user_database_1.UserDatabaseName.DRIZZLE) {
207
208
  // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-require-imports
208
- const DrizzleExports = require("drizzle-orm/node-postgres");
209
+ const DrizzleExports = require('drizzle-orm/node-postgres');
209
210
  const drizzlePool = new pg_1.Pool(userDBConfig);
210
211
  // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-member-access
211
212
  const drizzle = DrizzleExports.drizzle(drizzlePool, { schema: this.drizzleEntities });
212
213
  // eslint-disable-next-line @typescript-eslint/no-unsafe-argument
213
214
  this.userDatabase = new user_database_1.DrizzleUserDatabase(drizzlePool, drizzle);
214
- this.logger.debug("Loaded Drizzle user database");
215
+ this.logger.debug('Loaded Drizzle user database');
215
216
  }
216
217
  else {
217
218
  this.userDatabase = new user_database_1.PGNodeUserDatabase(userDBConfig);
218
- this.logger.debug("Loaded Postgres user database");
219
+ this.logger.debug('Loaded Postgres user database');
219
220
  }
220
221
  }
221
222
  #registerClass(cls) {
@@ -253,7 +254,7 @@ class DBOSExecutor {
253
254
  }
254
255
  async init(classes) {
255
256
  if (this.initialized) {
256
- this.logger.error("Workflow executor already initialized!");
257
+ this.logger.error('Workflow executor already initialized!');
257
258
  return;
258
259
  }
259
260
  if (!classes || !classes.length) {
@@ -267,7 +268,7 @@ class DBOSExecutor {
267
268
  * With TSORM, we take an array of entities (Function[]) and add them to this.entities:
268
269
  */
269
270
  if (Array.isArray(reg.ormEntities)) {
270
- this.typeormEntities = (this.typeormEntities).concat(reg.ormEntities);
271
+ this.typeormEntities = this.typeormEntities.concat(reg.ormEntities);
271
272
  length = reg.ormEntities.length;
272
273
  }
273
274
  else {
@@ -282,8 +283,8 @@ class DBOSExecutor {
282
283
  await (0, user_database_1.createDBIfDoesNotExist)(this.config.poolConfig, this.logger);
283
284
  this.configureDbClient();
284
285
  if (!this.userDatabase) {
285
- this.logger.error("No user database configured!");
286
- throw new error_1.DBOSInitializationError("No user database configured!");
286
+ this.logger.error('No user database configured!');
287
+ throw new error_1.DBOSInitializationError('No user database configured!');
287
288
  }
288
289
  for (const cls of classes) {
289
290
  this.#registerClass(cls);
@@ -324,30 +325,30 @@ class DBOSExecutor {
324
325
  for (const v of this.registeredOperations) {
325
326
  const m = v;
326
327
  if (m.init === true) {
327
- this.logger.debug("Executing init method: " + m.name);
328
+ this.logger.debug('Executing init method: ' + m.name);
328
329
  await m.origFunction(new context_1.InitContext(this));
329
330
  }
330
331
  }
331
332
  await this.recoverPendingWorkflows();
332
333
  }
333
- this.logger.info("Workflow executor initialized");
334
+ this.logger.info('Workflow executor initialized');
334
335
  }
335
336
  #logNotice(msg) {
336
337
  switch (msg.severity) {
337
- case "INFO":
338
- case "LOG":
339
- case "NOTICE":
338
+ case 'INFO':
339
+ case 'LOG':
340
+ case 'NOTICE':
340
341
  this.logger.info(msg.message);
341
342
  break;
342
- case "WARNING":
343
+ case 'WARNING':
343
344
  this.logger.warn(msg.message);
344
345
  break;
345
- case "DEBUG":
346
+ case 'DEBUG':
346
347
  this.logger.debug(msg.message);
347
348
  break;
348
- case "ERROR":
349
- case "FATAL":
350
- case "PANIC":
349
+ case 'ERROR':
350
+ case 'FATAL':
351
+ case 'PANIC':
351
352
  this.logger.error(msg.message);
352
353
  break;
353
354
  default:
@@ -356,7 +357,7 @@ class DBOSExecutor {
356
357
  }
357
358
  async destroy() {
358
359
  if (this.pendingWorkflowMap.size > 0) {
359
- this.logger.info("Waiting for pending workflows to finish.");
360
+ this.logger.info('Waiting for pending workflows to finish.');
360
361
  await Promise.allSettled(this.pendingWorkflowMap.values());
361
362
  }
362
363
  clearInterval(this.flushBufferID);
@@ -365,7 +366,7 @@ class DBOSExecutor {
365
366
  await this.flushWorkflowBuffers();
366
367
  }
367
368
  while (this.isFlushingBuffers) {
368
- this.logger.info("Waiting for result buffers to be exported.");
369
+ this.logger.info('Waiting for result buffers to be exported.');
369
370
  await (0, utils_1.sleepms)(1000);
370
371
  }
371
372
  await this.systemDatabase.destroy();
@@ -439,9 +440,7 @@ class DBOSExecutor {
439
440
  this.logger.debug(`Registered stored proc ${cfn}`);
440
441
  }
441
442
  getWorkflowInfo(wf) {
442
- const wfname = (wf.name === DBOSExecutor.tempWorkflowName)
443
- ? wf.name
444
- : (0, decorators_1.getRegisteredMethodClassName)(wf) + '.' + wf.name;
443
+ const wfname = wf.name === DBOSExecutor.tempWorkflowName ? wf.name : (0, decorators_1.getRegisteredMethodClassName)(wf) + '.' + wf.name;
445
444
  return this.workflowInfoMap.get(wfname);
446
445
  }
447
446
  getWorkflowInfoByStatus(wf) {
@@ -498,14 +497,14 @@ class DBOSExecutor {
498
497
  const wCtxt = new workflow_1.WorkflowContextImpl(this, params.parentCtx, workflowUUID, wConfig, wf.name, presetUUID, params.tempWfType, params.tempWfName);
499
498
  const internalStatus = {
500
499
  workflowUUID: workflowUUID,
501
- status: (params.queueName !== undefined) ? workflow_1.StatusString.ENQUEUED : workflow_1.StatusString.PENDING,
500
+ status: params.queueName !== undefined ? workflow_1.StatusString.ENQUEUED : workflow_1.StatusString.PENDING,
502
501
  name: wf.name,
503
- className: wCtxt.isTempWorkflow ? "" : (0, decorators_1.getRegisteredMethodClassName)(wf),
504
- configName: params.configuredInstance?.name || "",
502
+ className: wCtxt.isTempWorkflow ? '' : (0, decorators_1.getRegisteredMethodClassName)(wf),
503
+ configName: params.configuredInstance?.name || '',
505
504
  queueName: params.queueName,
506
505
  authenticatedUser: wCtxt.authenticatedUser,
507
506
  output: undefined,
508
- error: "",
507
+ error: '',
509
508
  assumedRole: wCtxt.assumedRole,
510
509
  authenticatedRoles: wCtxt.authenticatedRoles,
511
510
  request: wCtxt.request,
@@ -514,18 +513,17 @@ class DBOSExecutor {
514
513
  applicationID: wCtxt.applicationID,
515
514
  createdAt: Date.now(), // Remember the start time of this workflow
516
515
  maxRetries: wCtxt.maxRecoveryAttempts,
517
- recovery: params.recovery === true,
518
516
  };
519
517
  if (wCtxt.isTempWorkflow) {
520
518
  internalStatus.name = `${DBOSExecutor.tempWorkflowName}-${wCtxt.tempWfOperationType}-${wCtxt.tempWfOperationName}`;
521
- internalStatus.className = params.tempWfClass ?? "";
519
+ internalStatus.className = params.tempWfClass ?? '';
522
520
  }
523
521
  let status = undefined;
524
522
  // Synchronously set the workflow's status to PENDING and record workflow inputs (for non single-transaction workflows).
525
523
  // We have to do it for all types of workflows because operation_outputs table has a foreign key constraint on workflow status table.
526
- if ((wCtxt.tempWfOperationType !== TempWorkflowType.transaction
527
- && wCtxt.tempWfOperationType !== TempWorkflowType.procedure)
528
- || params.queueName !== undefined) {
524
+ if ((wCtxt.tempWfOperationType !== TempWorkflowType.transaction &&
525
+ wCtxt.tempWfOperationType !== TempWorkflowType.procedure) ||
526
+ params.queueName !== undefined) {
529
527
  if (this.debugMode) {
530
528
  const wfStatus = await this.systemDatabase.getWorkflowStatus(workflowUUID);
531
529
  const wfInputs = await this.systemDatabase.getWorkflowInputs(workflowUUID);
@@ -590,7 +588,7 @@ class DBOSExecutor {
590
588
  // Retrieve the handle and wait for the result.
591
589
  const retrievedHandle = this.retrieveWorkflow(workflowUUID);
592
590
  result = await retrievedHandle.getResult();
593
- wCtxt.span.setAttribute("cached", true);
591
+ wCtxt.span.setAttribute('cached', true);
594
592
  wCtxt.span.setStatus({ code: api_1.SpanStatusCode.OK });
595
593
  }
596
594
  else {
@@ -616,8 +614,8 @@ class DBOSExecutor {
616
614
  }
617
615
  finally {
618
616
  this.tracer.endSpan(wCtxt.span);
619
- if (wCtxt.tempWfOperationType === TempWorkflowType.transaction
620
- || wCtxt.tempWfOperationType === TempWorkflowType.procedure) {
617
+ if (wCtxt.tempWfOperationType === TempWorkflowType.transaction ||
618
+ wCtxt.tempWfOperationType === TempWorkflowType.procedure) {
621
619
  // For single-transaction workflows, asynchronously record inputs.
622
620
  // We must buffer inputs after workflow status is buffered/flushed because workflow_inputs table has a foreign key reference to the workflow_status table.
623
621
  if (!this.debugMode) {
@@ -631,12 +629,13 @@ class DBOSExecutor {
631
629
  }
632
630
  return result;
633
631
  };
634
- if (this.debugMode || (status !== 'SUCCESS' && status !== 'ERROR' && (params.queueName === undefined || params.executeWorkflow))) {
632
+ if (this.debugMode ||
633
+ (status !== 'SUCCESS' && status !== 'ERROR' && (params.queueName === undefined || params.executeWorkflow))) {
635
634
  const workflowPromise = runWorkflow();
636
635
  // Need to await for the workflow and capture errors.
637
636
  const awaitWorkflowPromise = workflowPromise
638
637
  .catch((error) => {
639
- this.logger.debug("Captured error in awaitWorkflowPromise: " + error);
638
+ this.logger.debug('Captured error in awaitWorkflowPromise: ' + error);
640
639
  })
641
640
  .finally(() => {
642
641
  // Remove itself from pending workflow map.
@@ -663,7 +662,7 @@ class DBOSExecutor {
663
662
  * Retrieve the transaction snapshot information of the current transaction
664
663
  */
665
664
  static async #retrieveSnapshot(query) {
666
- const rows = await query("SELECT pg_current_snapshot()::text as txn_snapshot;", []);
665
+ const rows = await query('SELECT pg_current_snapshot()::text as txn_snapshot;', []);
667
666
  return rows[0].txn_snapshot;
668
667
  }
669
668
  /**
@@ -675,14 +674,14 @@ class DBOSExecutor {
675
674
  */
676
675
  async #checkExecution(query, workflowUUID, funcID) {
677
676
  // Note: we read the current snapshot, not the recorded one!
678
- const rows = await query("(SELECT output, error, txn_snapshot, true as recorded FROM dbos.transaction_outputs WHERE workflow_uuid=$1 AND function_id=$2 UNION ALL SELECT null as output, null as error, pg_current_snapshot()::text as txn_snapshot, false as recorded) ORDER BY recorded", [workflowUUID, funcID]);
677
+ const rows = await query('(SELECT output, error, txn_snapshot, true as recorded FROM dbos.transaction_outputs WHERE workflow_uuid=$1 AND function_id=$2 UNION ALL SELECT null as output, null as error, pg_current_snapshot()::text as txn_snapshot, false as recorded) ORDER BY recorded', [workflowUUID, funcID]);
679
678
  if (rows.length === 0 || rows.length > 2) {
680
- this.logger.error("Unexpected! This should never happen. Returned rows: " + rows.toString());
681
- throw new error_1.DBOSError("This should never happen. Returned rows: " + rows.toString());
679
+ this.logger.error('Unexpected! This should never happen. Returned rows: ' + rows.toString());
680
+ throw new error_1.DBOSError('This should never happen. Returned rows: ' + rows.toString());
682
681
  }
683
682
  const res = {
684
683
  output: exports.dbosNull,
685
- txn_snapshot: ""
684
+ txn_snapshot: '',
686
685
  };
687
686
  // recorded=false row will be first because we used ORDER BY.
688
687
  res.txn_snapshot = rows[0].txn_snapshot;
@@ -701,11 +700,11 @@ class DBOSExecutor {
701
700
  */
702
701
  async #recordOutput(query, workflowUUID, funcID, txnSnapshot, output, isKeyConflict) {
703
702
  if (this.debugMode) {
704
- throw new error_1.DBOSDebuggerError("Cannot record output in debug mode.");
703
+ throw new error_1.DBOSDebuggerError('Cannot record output in debug mode.');
705
704
  }
706
705
  try {
707
706
  const serialOutput = utils_1.DBOSJSON.stringify(output);
708
- const rows = await query("INSERT INTO dbos.transaction_outputs (workflow_uuid, function_id, output, txn_id, txn_snapshot, created_at) VALUES ($1, $2, $3, (select pg_current_xact_id_if_assigned()::text), $4, $5) RETURNING txn_id;", [workflowUUID, funcID, serialOutput, txnSnapshot, Date.now()]);
707
+ const rows = await query('INSERT INTO dbos.transaction_outputs (workflow_uuid, function_id, output, txn_id, txn_snapshot, created_at) VALUES ($1, $2, $3, (select pg_current_xact_id_if_assigned()::text), $4, $5) RETURNING txn_id;', [workflowUUID, funcID, serialOutput, txnSnapshot, Date.now()]);
709
708
  return rows[0].txn_id;
710
709
  }
711
710
  catch (error) {
@@ -723,11 +722,11 @@ class DBOSExecutor {
723
722
  */
724
723
  async #recordError(query, workflowUUID, funcID, txnSnapshot, err, isKeyConflict) {
725
724
  if (this.debugMode) {
726
- throw new error_1.DBOSDebuggerError("Cannot record error in debug mode.");
725
+ throw new error_1.DBOSDebuggerError('Cannot record error in debug mode.');
727
726
  }
728
727
  try {
729
728
  const serialErr = utils_1.DBOSJSON.stringify((0, serialize_error_1.serializeError)(err));
730
- await query("INSERT INTO dbos.transaction_outputs (workflow_uuid, function_id, error, txn_id, txn_snapshot, created_at) VALUES ($1, $2, $3, null, $4, $5) RETURNING txn_id;", [workflowUUID, funcID, serialErr, txnSnapshot, Date.now()]);
729
+ await query('INSERT INTO dbos.transaction_outputs (workflow_uuid, function_id, error, txn_id, txn_snapshot, created_at) VALUES ($1, $2, $3, null, $4, $5) RETURNING txn_id;', [workflowUUID, funcID, serialErr, txnSnapshot, Date.now()]);
731
730
  }
732
731
  catch (error) {
733
732
  if (isKeyConflict(error)) {
@@ -749,11 +748,11 @@ class DBOSExecutor {
749
748
  return;
750
749
  }
751
750
  if (this.debugMode) {
752
- throw new error_1.DBOSDebuggerError("Cannot flush result buffer in debug mode.");
751
+ throw new error_1.DBOSDebuggerError('Cannot flush result buffer in debug mode.');
753
752
  }
754
753
  funcIDs.sort();
755
754
  try {
756
- let sqlStmt = "INSERT INTO dbos.transaction_outputs (workflow_uuid, function_id, output, error, txn_id, txn_snapshot, created_at) VALUES ";
755
+ let sqlStmt = 'INSERT INTO dbos.transaction_outputs (workflow_uuid, function_id, output, error, txn_id, txn_snapshot, created_at) VALUES ';
757
756
  let paramCnt = 1;
758
757
  const values = [];
759
758
  for (const funcID of funcIDs) {
@@ -764,7 +763,7 @@ class DBOSExecutor {
764
763
  const txnSnapshot = recorded.txn_snapshot;
765
764
  const createdAt = recorded.created_at;
766
765
  if (paramCnt > 1) {
767
- sqlStmt += ", ";
766
+ sqlStmt += ', ';
768
767
  }
769
768
  sqlStmt += `($${paramCnt++}, $${paramCnt++}, $${paramCnt++}, $${paramCnt++}, null, $${paramCnt++}, $${paramCnt++})`;
770
769
  values.push(workflowUUID, funcID, utils_1.DBOSJSON.stringify(output), utils_1.DBOSJSON.stringify(null), txnSnapshot, createdAt);
@@ -787,7 +786,7 @@ class DBOSExecutor {
787
786
  return this.#flushResultBuffer(func, resultBuffer, workflowUUID, (error) => this.userDatabase.isKeyConflictError(error));
788
787
  }
789
788
  #flushResultBufferProc(client, resultBuffer, workflowUUID) {
790
- const func = (sql, args) => client.query(sql, args).then(v => v.rows);
789
+ const func = (sql, args) => client.query(sql, args).then((v) => v.rows);
791
790
  return this.#flushResultBuffer(func, resultBuffer, workflowUUID, user_database_1.pgNodeIsKeyConflictError);
792
791
  }
793
792
  async transaction(txn, params, ...args) {
@@ -823,7 +822,7 @@ class DBOSExecutor {
823
822
  isolationLevel: txnInfo.config.isolationLevel,
824
823
  }, wfCtx.span);
825
824
  while (true) {
826
- let txn_snapshot = "invalid";
825
+ let txn_snapshot = 'invalid';
827
826
  const workflowUUID = wfCtx.workflowUUID;
828
827
  const wrappedTransaction = async (client) => {
829
828
  const tCtxt = new transaction_1.TransactionContextImpl(this.userDatabase.getName(), client, wfCtx, span, this.logger, funcId, txn.name);
@@ -834,7 +833,7 @@ class DBOSExecutor {
834
833
  const check = await this.#checkExecution(func, workflowUUID, funcId);
835
834
  txn_snapshot = check.txn_snapshot;
836
835
  if (check.output !== exports.dbosNull) {
837
- tCtxt.span.setAttribute("cached", true);
836
+ tCtxt.span.setAttribute('cached', true);
838
837
  tCtxt.span.setStatus({ code: api_1.SpanStatusCode.OK });
839
838
  this.tracer.endSpan(tCtxt.span);
840
839
  return check.output;
@@ -881,7 +880,7 @@ class DBOSExecutor {
881
880
  // Synchronously record the output of write transactions and obtain the transaction ID.
882
881
  const func = (sql, args) => this.userDatabase.queryWithClient(client, sql, ...args);
883
882
  const pg_txn_id = await this.#recordOutput(func, wfCtx.workflowUUID, funcId, txn_snapshot, result, (error) => this.userDatabase.isKeyConflictError(error));
884
- tCtxt.span.setAttribute("pg_txn_id", pg_txn_id);
883
+ tCtxt.span.setAttribute('pg_txn_id', pg_txn_id);
885
884
  wfCtx.resultBuffer.clear();
886
885
  }
887
886
  catch (error) {
@@ -908,7 +907,7 @@ class DBOSExecutor {
908
907
  }
909
908
  if (this.userDatabase.isRetriableTransactionError(err)) {
910
909
  // serialization_failure in PostgreSQL
911
- span.addEvent("TXN SERIALIZATION FAILURE", { "retryWaitMillis": retryWaitMillis }, performance.now());
910
+ span.addEvent('TXN SERIALIZATION FAILURE', { retryWaitMillis: retryWaitMillis }, performance.now());
912
911
  // Retry serialization failures.
913
912
  await (0, utils_1.sleepms)(retryWaitMillis);
914
913
  retryWaitMillis *= backoffFactor;
@@ -981,15 +980,15 @@ class DBOSExecutor {
981
980
  const maxRetryWaitMs = 2000; // Maximum wait 2 seconds.
982
981
  const readOnly = procInfo.config.readOnly ?? false;
983
982
  while (true) {
984
- let txn_snapshot = "invalid";
983
+ let txn_snapshot = 'invalid';
985
984
  const wrappedProcedure = async (client) => {
986
985
  const ctxt = new procedure_1.StoredProcedureContextImpl(client, wfCtx, span, this.logger, funcId, proc.name);
987
986
  if (wfCtx.presetUUID) {
988
- const func = (sql, args) => this.procedurePool.query(sql, args).then(v => v.rows);
987
+ const func = (sql, args) => this.procedurePool.query(sql, args).then((v) => v.rows);
989
988
  const check = await this.#checkExecution(func, wfCtx.workflowUUID, funcId);
990
989
  txn_snapshot = check.txn_snapshot;
991
990
  if (check.output !== exports.dbosNull) {
992
- ctxt.span.setAttribute("cached", true);
991
+ ctxt.span.setAttribute('cached', true);
993
992
  ctxt.span.setStatus({ code: api_1.SpanStatusCode.OK });
994
993
  this.tracer.endSpan(ctxt.span);
995
994
  return check.output;
@@ -997,7 +996,7 @@ class DBOSExecutor {
997
996
  }
998
997
  else {
999
998
  // Collect snapshot information for read-only transactions and non-preset UUID transactions, if not already collected above
1000
- const func = (sql, args) => this.procedurePool.query(sql, args).then(v => v.rows);
999
+ const func = (sql, args) => this.procedurePool.query(sql, args).then((v) => v.rows);
1001
1000
  txn_snapshot = await DBOSExecutor.#retrieveSnapshot(func);
1002
1001
  }
1003
1002
  if (this.debugMode) {
@@ -1031,23 +1030,25 @@ class DBOSExecutor {
1031
1030
  }
1032
1031
  else {
1033
1032
  // Synchronously record the output of write transactions and obtain the transaction ID.
1034
- const func = (sql, args) => client.query(sql, args).then(v => v.rows);
1033
+ const func = (sql, args) => client.query(sql, args).then((v) => v.rows);
1035
1034
  const pg_txn_id = await this.#recordOutput(func, wfCtx.workflowUUID, funcId, txn_snapshot, result, user_database_1.pgNodeIsKeyConflictError);
1036
1035
  // const pg_txn_id = await wfCtx.recordOutputProc<R>(client, funcId, txn_snapshot, result);
1037
- ctxt.span.setAttribute("pg_txn_id", pg_txn_id);
1036
+ ctxt.span.setAttribute('pg_txn_id', pg_txn_id);
1038
1037
  wfCtx.resultBuffer.clear();
1039
1038
  }
1040
1039
  return result;
1041
1040
  };
1042
1041
  try {
1043
- const result = await this.invokeStoredProcFunction(wrappedProcedure, { isolationLevel: procInfo.config.isolationLevel });
1042
+ const result = await this.invokeStoredProcFunction(wrappedProcedure, {
1043
+ isolationLevel: procInfo.config.isolationLevel,
1044
+ });
1044
1045
  span.setStatus({ code: api_1.SpanStatusCode.OK });
1045
1046
  return result;
1046
1047
  }
1047
1048
  catch (err) {
1048
1049
  if (this.userDatabase.isRetriableTransactionError(err)) {
1049
1050
  // serialization_failure in PostgreSQL
1050
- span.addEvent("TXN SERIALIZATION FAILURE", { "retryWaitMillis": retryWaitMillis }, performance.now());
1051
+ span.addEvent('TXN SERIALIZATION FAILURE', { retryWaitMillis: retryWaitMillis }, performance.now());
1051
1052
  // Retry serialization failures.
1052
1053
  await (0, utils_1.sleepms)(retryWaitMillis);
1053
1054
  retryWaitMillis *= backoffFactor;
@@ -1058,7 +1059,7 @@ class DBOSExecutor {
1058
1059
  const e = err;
1059
1060
  await this.invokeStoredProcFunction(async (client) => {
1060
1061
  await this.#flushResultBufferProc(client, wfCtx.resultBuffer, wfCtx.workflowUUID);
1061
- const func = (sql, args) => client.query(sql, args).then(v => v.rows);
1062
+ const func = (sql, args) => client.query(sql, args).then((v) => v.rows);
1062
1063
  await this.#recordError(func, wfCtx.workflowUUID, funcId, txn_snapshot, e, user_database_1.pgNodeIsKeyConflictError);
1063
1064
  }, { isolationLevel: transaction_1.IsolationLevel.ReadCommitted });
1064
1065
  await this.userDatabase.transaction(async (client) => {
@@ -1118,7 +1119,7 @@ class DBOSExecutor {
1118
1119
  wfCtx.resultBuffer.clear();
1119
1120
  }
1120
1121
  if (txn_id) {
1121
- span.setAttribute("pg_txn_id", txn_id);
1122
+ span.setAttribute('pg_txn_id', txn_id);
1122
1123
  }
1123
1124
  span.setStatus({ code: api_1.SpanStatusCode.OK });
1124
1125
  return output;
@@ -1128,13 +1129,11 @@ class DBOSExecutor {
1128
1129
  const log = (msg) => this.#logNotice(msg);
1129
1130
  const procClassName = this.getProcedureClassName(proc);
1130
1131
  const plainProcName = `${procClassName}_${proc.name}_p`;
1131
- const procName = this.config.appVersion
1132
- ? `v${this.config.appVersion}_${plainProcName}`
1133
- : plainProcName;
1132
+ const procName = this.config.appVersion ? `v${this.config.appVersion}_${plainProcName}` : plainProcName;
1134
1133
  const sql = `CALL "${procName}"(${args.map((_v, i) => `$${i + 1}`).join()});`;
1135
1134
  try {
1136
1135
  client.on('notice', log);
1137
- return await client.query(sql, args).then(value => value.rows);
1136
+ return await client.query(sql, args).then((value) => value.rows);
1138
1137
  }
1139
1138
  finally {
1140
1139
  client.off('notice', log);
@@ -1206,7 +1205,7 @@ class DBOSExecutor {
1206
1205
  // Check if this execution previously happened, returning its original result if it did.
1207
1206
  const check = await this.systemDatabase.checkOperationOutput(wfCtx.workflowUUID, ctxt.functionID);
1208
1207
  if (check !== exports.dbosNull) {
1209
- ctxt.span.setAttribute("cached", true);
1208
+ ctxt.span.setAttribute('cached', true);
1210
1209
  ctxt.span.setStatus({ code: api_1.SpanStatusCode.OK });
1211
1210
  this.tracer.endSpan(ctxt.span);
1212
1211
  return check;
@@ -1245,7 +1244,7 @@ class DBOSExecutor {
1245
1244
  const e = error;
1246
1245
  errors.push(e);
1247
1246
  this.logger.warn(`Error in step being automatically retried. Attempt ${numAttempts} of ${ctxt.maxAttempts}. ${e.stack}`);
1248
- span.addEvent(`Step attempt ${numAttempts + 1} failed`, { "retryIntervalSeconds": intervalSeconds, "error": error.message }, performance.now());
1247
+ span.addEvent(`Step attempt ${numAttempts + 1} failed`, { retryIntervalSeconds: intervalSeconds, error: error.message }, performance.now());
1249
1248
  if (numAttempts < ctxt.maxAttempts) {
1250
1249
  // Sleep for an interval, then increase the interval by backoffRate.
1251
1250
  // Cap at the maximum allowed retry interval.
@@ -1300,7 +1299,9 @@ class DBOSExecutor {
1300
1299
  };
1301
1300
  const workflowUUID = idempotencyKey ? destinationUUID + idempotencyKey : undefined;
1302
1301
  return (await this.workflow(temp_workflow, {
1303
- workflowUUID: workflowUUID, tempWfType: TempWorkflowType.send, configuredInstance: null,
1302
+ workflowUUID: workflowUUID,
1303
+ tempWfType: TempWorkflowType.send,
1304
+ configuredInstance: null,
1304
1305
  }, destinationUUID, message, topic)).getResult();
1305
1306
  }
1306
1307
  /**
@@ -1337,7 +1338,7 @@ class DBOSExecutor {
1337
1338
  for (const nname of channels) {
1338
1339
  await notificationsClient.query(`LISTEN ${nname};`);
1339
1340
  }
1340
- notificationsClient.on("notification", callback);
1341
+ notificationsClient.on('notification', callback);
1341
1342
  return {
1342
1343
  close: async () => {
1343
1344
  for (const nname of channels) {
@@ -1349,7 +1350,7 @@ class DBOSExecutor {
1349
1350
  }
1350
1351
  notificationsClient.release();
1351
1352
  }
1352
- }
1353
+ },
1353
1354
  };
1354
1355
  }
1355
1356
  /* INTERNAL HELPERS */
@@ -1360,13 +1361,13 @@ class DBOSExecutor {
1360
1361
  * A recovery process that by default runs during executor init time.
1361
1362
  * It runs to completion all pending workflows that were executing when the previous executor failed.
1362
1363
  */
1363
- async recoverPendingWorkflows(executorIDs = ["local"]) {
1364
+ async recoverPendingWorkflows(executorIDs = ['local']) {
1364
1365
  if (this.debugMode) {
1365
- throw new error_1.DBOSDebuggerError("Cannot recover pending workflows in debug mode.");
1366
+ throw new error_1.DBOSDebuggerError('Cannot recover pending workflows in debug mode.');
1366
1367
  }
1367
1368
  const pendingWorkflows = [];
1368
1369
  for (const execID of executorIDs) {
1369
- if (execID === "local" && process.env.DBOS__VMID) {
1370
+ if (execID === 'local' && process.env.DBOS__VMID) {
1370
1371
  this.logger.debug(`Skip local recovery because it's running in a VM: ${process.env.DBOS__VMID}`);
1371
1372
  continue;
1372
1373
  }
@@ -1386,7 +1387,7 @@ class DBOSExecutor {
1386
1387
  return handlerArray;
1387
1388
  }
1388
1389
  async deactivateEventReceivers() {
1389
- this.logger.info("Deactivating event receivers");
1390
+ this.logger.info('Deactivating event receivers');
1390
1391
  for (const evtRcvr of this.eventReceivers || []) {
1391
1392
  try {
1392
1393
  await evtRcvr.destroy();
@@ -1425,15 +1426,18 @@ class DBOSExecutor {
1425
1426
  const workflowStartUUID = startNewWorkflow ? undefined : workflowUUID;
1426
1427
  if (wfInfo) {
1427
1428
  return this.workflow(wfInfo.workflow, {
1428
- workflowUUID: workflowStartUUID, parentCtx: parentCtx, configuredInstance: configuredInst, recovery: true,
1429
- queueName: wfStatus.queueName, executeWorkflow: true,
1429
+ workflowUUID: workflowStartUUID,
1430
+ parentCtx: parentCtx,
1431
+ configuredInstance: configuredInst,
1432
+ queueName: wfStatus.queueName,
1433
+ executeWorkflow: true,
1430
1434
  },
1431
1435
  // eslint-disable-next-line @typescript-eslint/no-unsafe-argument
1432
1436
  ...inputs);
1433
1437
  }
1434
1438
  // Should be temporary workflows. Parse the name of the workflow.
1435
1439
  const wfName = wfStatus.workflowName;
1436
- const nameArr = wfName.split("-");
1440
+ const nameArr = wfName.split('-');
1437
1441
  if (!nameArr[0].startsWith(DBOSExecutor.tempWorkflowName)) {
1438
1442
  // CB - Doesn't this happen if the user changed the function name in their code?
1439
1443
  throw new error_1.DBOSError(`This should never happen! Cannot find workflow info for a non-temporary workflow! UUID ${workflowUUID}, name ${wfName}`);
@@ -1485,8 +1489,12 @@ class DBOSExecutor {
1485
1489
  throw new error_1.DBOSNotRegisteredError(wfName);
1486
1490
  }
1487
1491
  return this.workflow(temp_workflow, {
1488
- workflowUUID: workflowStartUUID, parentCtx: parentCtx ?? undefined, configuredInstance: clsinst,
1489
- recovery: true, tempWfType, tempWfClass, tempWfName,
1492
+ workflowUUID: workflowStartUUID,
1493
+ parentCtx: parentCtx ?? undefined,
1494
+ configuredInstance: clsinst,
1495
+ tempWfType,
1496
+ tempWfClass,
1497
+ tempWfName,
1490
1498
  },
1491
1499
  // eslint-disable-next-line @typescript-eslint/no-unsafe-argument
1492
1500
  ...inputs);
@@ -1510,6 +1518,13 @@ class DBOSExecutor {
1510
1518
  oc.workflowUUID = workflowUUID;
1511
1519
  return oc;
1512
1520
  }
1521
+ async cancelWorkflow(workflowID) {
1522
+ await this.systemDatabase.cancelWorkflow(workflowID);
1523
+ }
1524
+ async resumeWorkflow(workflowID) {
1525
+ await this.systemDatabase.resumeWorkflow(workflowID);
1526
+ return await this.executeWorkflowUUID(workflowID, false);
1527
+ }
1513
1528
  /* BACKGROUND PROCESSES */
1514
1529
  /**
1515
1530
  * Periodically flush the workflow output buffer to the system database.
@@ -1532,7 +1547,7 @@ class DBOSExecutor {
1532
1547
  try {
1533
1548
  let finishedCnt = 0;
1534
1549
  while (finishedCnt < totalSize) {
1535
- let sqlStmt = "INSERT INTO dbos.transaction_outputs (workflow_uuid, function_id, output, error, txn_id, txn_snapshot, created_at) VALUES ";
1550
+ let sqlStmt = 'INSERT INTO dbos.transaction_outputs (workflow_uuid, function_id, output, error, txn_id, txn_snapshot, created_at) VALUES ';
1536
1551
  let paramCnt = 1;
1537
1552
  const values = [];
1538
1553
  const batchUUIDs = [];
@@ -1542,7 +1557,7 @@ class DBOSExecutor {
1542
1557
  const txnSnapshot = recorded.txn_snapshot;
1543
1558
  const createdAt = recorded.created_at;
1544
1559
  if (paramCnt > 1) {
1545
- sqlStmt += ", ";
1560
+ sqlStmt += ', ';
1546
1561
  }
1547
1562
  sqlStmt += `($${paramCnt++}, $${paramCnt++}, $${paramCnt++}, $${paramCnt++}, null, $${paramCnt++}, $${paramCnt++})`;
1548
1563
  values.push(workflowUUID, funcID, utils_1.DBOSJSON.stringify(output), utils_1.DBOSJSON.stringify(null), txnSnapshot, createdAt);
@@ -1558,7 +1573,9 @@ class DBOSExecutor {
1558
1573
  // eslint-disable-next-line @typescript-eslint/no-unsafe-argument
1559
1574
  await this.userDatabase.query(sqlStmt, ...values);
1560
1575
  // Clean up after each batch succeeds
1561
- batchUUIDs.forEach((value) => { localBuffer.delete(value); });
1576
+ batchUUIDs.forEach((value) => {
1577
+ localBuffer.delete(value);
1578
+ });
1562
1579
  }
1563
1580
  }
1564
1581
  catch (error) {
@@ -1573,14 +1590,14 @@ class DBOSExecutor {
1573
1590
  }
1574
1591
  }
1575
1592
  logRegisteredHTTPUrls() {
1576
- this.logger.info("HTTP endpoints supported:");
1593
+ this.logger.info('HTTP endpoints supported:');
1577
1594
  this.registeredOperations.forEach((registeredOperation) => {
1578
1595
  const ro = registeredOperation;
1579
1596
  if (ro.apiURL) {
1580
- this.logger.info(" " + ro.apiType.padEnd(6) + " : " + ro.apiURL);
1597
+ this.logger.info(' ' + ro.apiType.padEnd(6) + ' : ' + ro.apiURL);
1581
1598
  const roles = ro.getRequiredRoles();
1582
1599
  if (roles.length > 0) {
1583
- this.logger.info(" Required Roles: " + utils_1.DBOSJSON.stringify(roles));
1600
+ this.logger.info(' Required Roles: ' + utils_1.DBOSJSON.stringify(roles));
1584
1601
  }
1585
1602
  }
1586
1603
  });