@dbos-inc/dbos-sdk 5.3.10-preview → 5.3.12-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.
@@ -387,6 +387,9 @@ function sqlStateLooksRetryable(sqlstate) {
387
387
  return false;
388
388
  if (RETRY_SQLSTATE_CODES.has(sqlstate))
389
389
  return true;
390
+ // query_canceled (a statement timeout or an explicit cancel); retrying would undo it
391
+ if (sqlstate === '57014')
392
+ return false;
390
393
  const prefix = sqlstate.toString().slice(0, 2);
391
394
  return RETRY_SQLSTATE_PREFIXES.has(prefix);
392
395
  }
@@ -692,7 +695,7 @@ class SystemDatabase {
692
695
  }
693
696
  catch (e) {
694
697
  await client.query('ROLLBACK').catch(() => { });
695
- // No `cause`: dbRetry walks the cause chain and would retry 57014 forever as an operator intervention.
698
+ // No `cause`: the typed timeout replaces the driver's query_canceled error.
696
699
  throw isStatementTimeout(e) ? new error_1.DBOSQueryTimeoutError(timeoutMs) : e;
697
700
  }
698
701
  }
@@ -1244,31 +1247,71 @@ class SystemDatabase {
1244
1247
  await (0, debugpoint_1.debugTriggerPoint)(debugpoint_1.DEBUG_TRIGGER_STEP_COMMIT);
1245
1248
  }
1246
1249
  }
