@dbos-inc/dbos-sdk 4.25.14 → 4.26.3-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.
- package/dist/src/dbos-executor.d.ts.map +1 -1
- package/dist/src/dbos-executor.js +117 -62
- package/dist/src/dbos-executor.js.map +1 -1
- package/dist/src/system_database.d.ts +3 -3
- package/dist/src/system_database.d.ts.map +1 -1
- package/dist/src/system_database.js +58 -48
- package/dist/src/system_database.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +1 -1
|
@@ -699,7 +699,7 @@ class SystemDatabase {
|
|
|
699
699
|
async recordWorkflowOutput(workflowID, status) {
|
|
700
700
|
const client = await this.pool.connect();
|
|
701
701
|
try {
|
|
702
|
-
await this.#recordWorkflowOutcome(client, workflowID, workflow_1.StatusString.SUCCESS, { output: status.output });
|
|
702
|
+
return await this.#recordWorkflowOutcome(client, workflowID, workflow_1.StatusString.SUCCESS, { output: status.output });
|
|
703
703
|
}
|
|
704
704
|
finally {
|
|
705
705
|
client.release();
|
|
@@ -708,36 +708,30 @@ class SystemDatabase {
|
|
|
708
708
|
async recordWorkflowError(workflowID, status) {
|
|
709
709
|
const client = await this.pool.connect();
|
|
710
710
|
try {
|
|
711
|
-
await this.#recordWorkflowOutcome(client, workflowID, workflow_1.StatusString.ERROR, { error: status.error });
|
|
711
|
+
return await this.#recordWorkflowOutcome(client, workflowID, workflow_1.StatusString.ERROR, { error: status.error });
|
|
712
712
|
}
|
|
713
713
|
finally {
|
|
714
714
|
client.release();
|
|
715
715
|
}
|
|
716
716
|
}
|
|
717
|
-
// Record a workflow's terminal outcome (SUCCESS or ERROR),
|
|
718
|
-
// the
|
|
719
|
-
//
|
|
720
|
-
// workflow is
|
|
721
|
-
//
|
|
717
|
+
// Record a workflow's terminal outcome (SUCCESS or ERROR), reporting whether
|
|
718
|
+
// the write landed. The write applies only to a PENDING row: a run owns its
|
|
719
|
+
// workflow's outcome exactly as long as the row says that run is what the
|
|
720
|
+
// workflow is doing. (Note: this does not prevent a write when another
|
|
721
|
+
// concurrent execution is already running and the status is PENDING. However,
|
|
722
|
+
// both executions should be deterministic and idempotent.)
|
|
723
|
+
//
|
|
724
|
+
// Returning false means the row was CANCELLED, dead-lettered, already
|
|
725
|
+
// terminal, handed to another execution (ENQUEUED/DELAYED, e.g. by a
|
|
726
|
+
// concurrent resume), or deleted; the caller resolves which by awaiting the
|
|
727
|
+
// recorded outcome.
|
|
722
728
|
async #recordWorkflowOutcome(client, workflowID, status, outcome) {
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
throwOnFailure: false,
|
|
730
|
-
});
|
|
731
|
-
cancelled = (await this.getWorkflowStatusValue(client, workflowID)) === workflow_1.StatusString.CANCELLED;
|
|
732
|
-
await client.query('COMMIT');
|
|
733
|
-
}
|
|
734
|
-
catch (e) {
|
|
735
|
-
await client.query('ROLLBACK');
|
|
736
|
-
throw e;
|
|
737
|
-
}
|
|
738
|
-
if (cancelled) {
|
|
739
|
-
throw new error_1.DBOSWorkflowCancelledError(workflowID);
|
|
740
|
-
}
|
|
729
|
+
const rowCount = await this.updateWorkflowStatus(client, workflowID, status, {
|
|
730
|
+
update: { ...outcome, resetDeduplicationID: true, setCompletedAt: true },
|
|
731
|
+
where: { status: workflow_1.StatusString.PENDING },
|
|
732
|
+
throwOnFailure: false,
|
|
733
|
+
});
|
|
734
|
+
return rowCount > 0;
|
|
741
735
|
}
|
|
742
736
|
async getPendingWorkflows(executorID, appVersion) {
|
|
743
737
|
const getWorkflows = await this.pool.query(`SELECT workflow_uuid
|
|
@@ -1487,7 +1481,12 @@ class SystemDatabase {
|
|
|
1487
1481
|
async #checkIfCanceledLimited(workflowID) {
|
|
1488
1482
|
await this.#pollWithLimiter(() => this.#checkIfCanceled(this.pool, workflowID));
|
|
1489
1483
|
}
|
|
1490
|
-
|
|
1484
|
+
// A missing row normally means the workflow has not been inserted yet, so
|
|
1485
|
+
// polling for it is correct. Callers that know the row must already exist
|
|
1486
|
+
// (e.g. a run parking on an outcome it just failed to write) pass
|
|
1487
|
+
// `failIfMissing` to fail fast with DBOSNonExistentWorkflowError instead of
|
|
1488
|
+
// polling forever.
|
|
1489
|
+
async awaitWorkflowResult(workflowID, timeoutSeconds, callerID, timerFuncID, pollingIntervalMs, failIfMissing) {
|
|
1491
1490
|
const timeoutms = timeoutSeconds !== undefined ? timeoutSeconds * 1000 : undefined;
|
|
1492
1491
|
let finishTime = timeoutms !== undefined ? Date.now() + timeoutms : undefined;
|
|
1493
1492
|
const pollIntervalMs = pollingIntervalMs ?? this.dbPollingIntervalResultMs;
|
|
@@ -1499,33 +1498,37 @@ class SystemDatabase {
|
|
|
1499
1498
|
while (true) {
|
|
1500
1499
|
if (callerID)
|
|
1501
1500
|
await this.#checkIfCanceledLimited(callerID);
|
|
1501
|
+
let rows;
|
|
1502
1502
|
try {
|
|
1503
|
-
|
|
1504
|
-
WHERE workflow_uuid=$1`, [workflowID]));
|
|
1505
|
-
if (rows.length > 0) {
|
|
1506
|
-
const status = rows[0].status;
|
|
1507
|
-
if (status === workflow_1.StatusString.SUCCESS) {
|
|
1508
|
-
return { output: rows[0].output, serialization: rows[0].serialization };
|
|
1509
|
-
}
|
|
1510
|
-
else if (status === workflow_1.StatusString.ERROR) {
|
|
1511
|
-
return { error: rows[0].error, serialization: rows[0].serialization };
|
|
1512
|
-
}
|
|
1513
|
-
else if (status === workflow_1.StatusString.CANCELLED) {
|
|
1514
|
-
return { cancelled: true };
|
|
1515
|
-
}
|
|
1516
|
-
else if (status === workflow_1.StatusString.MAX_RECOVERY_ATTEMPTS_EXCEEDED) {
|
|
1517
|
-
return { maxRecoveryAttemptsExceeded: true };
|
|
1518
|
-
}
|
|
1519
|
-
else {
|
|
1520
|
-
// Status is not actionable
|
|
1521
|
-
}
|
|
1522
|
-
}
|
|
1503
|
+
({ rows } = await this.#pollWithLimiter(() => this.pool.query(`SELECT status, output, error, serialization FROM "${this.schemaName}".workflow_status
|
|
1504
|
+
WHERE workflow_uuid=$1`, [workflowID])));
|
|
1523
1505
|
}
|
|
1524
1506
|
catch (e) {
|
|
1525
1507
|
const err = e;
|
|
1526
1508
|
this.logger.error(`Exception from system database: ${err}`, err);
|
|
1527
1509
|
throw err;
|
|
1528
1510
|
}
|
|
1511
|
+
if (rows.length > 0) {
|
|
1512
|
+
const status = rows[0].status;
|
|
1513
|
+
if (status === workflow_1.StatusString.SUCCESS) {
|
|
1514
|
+
return { output: rows[0].output, serialization: rows[0].serialization };
|
|
1515
|
+
}
|
|
1516
|
+
else if (status === workflow_1.StatusString.ERROR) {
|
|
1517
|
+
return { error: rows[0].error, serialization: rows[0].serialization };
|
|
1518
|
+
}
|
|
1519
|
+
else if (status === workflow_1.StatusString.CANCELLED) {
|
|
1520
|
+
return { cancelled: true };
|
|
1521
|
+
}
|
|
1522
|
+
else if (status === workflow_1.StatusString.MAX_RECOVERY_ATTEMPTS_EXCEEDED) {
|
|
1523
|
+
return { maxRecoveryAttemptsExceeded: true };
|
|
1524
|
+
}
|
|
1525
|
+
else {
|
|
1526
|
+
// Status is not actionable
|
|
1527
|
+
}
|
|
1528
|
+
}
|
|
1529
|
+
else if (failIfMissing) {
|
|
1530
|
+
throw new error_1.DBOSNonExistentWorkflowError(`Workflow ${workflowID} does not exist`);
|
|
1531
|
+
}
|
|
1529
1532
|
const ct = Date.now();
|
|
1530
1533
|
if (finishTime && ct > finishTime)
|
|
1531
1534
|
return undefined; // Time's up
|
|
@@ -3334,6 +3337,7 @@ class SystemDatabase {
|
|
|
3334
3337
|
if (throwOnFailure && result.rowCount !== 1) {
|
|
3335
3338
|
throw new error_1.DBOSWorkflowConflictError(`Attempt to record transition of nonexistent workflow ${workflowID}`);
|
|
3336
3339
|
}
|
|
3340
|
+
return result.rowCount ?? 0;
|
|
3337
3341
|
}
|
|
3338
3342
|
async recordOperationResultInternal(client, workflowID, functionID, functionName, checkConflict, startTimeEpochMs, endTimeEpochMs, options = {}) {
|
|
3339
3343
|
try {
|
|
@@ -3589,9 +3593,15 @@ __decorate([
|
|
|
3589
3593
|
__metadata("design:returntype", Promise)
|
|
3590
3594
|
], SystemDatabase.prototype, "debounceDelayedWorkflowStandalone", null);
|
|
3591
3595
|
__decorate([
|
|
3592
|
-
dbRetry()
|
|
3596
|
+
dbRetry()
|
|
3597
|
+
// A missing row normally means the workflow has not been inserted yet, so
|
|
3598
|
+
// polling for it is correct. Callers that know the row must already exist
|
|
3599
|
+
// (e.g. a run parking on an outcome it just failed to write) pass
|
|
3600
|
+
// `failIfMissing` to fail fast with DBOSNonExistentWorkflowError instead of
|
|
3601
|
+
// polling forever.
|
|
3602
|
+
,
|
|
3593
3603
|
__metadata("design:type", Function),
|
|
3594
|
-
__metadata("design:paramtypes", [String, Number, String, Number, Number]),
|
|
3604
|
+
__metadata("design:paramtypes", [String, Number, String, Number, Number, Boolean]),
|
|
3595
3605
|
__metadata("design:returntype", Promise)
|
|
3596
3606
|
], SystemDatabase.prototype, "awaitWorkflowResult", null);
|
|
3597
3607
|
__decorate([
|