@dbos-inc/dbos-sdk 5.4.10-preview → 5.4.11-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/cli/cli.js +56 -13
- package/dist/src/cli/cli.js.map +1 -1
- package/dist/src/client.d.ts +20 -10
- package/dist/src/client.d.ts.map +1 -1
- package/dist/src/client.js +76 -44
- package/dist/src/client.js.map +1 -1
- package/dist/src/config.d.ts +1 -0
- package/dist/src/config.d.ts.map +1 -1
- package/dist/src/config.js +1 -0
- package/dist/src/config.js.map +1 -1
- package/dist/src/context.d.ts +6 -0
- package/dist/src/context.d.ts.map +1 -1
- package/dist/src/context.js +15 -1
- package/dist/src/context.js.map +1 -1
- package/dist/src/datasource.d.ts +2 -0
- package/dist/src/datasource.d.ts.map +1 -1
- package/dist/src/datasource.js +7 -1
- package/dist/src/datasource.js.map +1 -1
- package/dist/src/dbos-executor.d.ts +7 -4
- package/dist/src/dbos-executor.d.ts.map +1 -1
- package/dist/src/dbos-executor.js +56 -30
- package/dist/src/dbos-executor.js.map +1 -1
- package/dist/src/dbos.d.ts +30 -10
- package/dist/src/dbos.d.ts.map +1 -1
- package/dist/src/dbos.js +136 -64
- package/dist/src/dbos.js.map +1 -1
- package/dist/src/enqueue_options.d.ts +2 -0
- package/dist/src/enqueue_options.d.ts.map +1 -1
- package/dist/src/enqueue_options.js +3 -0
- package/dist/src/enqueue_options.js.map +1 -1
- package/dist/src/enqueue_workflow.d.ts.map +1 -1
- package/dist/src/enqueue_workflow.js +11 -5
- package/dist/src/enqueue_workflow.js.map +1 -1
- package/dist/src/enterprise.d.ts +23 -3
- package/dist/src/enterprise.d.ts.map +1 -1
- package/dist/src/enterprise.js +81 -44
- package/dist/src/enterprise.js.map +1 -1
- package/dist/src/eventreceiver.d.ts +2 -0
- package/dist/src/eventreceiver.d.ts.map +1 -1
- package/dist/src/eventreceiver.js +7 -1
- package/dist/src/eventreceiver.js.map +1 -1
- package/dist/src/index.d.ts +1 -1
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js.map +1 -1
- package/dist/src/scheduler/scheduler.d.ts +5 -0
- package/dist/src/scheduler/scheduler.d.ts.map +1 -1
- package/dist/src/scheduler/scheduler.js +14 -4
- package/dist/src/scheduler/scheduler.js.map +1 -1
- package/dist/src/shard_keys.d.ts +13 -0
- package/dist/src/shard_keys.d.ts.map +1 -0
- package/dist/src/shard_keys.js +55 -0
- package/dist/src/shard_keys.js.map +1 -0
- package/dist/src/streams.d.ts +2 -0
- package/dist/src/streams.d.ts.map +1 -1
- package/dist/src/streams.js +5 -2
- package/dist/src/streams.js.map +1 -1
- package/dist/src/system_database.d.ts +143 -9
- package/dist/src/system_database.d.ts.map +1 -1
- package/dist/src/system_database.js +1095 -503
- package/dist/src/system_database.js.map +1 -1
- package/dist/src/wfqueue.d.ts +1 -2
- package/dist/src/wfqueue.d.ts.map +1 -1
- package/dist/src/wfqueue.js +83 -63
- package/dist/src/wfqueue.js.map +1 -1
- package/dist/src/workflow.d.ts +12 -2
- package/dist/src/workflow.d.ts.map +1 -1
- package/dist/src/workflow.js +14 -9
- package/dist/src/workflow.js.map +1 -1
- package/dist/src/workflow_management.d.ts +5 -3
- package/dist/src/workflow_management.d.ts.map +1 -1
- package/dist/src/workflow_management.js +45 -14
- package/dist/src/workflow_management.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +1 -1
package/dist/src/dbos.js
CHANGED
|
@@ -48,6 +48,7 @@ const crontab_1 = require("./scheduler/crontab");
|
|
|
48
48
|
const wfqueue_1 = require("./wfqueue");
|
|
49
49
|
const enqueue_workflow_1 = require("./enqueue_workflow");
|
|
50
50
|
const node_assert_1 = __importDefault(require("node:assert"));
|
|
51
|
+
const shard_keys_1 = require("./shard_keys");
|
|
51
52
|
function resolveTimeoutSeconds(options) {
|
|
52
53
|
if (options === undefined)
|
|
53
54
|
return undefined;
|
|
@@ -259,8 +260,29 @@ class DBOS {
|
|
|
259
260
|
* @param systemDatabaseUrl - The system database to create or migrate
|
|
260
261
|
* @param options.schemaName - The schema holding the DBOS system tables (default: `dbos`)
|
|
261
262
|
* @param options.applicationRole - A role to grant access to the system schema once migrated
|
|
263
|
+
* @param options.sharding - Create or migrate a sharded system database (requires @dbos-inc/dbos-enterprise)
|
|
262
264
|
*/
|
|
263
265
|
static async migrate(systemDatabaseUrl, options = {}) {
|
|
266
|
+
if (options.sharding) {
|
|
267
|
+
// Sharded migrations come from Transact Enterprise; the grant is the same.
|
|
268
|
+
const sysdb = (0, system_database_1.createSystemDatabase)({
|
|
269
|
+
systemDatabaseUrl,
|
|
270
|
+
logger: new logs_1.GlobalLogger(),
|
|
271
|
+
serializer: serialization_1.DBOSJSON,
|
|
272
|
+
schemaName: options.schemaName ?? 'dbos',
|
|
273
|
+
sharding: true,
|
|
274
|
+
});
|
|
275
|
+
try {
|
|
276
|
+
await sysdb.runMigrations();
|
|
277
|
+
}
|
|
278
|
+
finally {
|
|
279
|
+
await sysdb.destroy();
|
|
280
|
+
}
|
|
281
|
+
if (options.applicationRole) {
|
|
282
|
+
await (0, system_database_1.grantDbosSchemaPermissions)(systemDatabaseUrl, options.applicationRole, new logs_1.GlobalLogger(), options.schemaName ?? 'dbos');
|
|
283
|
+
}
|
|
284
|
+
return;
|
|
285
|
+
}
|
|
264
286
|
await (0, system_database_1.migrateSystemDatabase)(systemDatabaseUrl, new logs_1.GlobalLogger(), options.schemaName ?? 'dbos', options.applicationRole);
|
|
265
287
|
}
|
|
266
288
|
/**
|
|
@@ -289,7 +311,11 @@ class DBOS {
|
|
|
289
311
|
}
|
|
290
312
|
(0, decorators_1.finalizeClassRegistrations)();
|
|
291
313
|
// Every enterprise feature requires Conductor to report the org entitled to it, and the package.
|
|
292
|
-
|
|
314
|
+
let features = enterprise.enabledFeatures(config);
|
|
315
|
+
if (internalConfig.sharding) {
|
|
316
|
+
// Auto-upgrade is disabled on a sharded system database, so it needs no entitlement.
|
|
317
|
+
features = features.filter((f) => f !== enterprise.AUTO_UPGRADE);
|
|
318
|
+
}
|
|
293
319
|
const entitlementOptions = {
|
|
294
320
|
enterpriseKey: config.transactEnterpriseKey,
|
|
295
321
|
conductorKey: options?.conductorKey,
|
|
@@ -304,7 +330,7 @@ class DBOS {
|
|
|
304
330
|
: undefined;
|
|
305
331
|
// Workflows can also enroll for auto-upgrade individually, which the config flag's check above does not cover.
|
|
306
332
|
const autoUpgradableWorkflowNames = (0, auto_upgrade_1.autoUpgradableWorkflows)(internalConfig.autoUpgrade);
|
|
307
|
-
if (autoUpgradableWorkflowNames.length > 0 && !internalConfig.autoUpgrade) {
|
|
333
|
+
if (autoUpgradableWorkflowNames.length > 0 && !internalConfig.autoUpgrade && !internalConfig.sharding) {
|
|
308
334
|
await enterprise.requireEnterprise([enterprise.AUTO_UPGRADE], entitlementOptions);
|
|
309
335
|
loadedEnterprise ??= enterprise.load(enterprise.AUTO_UPGRADE.description);
|
|
310
336
|
}
|
|
@@ -395,7 +421,11 @@ class DBOS {
|
|
|
395
421
|
executor.conductor.start();
|
|
396
422
|
}
|
|
397
423
|
// Start the auto-upgrade loop if any workflow takes part.
|
|
398
|
-
if (autoUpgradableWorkflowNames.length > 0) {
|
|
424
|
+
if (autoUpgradableWorkflowNames.length > 0 && executor.systemDatabase.sharded) {
|
|
425
|
+
// Its queries aren't keyed by shard, so it doesn't run on a sharded database.
|
|
426
|
+
executor.logger.warn('Auto-upgrade is disabled: it is not supported on a sharded system database.');
|
|
427
|
+
}
|
|
428
|
+
else if (autoUpgradableWorkflowNames.length > 0) {
|
|
399
429
|
(0, node_assert_1.default)(loadedEnterprise, 'the enterprise package is loaded whenever a workflow enrolls in auto-upgrade');
|
|
400
430
|
const upgradePass = new loadedEnterprise.AutoUpgradePass(executor, {
|
|
401
431
|
graceMs: internalConfig.autoUpgradeGraceMs ?? auto_upgrade_1.DEFAULT_AUTO_UPGRADE_GRACE_MS,
|
|
@@ -459,7 +489,7 @@ class DBOS {
|
|
|
459
489
|
executor.autoUpgrader = undefined;
|
|
460
490
|
}
|
|
461
491
|
await executor.awaitRunningWorkflows(drainTimeoutMS);
|
|
462
|
-
await executor.
|
|
492
|
+
await executor.stopBackgroundJobs();
|
|
463
493
|
}
|
|
464
494
|
// Stop the conductor
|
|
465
495
|
if (executor?.conductor) {
|
|
@@ -541,6 +571,11 @@ class DBOS {
|
|
|
541
571
|
static get workflowID() {
|
|
542
572
|
return (0, context_1.getCurrentContextStore)()?.workflowId;
|
|
543
573
|
}
|
|
574
|
+
/** The shard key of the currently executing workflow; undefined outside a workflow or on an unsharded database. */
|
|
575
|
+
static get shardKey() {
|
|
576
|
+
const ctx = (0, context_1.getCurrentContextStore)();
|
|
577
|
+
return ctx?.workflowId !== undefined ? ctx.shardKey : undefined;
|
|
578
|
+
}
|
|
544
579
|
/** Use portable serialization by default? */
|
|
545
580
|
static get #defaultSerializationType() {
|
|
546
581
|
return (0, context_1.getCurrentContextStore)()?.serializationType;
|
|
@@ -603,21 +638,23 @@ class DBOS {
|
|
|
603
638
|
* @param workflowID - ID of the workflow
|
|
604
639
|
* @returns status of the workflow as `WorkflowStatus`, or `null` if there is no workflow with `workflowID`
|
|
605
640
|
*/
|
|
606
|
-
static getWorkflowStatus(workflowID) {
|
|
641
|
+
static async getWorkflowStatus(workflowID, options) {
|
|
607
642
|
(0, decorators_1.ensureDBOSIsLaunched)('getWorkflowStatus');
|
|
608
|
-
|
|
609
|
-
if (DBOS.
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
643
|
+
return await (0, shard_keys_1.bindShardKeys)([[workflowID, options?.shardKey]], () => {
|
|
644
|
+
if (DBOS.isWithinWorkflow()) {
|
|
645
|
+
if (DBOS.isInStep()) {
|
|
646
|
+
// OK to use directly
|
|
647
|
+
return DBOS.#executor.getWorkflowStatus(workflowID);
|
|
648
|
+
}
|
|
649
|
+
else if (DBOS.isInWorkflow()) {
|
|
650
|
+
return DBOS.#executor.getWorkflowStatus(workflowID, DBOS.workflowID, (0, context_1.functionIDGetIncrement)());
|
|
651
|
+
}
|
|
652
|
+
else {
|
|
653
|
+
throw new error_1.DBOSInvalidWorkflowTransitionError('Invalid call to `getWorkflowStatus` inside a `transaction`');
|
|
654
|
+
}
|
|
618
655
|
}
|
|
619
|
-
|
|
620
|
-
|
|
656
|
+
return DBOS.#executor.getWorkflowStatus(workflowID);
|
|
657
|
+
});
|
|
621
658
|
}
|
|
622
659
|
/**
|
|
623
660
|
* Get the workflow result, given a workflow ID
|
|
@@ -634,7 +671,8 @@ class DBOS {
|
|
|
634
671
|
// Reserve the function ID synchronously, before any await.
|
|
635
672
|
timerFuncID = (0, context_1.functionIDGetIncrement)();
|
|
636
673
|
}
|
|
637
|
-
|
|
674
|
+
const shardKey = typeof options === 'object' ? options.shardKey : undefined;
|
|
675
|
+
return await (0, shard_keys_1.bindShardKeys)([[workflowID, shardKey]], () => getResultInternal(workflowID, timeoutSeconds, timerFuncID, undefined, pollingIntervalMs));
|
|
638
676
|
}
|
|
639
677
|
/**
|
|
640
678
|
* Wait for any one of the given workflow handles to complete and return it.
|
|
@@ -658,9 +696,9 @@ class DBOS {
|
|
|
658
696
|
handleMap.set(handle.workflowID, handle);
|
|
659
697
|
}
|
|
660
698
|
const workflowIds = [...handleMap.keys()];
|
|
661
|
-
const completedId = await runInternalStep(async () => {
|
|
699
|
+
const completedId = await (0, shard_keys_1.bindShardKeys)(handles.map((h) => [h.workflowID, h.shardKey]), () => runInternalStep(async () => {
|
|
662
700
|
return await dbos_executor_1.DBOSExecutor.globalInstance.systemDatabase.awaitFirstWorkflowId(workflowIds, DBOS.workflowID, pollingIntervalMs);
|
|
663
|
-
}, 'DBOS.waitFirst');
|
|
701
|
+
}, 'DBOS.waitFirst'));
|
|
664
702
|
return handleMap.get(completedId);
|
|
665
703
|
}
|
|
666
704
|
/**
|
|
@@ -677,9 +715,9 @@ class DBOS {
|
|
|
677
715
|
}
|
|
678
716
|
const pollingIntervalMs = resolvePollingIntervalMs(options);
|
|
679
717
|
const workflowIds = [...new Set(handles.map((handle) => handle.workflowID))];
|
|
680
|
-
await runInternalStep(async () => {
|
|
718
|
+
await (0, shard_keys_1.bindShardKeys)(handles.map((h) => [h.workflowID, h.shardKey]), () => runInternalStep(async () => {
|
|
681
719
|
await dbos_executor_1.DBOSExecutor.globalInstance.systemDatabase.awaitWorkflowIds(workflowIds, DBOS.workflowID, pollingIntervalMs);
|
|
682
|
-
}, 'DBOS.waitAll');
|
|
720
|
+
}, 'DBOS.waitAll'));
|
|
683
721
|
return handles;
|
|
684
722
|
}
|
|
685
723
|
/**
|
|
@@ -689,15 +727,14 @@ class DBOS {
|
|
|
689
727
|
* @param workflowID - ID of the workflow
|
|
690
728
|
* @returns `WorkflowHandle` that can be used to poll for the status or result of any workflow with `workflowID`
|
|
691
729
|
*/
|
|
692
|
-
static retrieveWorkflow(workflowID) {
|
|
730
|
+
static retrieveWorkflow(workflowID, options) {
|
|
693
731
|
(0, decorators_1.ensureDBOSIsLaunched)('retrieveWorkflow');
|
|
694
|
-
if (DBOS.isWithinWorkflow()) {
|
|
695
|
-
|
|
696
|
-
throw new error_1.DBOSInvalidWorkflowTransitionError('Invalid call to `retrieveWorkflow` inside a `transaction` or `step`');
|
|
697
|
-
}
|
|
698
|
-
return new workflow_1.RetrievedHandle(workflowID);
|
|
732
|
+
if (DBOS.isWithinWorkflow() && !DBOS.isInWorkflow()) {
|
|
733
|
+
throw new error_1.DBOSInvalidWorkflowTransitionError('Invalid call to `retrieveWorkflow` inside a `transaction` or `step`');
|
|
699
734
|
}
|
|
700
|
-
|
|
735
|
+
// The resolved key, so the handle also works outside this binding.
|
|
736
|
+
const shardKey = (0, shard_keys_1.bindShardKeys)([[workflowID, options?.shardKey]], () => DBOS.#executor.systemDatabase.keyHint(workflowID));
|
|
737
|
+
return new workflow_1.RetrievedHandle(workflowID, shardKey);
|
|
701
738
|
}
|
|
702
739
|
/**
|
|
703
740
|
* Query the system database for all workflows matching the provided predicate
|
|
@@ -727,14 +764,14 @@ class DBOS {
|
|
|
727
764
|
* @param workflowID - ID of the workflow
|
|
728
765
|
* @param priority - Priority value (0 to 2,147,483,647). Lower values are dequeued first.
|
|
729
766
|
*/
|
|
730
|
-
static async setWorkflowPriority(workflowID, priority) {
|
|
767
|
+
static async setWorkflowPriority(workflowID, priority, options) {
|
|
731
768
|
(0, decorators_1.ensureDBOSIsLaunched)('setWorkflowPriority');
|
|
732
769
|
if (priority < dbos_executor_1.DBOS_QUEUE_MIN_PRIORITY || priority > dbos_executor_1.DBOS_QUEUE_MAX_PRIORITY) {
|
|
733
770
|
throw new error_1.DBOSInvalidQueuePriorityError(priority, dbos_executor_1.DBOS_QUEUE_MIN_PRIORITY, dbos_executor_1.DBOS_QUEUE_MAX_PRIORITY);
|
|
734
771
|
}
|
|
735
|
-
return runInternalStep(async () => {
|
|
772
|
+
return (0, shard_keys_1.bindShardKeys)([[workflowID, options?.shardKey]], () => runInternalStep(async () => {
|
|
736
773
|
return dbos_executor_1.DBOSExecutor.globalInstance.systemDatabase.setWorkflowPriority(workflowID, priority);
|
|
737
|
-
}, 'DBOS.setWorkflowPriority');
|
|
774
|
+
}, 'DBOS.setWorkflowPriority'));
|
|
738
775
|
}
|
|
739
776
|
/**
|
|
740
777
|
* Update the delay on a DELAYED workflow.
|
|
@@ -746,9 +783,10 @@ class DBOS {
|
|
|
746
783
|
static async setWorkflowDelay(workflowID, options) {
|
|
747
784
|
(0, decorators_1.ensureDBOSIsLaunched)('setWorkflowDelay');
|
|
748
785
|
const delayUntilEpochMS = resolveDelayEpochMS(options);
|
|
749
|
-
|
|
786
|
+
const shardKey = typeof options === 'object' ? options.shardKey : undefined;
|
|
787
|
+
return (0, shard_keys_1.bindShardKeys)([[workflowID, shardKey]], () => runInternalStep(async () => {
|
|
750
788
|
return dbos_executor_1.DBOSExecutor.globalInstance.systemDatabase.setWorkflowDelay(workflowID, delayUntilEpochMS);
|
|
751
|
-
}, 'DBOS.setWorkflowDelay');
|
|
789
|
+
}, 'DBOS.setWorkflowDelay'));
|
|
752
790
|
}
|
|
753
791
|
/**
|
|
754
792
|
* Retrieve the steps of a workflow
|
|
@@ -758,9 +796,9 @@ class DBOS {
|
|
|
758
796
|
*/
|
|
759
797
|
static async listWorkflowSteps(workflowID, options) {
|
|
760
798
|
(0, decorators_1.ensureDBOSIsLaunched)('listWorkflowSteps');
|
|
761
|
-
return await runInternalStep(async () => {
|
|
799
|
+
return await (0, shard_keys_1.bindShardKeys)([[workflowID, options?.shardKey]], () => runInternalStep(async () => {
|
|
762
800
|
return await DBOS.#executor.listWorkflowSteps(workflowID, true, options);
|
|
763
|
-
}, 'DBOS.listWorkflowSteps');
|
|
801
|
+
}, 'DBOS.listWorkflowSteps'));
|
|
764
802
|
}
|
|
765
803
|
/**
|
|
766
804
|
* Cancel a workflow given its ID.
|
|
@@ -779,9 +817,9 @@ class DBOS {
|
|
|
779
817
|
*/
|
|
780
818
|
static async cancelWorkflows(workflowIDs, options) {
|
|
781
819
|
(0, decorators_1.ensureDBOSIsLaunched)('cancelWorkflows');
|
|
782
|
-
return runInternalStep(async () => {
|
|
820
|
+
return (0, shard_keys_1.bindShardKeys)(workflowIDs.map((wid) => [wid, options?.shardKey]), () => runInternalStep(async () => {
|
|
783
821
|
return dbos_executor_1.DBOSExecutor.globalInstance.systemDatabase.cancelWorkflows(workflowIDs, options?.cancelChildren);
|
|
784
|
-
}, 'DBOS.cancelWorkflow');
|
|
822
|
+
}, 'DBOS.cancelWorkflow'));
|
|
785
823
|
}
|
|
786
824
|
/**
|
|
787
825
|
* Resume a workflow given its ID.
|
|
@@ -789,8 +827,11 @@ class DBOS {
|
|
|
789
827
|
* @throws DBOSNonExistentWorkflowError if the workflow does not exist
|
|
790
828
|
*/
|
|
791
829
|
static async resumeWorkflow(workflowID, options) {
|
|
792
|
-
|
|
793
|
-
|
|
830
|
+
return await (0, shard_keys_1.bindShardKeys)([[workflowID, options?.shardKey]], async () => {
|
|
831
|
+
await this.resumeWorkflows([workflowID], options);
|
|
832
|
+
// The resolved key, so the handle also works outside this binding.
|
|
833
|
+
return new workflow_1.RetrievedHandle(workflowID, DBOS.#executor.systemDatabase.keyHint(workflowID));
|
|
834
|
+
});
|
|
794
835
|
}
|
|
795
836
|
/**
|
|
796
837
|
* Resume multiple workflows given their IDs.
|
|
@@ -800,10 +841,12 @@ class DBOS {
|
|
|
800
841
|
*/
|
|
801
842
|
static async resumeWorkflows(workflowIDs, options) {
|
|
802
843
|
(0, decorators_1.ensureDBOSIsLaunched)('resumeWorkflows');
|
|
803
|
-
await
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
844
|
+
return await (0, shard_keys_1.bindShardKeys)(workflowIDs.map((wid) => [wid, options?.shardKey]), async () => {
|
|
845
|
+
await runInternalStep(async () => {
|
|
846
|
+
return dbos_executor_1.DBOSExecutor.globalInstance.systemDatabase.resumeWorkflows(workflowIDs, options?.queueName);
|
|
847
|
+
}, 'DBOS.resumeWorkflow');
|
|
848
|
+
return workflowIDs.map((wfid) => new workflow_1.RetrievedHandle(wfid, options?.shardKey));
|
|
849
|
+
});
|
|
807
850
|
}
|
|
808
851
|
/**
|
|
809
852
|
* Delete a workflow and optionally all its child workflows.
|
|
@@ -814,8 +857,8 @@ class DBOS {
|
|
|
814
857
|
* @param workflowID - ID of the workflow to delete
|
|
815
858
|
* @param deleteChildren - If true, also delete all child workflows recursively (default: false)
|
|
816
859
|
*/
|
|
817
|
-
static async deleteWorkflow(workflowID, deleteChildren = false) {
|
|
818
|
-
return this.deleteWorkflows([workflowID], deleteChildren);
|
|
860
|
+
static async deleteWorkflow(workflowID, deleteChildren = false, options) {
|
|
861
|
+
return this.deleteWorkflows([workflowID], deleteChildren, options);
|
|
819
862
|
}
|
|
820
863
|
/**
|
|
821
864
|
* Delete multiple workflows and optionally all their child workflows.
|
|
@@ -825,11 +868,11 @@ class DBOS {
|
|
|
825
868
|
* @param workflowIDs - IDs of the workflows to delete
|
|
826
869
|
* @param deleteChildren - If true, also delete all child workflows recursively (default: false)
|
|
827
870
|
*/
|
|
828
|
-
static async deleteWorkflows(workflowIDs, deleteChildren = false) {
|
|
871
|
+
static async deleteWorkflows(workflowIDs, deleteChildren = false, options) {
|
|
829
872
|
(0, decorators_1.ensureDBOSIsLaunched)('deleteWorkflows');
|
|
830
|
-
return runInternalStep(async () => {
|
|
873
|
+
return (0, shard_keys_1.bindShardKeys)(workflowIDs.map((wid) => [wid, options?.shardKey]), () => runInternalStep(async () => {
|
|
831
874
|
return dbos_executor_1.DBOSExecutor.globalInstance.systemDatabase.deleteWorkflows(workflowIDs, deleteChildren);
|
|
832
|
-
}, 'DBOS.deleteWorkflow');
|
|
875
|
+
}, 'DBOS.deleteWorkflow'));
|
|
833
876
|
}
|
|
834
877
|
/**
|
|
835
878
|
* Fork a workflow given its ID.
|
|
@@ -841,10 +884,14 @@ class DBOS {
|
|
|
841
884
|
*/
|
|
842
885
|
static async forkWorkflow(workflowID, startStep, options) {
|
|
843
886
|
(0, decorators_1.ensureDBOSIsLaunched)('forkWorkflow');
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
887
|
+
return await (0, shard_keys_1.bindShardKeys)([[workflowID, options?.shardKey]], async () => {
|
|
888
|
+
const forkedID = await runInternalStep(async () => {
|
|
889
|
+
return await DBOS.#executor.forkWorkflow(workflowID, startStep, options);
|
|
890
|
+
}, 'DBOS.forkWorkflow');
|
|
891
|
+
// A fork lives under its original's shard key, however the caller supplied it.
|
|
892
|
+
const forkKey = DBOS.#executor.systemDatabase.keyHint(workflowID);
|
|
893
|
+
return new workflow_1.RetrievedHandle(forkedID, forkKey);
|
|
894
|
+
});
|
|
848
895
|
}
|
|
849
896
|
/**
|
|
850
897
|
* Rewind a workflow given its ID: drop its recorded history from `startStep` onwards
|
|
@@ -868,10 +915,13 @@ class DBOS {
|
|
|
868
915
|
static async rewindWorkflow(workflowID, options) {
|
|
869
916
|
(0, decorators_1.ensureDBOSIsLaunched)('rewindWorkflow');
|
|
870
917
|
const startStep = options?.startStep ?? 0;
|
|
871
|
-
await
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
918
|
+
return await (0, shard_keys_1.bindShardKeys)([[workflowID, options?.shardKey]], async () => {
|
|
919
|
+
await runInternalStep(async () => {
|
|
920
|
+
return await DBOS.#executor.rewindWorkflow(workflowID, startStep, options ?? {});
|
|
921
|
+
}, 'DBOS.rewindWorkflow');
|
|
922
|
+
// The resolved key, so the handle also works outside this binding.
|
|
923
|
+
return new workflow_1.RetrievedHandle(workflowID, DBOS.#executor.systemDatabase.keyHint(workflowID));
|
|
924
|
+
});
|
|
875
925
|
}
|
|
876
926
|
/**
|
|
877
927
|
* Sleep for the specified amount of time.
|
|
@@ -986,6 +1036,13 @@ class DBOS {
|
|
|
986
1036
|
(0, decorators_1.ensureDBOSIsLaunched)('workflows');
|
|
987
1037
|
return DBOS.#withTopContext({ workflowTimeoutMS: timeoutMS }, callback);
|
|
988
1038
|
}
|
|
1039
|
+
/** Set the shard key of each workflow started, enqueued, or called in `callback`; their children don't inherit it. */
|
|
1040
|
+
static async withShardKey(shardKey, callback) {
|
|
1041
|
+
if (typeof shardKey !== 'string' || shardKey === '') {
|
|
1042
|
+
throw new error_1.DBOSError('shardKey must be a non-empty string');
|
|
1043
|
+
}
|
|
1044
|
+
return DBOS.#withTopContext({ shardKeyForNextWorkflow: shardKey }, callback);
|
|
1045
|
+
}
|
|
989
1046
|
static async #withTopContext(options, callback) {
|
|
990
1047
|
const pctx = (0, context_1.getCurrentContextStore)();
|
|
991
1048
|
if (pctx) {
|
|
@@ -1073,16 +1130,16 @@ class DBOS {
|
|
|
1073
1130
|
// calls in the same workflow don't race for IDs.
|
|
1074
1131
|
const functionID = (0, context_1.functionIDGetIncrement)();
|
|
1075
1132
|
const sermsg = await (0, serialization_1.serializeValue)(message, DBOS.#executor.serializer, options?.serializationType ?? DBOS.#defaultSerializationType);
|
|
1076
|
-
return await dbos_executor_1.DBOSExecutor.globalInstance.systemDatabase.send(DBOS.workflowID, functionID, destinationID, sermsg.serializedValue, topic, sermsg.serialization, idempotencyKey);
|
|
1133
|
+
return await dbos_executor_1.DBOSExecutor.globalInstance.systemDatabase.send(DBOS.workflowID, functionID, destinationID, sermsg.serializedValue, topic, sermsg.serialization, idempotencyKey, options?.shardKey);
|
|
1077
1134
|
}
|
|
1078
1135
|
else if (DBOS.isInStep()) {
|
|
1079
1136
|
// Inside a step: not recorded, but fenced on the enclosing workflow's ownership.
|
|
1080
1137
|
const sermsg = await (0, serialization_1.serializeValue)(message, DBOS.#executor.serializer, options?.serializationType ?? DBOS.#defaultSerializationType);
|
|
1081
|
-
return await dbos_executor_1.DBOSExecutor.globalInstance.systemDatabase.sendFromStep(DBOS.workflowID, destinationID, sermsg.serializedValue, topic, sermsg.serialization, idempotencyKey);
|
|
1138
|
+
return await dbos_executor_1.DBOSExecutor.globalInstance.systemDatabase.sendFromStep(DBOS.workflowID, destinationID, sermsg.serializedValue, topic, sermsg.serialization, idempotencyKey, options?.shardKey);
|
|
1082
1139
|
}
|
|
1083
1140
|
else {
|
|
1084
1141
|
const sermsg = await (0, serialization_1.serializeValue)(message, DBOS.#executor.serializer, options?.serializationType ?? DBOS.#defaultSerializationType);
|
|
1085
|
-
return dbos_executor_1.DBOSExecutor.globalInstance.systemDatabase.sendDirect(destinationID, sermsg.serializedValue, topic, sermsg.serialization, idempotencyKey);
|
|
1142
|
+
return dbos_executor_1.DBOSExecutor.globalInstance.systemDatabase.sendDirect(destinationID, sermsg.serializedValue, topic, sermsg.serialization, idempotencyKey, undefined, options?.shardKey);
|
|
1086
1143
|
}
|
|
1087
1144
|
}
|
|
1088
1145
|
/**
|
|
@@ -1150,6 +1207,10 @@ class DBOS {
|
|
|
1150
1207
|
*/
|
|
1151
1208
|
static async getEvent(workflowID, key, options) {
|
|
1152
1209
|
(0, decorators_1.ensureDBOSIsLaunched)('getEvent');
|
|
1210
|
+
const shardKey = typeof options === 'object' ? options.shardKey : undefined;
|
|
1211
|
+
return await (0, shard_keys_1.bindShardKeys)([[workflowID, shardKey]], () => DBOS.#getEvent(workflowID, key, options));
|
|
1212
|
+
}
|
|
1213
|
+
static async #getEvent(workflowID, key, options) {
|
|
1153
1214
|
const timeoutSeconds = resolveTimeoutSeconds(options);
|
|
1154
1215
|
const pollingIntervalMs = resolvePollingIntervalMs(options);
|
|
1155
1216
|
if (DBOS.isWithinWorkflow()) {
|
|
@@ -1227,6 +1288,7 @@ class DBOS {
|
|
|
1227
1288
|
timeoutMS: resolveStreamTimeoutMS(options),
|
|
1228
1289
|
functionName: system_database_1.DBOS_FUNCNAME_READSTREAM,
|
|
1229
1290
|
checkpoint: true,
|
|
1291
|
+
shardKey: options.shardKey,
|
|
1230
1292
|
});
|
|
1231
1293
|
}
|
|
1232
1294
|
/**
|
|
@@ -1250,6 +1312,7 @@ class DBOS {
|
|
|
1250
1312
|
timeoutMS: resolveStreamTimeoutMS(options),
|
|
1251
1313
|
functionName: system_database_1.DBOS_FUNCNAME_READSTREAMOFFSET,
|
|
1252
1314
|
checkpoint: true,
|
|
1315
|
+
shardKey: options.shardKey,
|
|
1253
1316
|
});
|
|
1254
1317
|
}
|
|
1255
1318
|
//////
|
|
@@ -1306,6 +1369,8 @@ class DBOS {
|
|
|
1306
1369
|
const ppctx = (0, context_1.getCurrentContextStore)();
|
|
1307
1370
|
const queueName = params.queueName ?? ppctx?.queueAssignedForWorkflows;
|
|
1308
1371
|
const timeoutMS = params.timeoutMS ?? ppctx?.workflowTimeoutMS;
|
|
1372
|
+
// Set by DBOS.withShardKey; a workflow never inherits its caller's own key.
|
|
1373
|
+
const shardKey = (0, context_1.nextWorkflowShardKey)(ppctx);
|
|
1309
1374
|
const instance = $this === undefined || typeof $this === 'function' ? undefined : $this;
|
|
1310
1375
|
if (instance && !(instance instanceof decorators_1.ConfiguredInstance)) {
|
|
1311
1376
|
throw new error_1.DBOSInvalidWorkflowTransitionError('Attempt to call a `workflow` function on an object that is not a `ConfiguredInstance`');
|
|
@@ -1343,7 +1408,7 @@ class DBOS {
|
|
|
1343
1408
|
if (isChild) {
|
|
1344
1409
|
const pwfid = ppctx.workflowId;
|
|
1345
1410
|
const wfParams = {
|
|
1346
|
-
workflowUUID: wfId || pwfid
|
|
1411
|
+
workflowUUID: wfId || (0, context_1.childWorkflowID)(pwfid, funcId, ppctx?.shardKey, shardKey),
|
|
1347
1412
|
configuredInstance: instance,
|
|
1348
1413
|
queueName,
|
|
1349
1414
|
timeoutMS,
|
|
@@ -1355,6 +1420,7 @@ class DBOS {
|
|
|
1355
1420
|
workflowAttributes: params.workflowAttributes,
|
|
1356
1421
|
authenticatedUser: params.authenticatedUser,
|
|
1357
1422
|
authenticatedRoles: params.authenticatedRoles,
|
|
1423
|
+
shardKey,
|
|
1358
1424
|
};
|
|
1359
1425
|
return await invokeRegOp(wfParams, pwfid, funcId);
|
|
1360
1426
|
}
|
|
@@ -1370,6 +1436,7 @@ class DBOS {
|
|
|
1370
1436
|
workflowAttributes: params.workflowAttributes,
|
|
1371
1437
|
authenticatedUser: params.authenticatedUser,
|
|
1372
1438
|
authenticatedRoles: params.authenticatedRoles,
|
|
1439
|
+
shardKey,
|
|
1373
1440
|
};
|
|
1374
1441
|
return await invokeRegOp(wfParams, undefined, undefined);
|
|
1375
1442
|
}
|
|
@@ -1396,6 +1463,8 @@ class DBOS {
|
|
|
1396
1463
|
// Reserve the parent's child-funcID once, before any await. Each loop iteration passes it
|
|
1397
1464
|
// through so the return-existing retry loop consumes a single funcID instead of one per try.
|
|
1398
1465
|
const childFuncId = DBOS.isInWorkflow() ? (0, context_1.functionIDGetIncrement)() : undefined;
|
|
1466
|
+
// The key the attached-to workflow lives under, as the start would have used.
|
|
1467
|
+
const shardKey = (0, context_1.nextWorkflowShardKey)((0, context_1.getCurrentContextStore)());
|
|
1399
1468
|
// Resolve the workflow ID once: if the caller supplied one explicitly or via
|
|
1400
1469
|
// `withNextWorkflowID`, reuse it on every iteration.
|
|
1401
1470
|
const resolvedWorkflowID = (0, context_1.getNextWFID)(params.workflowID);
|
|
@@ -1416,7 +1485,7 @@ class DBOS {
|
|
|
1416
1485
|
const now = Date.now();
|
|
1417
1486
|
await dbos_executor_1.DBOSExecutor.globalInstance.systemDatabase.recordOperationResult(DBOS.workflowID, childFuncId, regOP.name, true, now, now, { childWorkflowID: existingID });
|
|
1418
1487
|
}
|
|
1419
|
-
return new workflow_1.RetrievedHandle(existingID);
|
|
1488
|
+
return new workflow_1.RetrievedHandle(existingID, shardKey);
|
|
1420
1489
|
}
|
|
1421
1490
|
// The prior workflow's deduplication_id was cleared between our INSERT and
|
|
1422
1491
|
// the lookup (it completed or was cancelled). Loop and try to claim the slot.
|
|
@@ -1700,6 +1769,7 @@ class DBOS {
|
|
|
1700
1769
|
cronTimezone: options.options?.cronTimezone ?? null,
|
|
1701
1770
|
queueName: options.options?.queueName ?? null,
|
|
1702
1771
|
applicationName: utils_1.globalParams.appName,
|
|
1772
|
+
shardKey: options.options?.shardKey,
|
|
1703
1773
|
};
|
|
1704
1774
|
await runTransactionalInternalStep((client) => dbos_executor_1.DBOSExecutor.globalInstance.systemDatabase.createSchedule(schedInternal, client), 'DBOS.createSchedule');
|
|
1705
1775
|
}
|
|
@@ -1785,6 +1855,7 @@ class DBOS {
|
|
|
1785
1855
|
automaticBackfill: sched.automaticBackfill ?? false,
|
|
1786
1856
|
cronTimezone: sched.cronTimezone ?? null,
|
|
1787
1857
|
queueName: sched.queueName ?? null,
|
|
1858
|
+
shardKey: sched.shardKey,
|
|
1788
1859
|
});
|
|
1789
1860
|
}
|
|
1790
1861
|
await dbos_executor_1.DBOSExecutor.globalInstance.systemDatabase.applySchedules(internals);
|
|
@@ -1796,7 +1867,7 @@ class DBOS {
|
|
|
1796
1867
|
}
|
|
1797
1868
|
const executor = dbos_executor_1.DBOSExecutor.globalInstance;
|
|
1798
1869
|
const workflowID = await (0, scheduler_1.triggerSchedule)(executor.systemDatabase, executor.serializer, name);
|
|
1799
|
-
return new workflow_1.RetrievedHandle(workflowID);
|
|
1870
|
+
return new workflow_1.RetrievedHandle(workflowID, await (0, scheduler_1.scheduleShardKey)(executor.systemDatabase, name));
|
|
1800
1871
|
}
|
|
1801
1872
|
static async backfillSchedule(name, start, end) {
|
|
1802
1873
|
(0, decorators_1.ensureDBOSIsLaunched)('backfillSchedule');
|
|
@@ -1805,7 +1876,8 @@ class DBOS {
|
|
|
1805
1876
|
}
|
|
1806
1877
|
const executor = dbos_executor_1.DBOSExecutor.globalInstance;
|
|
1807
1878
|
const workflowIDs = await (0, scheduler_1.backfillSchedule)(executor.systemDatabase, executor.serializer, name, start, end);
|
|
1808
|
-
|
|
1879
|
+
const shardKey = await (0, scheduler_1.scheduleShardKey)(executor.systemDatabase, name);
|
|
1880
|
+
return workflowIDs.map((id) => new workflow_1.RetrievedHandle(id, shardKey));
|
|
1809
1881
|
}
|
|
1810
1882
|
// ==================== Application Versions ====================
|
|
1811
1883
|
/**
|