1247
- async runTransactionalStep(workflowID, functionID, functionName, callback) {
1248
- const client = await this.connect();
1250
+ /** Checkpoint an operation's failure so a replay re-throws it instead of re-running. */
1251
+ async recordOperationError(workflowID, functionID, functionName, startTimeEpochMs, error, childWorkflowID) {
1252
+ let serialized;
1249
1253
  try {
1250
- await client.query('BEGIN ISOLATION LEVEL READ COMMITTED');
1251
- const existing = await this.#getOperationResultAndThrowIfCancelled(client, workflowID, functionID);
1252
- if (existing !== undefined) {
1254
+ serialized = await (0, serialization_1.serializeResErrorWithSerializer)(error, this.serializer, this.serializer.name());
1255
+ await (0, serialization_1.deserializeValue)(serialized.serializedValue, serialized.serialization, this.serializer);
1256
+ }
1257
+ catch (serError) {
1258
+ // A checkpoint replay could not load would wedge the workflow; leave it unrecorded so replay re-runs.
1259
+ this.logger.warn(`Not checkpointing ${functionName} failure in workflow ${workflowID}: its error cannot be serialized: ${String(serError)}`);
1260
+ return;
1261
+ }
1262
+ await this.recordOperationResult(workflowID, functionID, functionName, true, startTimeEpochMs, Date.now(), {
1263
+ error: serialized.serializedValue,
1264
+ serialization: serialized.serialization,
1265
+ childWorkflowID,
1266
+ });
1267
+ }
1268
+ async runTransactionalStep(workflowID, functionID, functionName, callback) {
1269
+ const startTime = Date.now();
1270
+ // The latest attempt's callback failure, told apart from a check or checkpoint failure.
1271
+ let callbackError = undefined;
1272
+ const attempt = async () => {
1273
+ callbackError = undefined;
1274
+ const client = await this.connect();
1275
+ try {
1276
+ await client.query('BEGIN ISOLATION LEVEL READ COMMITTED');
1277
+ const existing = await this.#getOperationResultAndThrowIfCancelled(client, workflowID, functionID);
1278
+ if (existing !== undefined) {
1279
+ await client.query('ROLLBACK');
1280
+ return existing;
1281
+ }
1282
+ let output;
1283
+ try {
1284
+ output = await callback(client);
1285
+ }
1286
+ catch (e) {
1287
+ callbackError = e;
1288
+ throw e;
1289
+ }
1290
+ await this.recordOperationResultInternal(client, workflowID, functionID, functionName, true, startTime, Date.now(), {
1291
+ output,
1292
+ });
1293
+ await client.query('COMMIT');
1294
+ await (0, debugpoint_1.debugTriggerPoint)(debugpoint_1.DEBUG_TRIGGER_STEP_COMMIT);
1295
+ return undefined;
1296
+ }
1297
+ catch (e) {
1253
1298
  await client.query('ROLLBACK');
1254
- return existing;
1299
+ throw e;
1255
1300
  }
1256
- const startTime = Date.now();
1257
- const output = await callback(client);
1258
- await this.recordOperationResultInternal(client, workflowID, functionID, functionName, true, startTime, Date.now(), {
1259
- output,
1260
- });
1261
- await client.query('COMMIT');
1262
- await (0, debugpoint_1.debugTriggerPoint)(debugpoint_1.DEBUG_TRIGGER_STEP_COMMIT);
1263
- return undefined;
1301
+ finally {
1302
+ client.release();
1303
+ }
1304
+ };
1305
+ try {
1306
+ return await withDbRetry(attempt);
1264
1307
  }
1265
1308
  catch (e) {
1266
- await client.query('ROLLBACK');
1309
+ // Retries are done and the transaction rolled back, so record the callback's own failure separately.
1310
+ if (e === callbackError) {
1311
+ await this.recordOperationError(workflowID, functionID, functionName, startTime, e);
1312
+ }
1267
1313
  throw e;
1268
1314
  }
1269
- finally {
1270
- client.release();
1271
- }
1272
1315
  }
1273
1316
  async checkPatch(workflowID, functionID, patchName, deprecated) {
1274
1317
  // Not doing a cancel check at this point.
@@ -2086,6 +2129,8 @@ class SystemDatabase {
2086
2129
  async send(workflowID, functionID, destinationID, message, topic, serialization, idempotencyKey) {
2087
2130
  topic = topic ?? this.nullTopic;
2088
2131
  const messageUUID = idempotencyKey ? `${idempotencyKey}::${destinationID}` : (0, crypto_1.randomUUID)();
2132
+ const startTime = Date.now();
2133
+ let missing;
2089
2134
  const client = await this.connect();
2090
2135
  try {
2091
2136
  await client.query('BEGIN ISOLATION LEVEL READ COMMITTED');
@@ -2102,7 +2147,7 @@ class SystemDatabase {
2102
2147
  const err = error;
2103
2148
  if (err.code === '23503') {
2104
2149
  // Foreign key constraint violation (only expected for the INSERT query)
2105
- throw new error_1.DBOSNonExistentWorkflowError(`Sent to non-existent destination workflow UUID: ${destinationID}`);
2150
+ missing = new error_1.DBOSNonExistentWorkflowError(`Sent to non-existent destination workflow UUID: ${destinationID}`);
2106
2151
  }
2107
2152
  else {
2108
2153
  throw err;
@@ -2111,6 +2156,11 @@ class SystemDatabase {
2111
2156
  finally {
2112
2157
  client.release();
2113
2158
  }
2159
+ if (missing) {
2160
+ // A missing destination is the send's answer; the transaction has rolled back, so record it separately.
2161
+ await this.recordOperationError(workflowID, functionID, exports.DBOS_FUNCNAME_SEND, startTime, missing);
2162
+ throw missing;
2163
+ }
2114
2164
  }
2115
2165
  /** Runs on `client` if given, joining its transaction; otherwise on the pool with retries. */
2116
2166
  async sendDirect(destinationID, message, topic, serialization, idempotencyKey, client) {
@@ -3869,6 +3919,9 @@ class SystemDatabase {
3869
3919
  if (result.functionName !== functionName) {
3870
3920
  throw new error_1.DBOSUnexpectedStepError(workflowID, functionID, functionName, result.functionName);
3871
3921
  }
3922
+ if (result.error) {
3923
+ throw await (0, serialization_1.deserializeResError)(result.error, result.serialization ?? null, this.serializer);
3924
+ }
3872
3925
  return result.output;
3873
3926
  }
3874
3927
  const output = await func();
@@ -4089,27 +4142,45 @@ __decorate([
4089
4142
  __decorate([
4090
4143
  dbRetry(),
4091
4144
  __metadata("design:type", Function),
4092
- __metadata("design:paramtypes", [String, Number, String, Boolean, Number, Number, Object]),
4145
+ __metadata("design:paramtypes", [String, Number, Number, Boolean]),
4093
4146
  __metadata("design:returntype", Promise)
4094
- ], SystemDatabase.prototype, "recordOperationResult", null);
4147
+ ], SystemDatabase.prototype, "getAllOperationResults", null);
4095
4148
  __decorate([
4096
4149
  dbRetry(),
4097
4150
  __metadata("design:type", Function),
4098
- __metadata("design:paramtypes", [String, Number, String, Function]),
4151
+ __metadata("design:paramtypes", [String, Number, String, Boolean, Number, Number, Object]),
4099
4152
  __metadata("design:returntype", Promise)
4100
- ], SystemDatabase.prototype, "runTransactionalStep", null);
4153
+ ], SystemDatabase.prototype, "recordOperationResult", null);
4101
4154
  __decorate([
4102
4155
  dbRetry(),
4103
4156
  __metadata("design:type", Function),
4104
4157
  __metadata("design:paramtypes", [String, Number, String, Boolean]),
4105
4158
  __metadata("design:returntype", Promise)
4106
4159
  ], SystemDatabase.prototype, "checkPatch", null);
4160
+ __decorate([
4161
+ dbRetry(),
4162
+ __metadata("design:type", Function),
4163
+ __metadata("design:paramtypes", [Array, Boolean]),
4164
+ __metadata("design:returntype", Promise)
4165
+ ], SystemDatabase.prototype, "cancelWorkflows", null);
4107
4166
  __decorate([
4108
4167
  dbRetry(),
4109
4168
  __metadata("design:type", Function),
4110
4169
  __metadata("design:paramtypes", [String]),
4111
4170
  __metadata("design:returntype", Promise)
4112
4171
  ], SystemDatabase.prototype, "checkIfCanceled", null);
4172
+ __decorate([
4173
+ dbRetry(),
4174
+ __metadata("design:type", Function),
4175
+ __metadata("design:paramtypes", [Array, String]),
4176
+ __metadata("design:returntype", Promise)
4177
+ ], SystemDatabase.prototype, "resumeWorkflows", null);
4178
+ __decorate([
4179
+ dbRetry(),
4180
+ __metadata("design:type", Function),
4181
+ __metadata("design:paramtypes", [String, Number]),
4182
+ __metadata("design:returntype", Promise)
4183
+ ], SystemDatabase.prototype, "setWorkflowDelay", null);
4113
4184
  __decorate([
4114
4185
  dbRetry(),
4115
4186
  __metadata("design:type", Function),
@@ -4119,9 +4190,15 @@ __decorate([
4119
4190
  __decorate([
4120
4191
  dbRetry(),
4121
4192
  __metadata("design:type", Function),
4122
- __metadata("design:paramtypes", [String, Number, Object]),
4193
+ __metadata("design:paramtypes", [String]),
4123
4194
  __metadata("design:returntype", Promise)
4124
- ], SystemDatabase.prototype, "rewindWorkflow", null);
4195
+ ], SystemDatabase.prototype, "getWorkflowChildren", null);
4196
+ __decorate([
4197
+ dbRetry(),
4198
+ __metadata("design:type", Function),
4199
+ __metadata("design:paramtypes", [Array, Boolean]),
4200
+ __metadata("design:returntype", Promise)
4201
+ ], SystemDatabase.prototype, "deleteWorkflows", null);
4125
4202
  __decorate([
4126
4203
  dbRetry()
4127
4204
  // A missing row normally means the workflow has not been inserted yet, so
@@ -4218,6 +4295,12 @@ __decorate([
4218
4295
  __metadata("design:paramtypes", [String]),
4219
4296
  __metadata("design:returntype", Promise)
4220
4297
  ], SystemDatabase.prototype, "getQueuePartitions", null);
4298
+ __decorate([
4299
+ dbRetry(),
4300
+ __metadata("design:type", Function),
4301
+ __metadata("design:paramtypes", [Object]),
4302
+ __metadata("design:returntype", Promise)
4303
+ ], SystemDatabase.prototype, "listWorkflows", null);
4221
4304
  __decorate([
4222
4305
  dbRetry(),
4223
4306
  __metadata("design:type", Function),