@brandboostinggmbh/observable-workflows 0.21.1 → 0.22.0

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/index.d.ts CHANGED
@@ -91,6 +91,16 @@ interface PrepareWorkflowInsertParams {
91
91
  * When provided, dependency insert statements are included in the returned statements array.
92
92
  */
93
93
  dependencies?: Array<WorkflowDependency>;
94
+ /**
95
+ * Optional delay in seconds before the queue message is delivered.
96
+ * Stored in the DB for transparency so the original delay intent is preserved.
97
+ */
98
+ delaySeconds?: number | null;
99
+ /**
100
+ * Absolute epoch-millisecond timestamp indicating the earliest time the queue message
101
+ * will be delivered. `null` or absent when no delay was requested.
102
+ */
103
+ scheduledFor?: number | null;
94
104
  }
95
105
  /** Result from preparing workflow insert statements */
96
106
 
@@ -214,6 +224,8 @@ declare function workflowTableRowToWorkflowRun({
214
224
  endTime: number | null;
215
225
  parentInstanceId: string | null;
216
226
  triggerId: string | null;
227
+ delaySeconds?: number | null;
228
+ scheduledFor?: number | null;
217
229
  };
218
230
  serializer: Serializer;
219
231
  externalBlobStorage?: ExternalBlobStorage;
@@ -259,6 +271,8 @@ declare function updateWorkflow(context: InternalWorkflowContextOptions, instanc
259
271
  startTime?: number;
260
272
  parentInstanceId?: string | null;
261
273
  triggerId?: string | null;
274
+ delaySeconds?: number | null;
275
+ scheduledFor?: number | null;
262
276
  }): Promise<D1Result<Record<string, unknown>> | {
263
277
  success: boolean;
264
278
  meta: {
@@ -484,6 +498,22 @@ type WorkflowRun = {
484
498
  isRetryOf?: WorkflowRun | null;
485
499
  retries?: WorkflowRun[] | null;
486
500
  properties?: WorkflowProperty[];
501
+ /**
502
+ * Optional queue delivery delay in seconds. Stored for transparency so the original
503
+ * delay intent is preserved. For waiting workflows, this value is applied when the
504
+ * workflow transitions from 'waiting' to 'scheduled'.
505
+ */
506
+ delaySeconds?: number | null;
507
+ /**
508
+ * Absolute epoch-millisecond timestamp indicating the earliest time the queue message
509
+ * will be delivered. Computed as `enqueueTime + delaySeconds * 1000` at the moment the
510
+ * message is actually sent to the queue.
511
+ *
512
+ * - For directly-scheduled workflows: set at enqueue time.
513
+ * - For waiting workflows: set when dependencies finish and the workflow transitions to 'scheduled'.
514
+ * - `null` or absent when no delay was requested.
515
+ */
516
+ scheduledFor?: number | null;
487
517
  /** Workflows that this workflow depends on (must complete before this workflow can start) */
488
518
  dependencies?: WorkflowDependencyRelation[];
489
519
  /** Workflows that depend on this workflow (will start after this workflow completes) */
@@ -694,6 +724,12 @@ type WorkflowEnqueueBatchItem<I, O, TYPE extends string = string> = {
694
724
  dependencies?: WorkflowDependency[];
695
725
  /** Optional trigger identifier for workflow correlation. If not provided, one will be auto-generated. */
696
726
  triggerId?: string | null;
727
+ /**
728
+ * Optional delay in seconds before the queue message is delivered.
729
+ * Maps directly to the Cloudflare Queue `delaySeconds` option.
730
+ * The message will not be delivered to a consumer until at least this many seconds have passed.
731
+ */
732
+ delaySeconds?: number;
697
733
  };
698
734
  type WorkflowQueueMessage = {
699
735
  type: 'workflow-run';
@@ -704,6 +740,8 @@ type WorkflowQueueMessage = {
704
740
  triggerId?: string | null;
705
741
  queueIdentifier?: string;
706
742
  scheduledInstanceId?: string | undefined;
743
+ /** Queue delivery delay in seconds (passed through to Cloudflare Queue) */
744
+ delaySeconds?: number;
707
745
  } | {
708
746
  type: 'workflow-retry';
709
747
  workflowType: string;
@@ -713,6 +751,7 @@ type WorkflowQueueMessage = {
713
751
  /** If true the workflow will attempt to reuse all results from successful steps. Defaults to True */
714
752
  reuseSuccessfulSteps?: boolean;
715
753
  queueIdentifier?: string;
754
+ scheduledInstanceId?: string | undefined;
716
755
  };
717
756
  type RetryWorkflowOptions = {
718
757
  /** If true the retry will attept to reuse all results from successful steps. Defaults to True */
@@ -723,6 +762,8 @@ type RetryWorkflowParams<I, O> = {
723
762
  retryInstanceId: string;
724
763
  triggerId?: string | null;
725
764
  retryOptions?: RetryWorkflowOptions;
765
+ /** Optional: Provide an existing workflow instance ID. When provided, retry will update the existing instance instead of creating a new one. */
766
+ scheduledInstanceId?: string | undefined;
726
767
  };
727
768
  type WorkflowCallParams<I, O> = {
728
769
  workflow: WorkflowFunction<I, O>;
@@ -878,7 +919,7 @@ declare const createLogAccessor: (context: {
878
919
  declare function createQueueWorkflowContext(options: QueueWorkflowContextOptions): {
879
920
  enqueueWorkflow: <I, O, TYPE extends string>(params: WorkflowEnqueueBatchItem<I, O, TYPE>) => Promise<ScheduledWorkflowExecutionStub<O, TYPE>>;
880
921
  enqueueWorkflowBatch: <I, O>(workflows: Array<WorkflowEnqueueBatchItem<I, O>>) => Promise<Array<ScheduledWorkflowExecutionStub<O, string>>>;
881
- enqueueRetryWorkflow: <I, O>(workflow: WorkflowFunction<I, O>, tenantId: string, oldInstanceId: string, reuseSuccessfulSteps?: boolean) => Promise<void>;
922
+ enqueueRetryWorkflow: <I, O, TYPE extends string>(workflow: WorkflowFunction<I, O, TYPE>, tenantId: string, oldInstanceId: string, reuseSuccessfulSteps?: boolean, delaySeconds?: number) => Promise<ScheduledWorkflowExecutionStub<O, TYPE>>;
882
923
  handleWorkflowQueueMessage: ({
883
924
  message,
884
925
  env,
package/dist/index.js CHANGED
@@ -9,8 +9,10 @@ async function detectSchemaVersion(db, retryConfig) {
9
9
  const hasInputRef = workflowTableInfo.sql.includes("inputRef");
10
10
  const hasTriggerId = workflowTableInfo.sql.includes("triggerId");
11
11
  const hasResultRef = workflowTableInfo.sql.includes("resultRef");
12
+ const hasDelaySeconds = workflowTableInfo.sql.includes("delaySeconds");
12
13
  const inputHasNotNull = workflowTableInfo.sql.includes("input TEXT NOT NULL");
13
- if (hasResultRef && hasTriggerId && hasInputRef && !inputHasNotNull) workflowTable = "v6";
14
+ if (hasDelaySeconds && hasResultRef && hasTriggerId && hasInputRef && !inputHasNotNull) workflowTable = "v8";
15
+ else if (hasResultRef && hasTriggerId && hasInputRef && !inputHasNotNull) workflowTable = "v6";
14
16
  else if (hasTriggerId && hasInputRef && !inputHasNotNull && !hasResultRef) workflowTable = "v4";
15
17
  else if (hasInputRef && !inputHasNotNull && !hasTriggerId) workflowTable = "v2";
16
18
  else if (!hasInputRef && inputHasNotNull) workflowTable = "v1";
@@ -123,6 +125,23 @@ async function migrateWorkflowTableV4ToV6(db, retryConfig) {
123
125
  if (!hasResultRef) await retryD1Operation(() => db.batch([db.prepare(`ALTER TABLE WorkflowTable ADD COLUMN result TEXT`), db.prepare(`ALTER TABLE WorkflowTable ADD COLUMN resultRef TEXT`)]), retryConfig);
124
126
  }
125
127
  /**
128
+ * Migrate WorkflowTable from V6 to V8 schema
129
+ * Adds delaySeconds and scheduledFor columns for delayed workflow scheduling.
130
+ *
131
+ * - `delaySeconds` (INTEGER, nullable): The original delay intent in seconds. Preserved so that
132
+ * waiting workflows can apply the delay when they transition to 'scheduled'.
133
+ * - `scheduledFor` (INTEGER, nullable): Absolute epoch-millisecond timestamp indicating the
134
+ * earliest time the queue message will be delivered. For directly-scheduled workflows this is
135
+ * computed at enqueue time (`startTime + delaySeconds * 1000`). For waiting workflows it is
136
+ * computed at transition time (`transitionTime + delaySeconds * 1000`). NULL when no delay
137
+ * was requested.
138
+ */
139
+ async function migrateWorkflowTableV6ToV8(db, retryConfig) {
140
+ const workflowTableInfo = await retryD1Operation(() => db.prepare(`SELECT sql FROM sqlite_master WHERE type='table' AND name='WorkflowTable'`).first(), retryConfig);
141
+ const hasDelaySeconds = workflowTableInfo.sql.includes("delaySeconds");
142
+ if (!hasDelaySeconds) await retryD1Operation(() => db.batch([db.prepare(`ALTER TABLE WorkflowTable ADD COLUMN delaySeconds INTEGER`), db.prepare(`ALTER TABLE WorkflowTable ADD COLUMN scheduledFor INTEGER`)]), retryConfig);
143
+ }
144
+ /**
126
145
  * Create or migrate WorkflowTable to the latest schema
127
146
  */
128
147
  async function migrateWorkflowTable(db, currentVersion, retryConfig) {
@@ -142,6 +161,8 @@ async function migrateWorkflowTable(db, currentVersion, retryConfig) {
142
161
  endTime INTEGER,
143
162
  parentInstanceId TEXT,
144
163
  triggerId TEXT,
164
+ delaySeconds INTEGER,
165
+ scheduledFor INTEGER,
145
166
  PRIMARY KEY (instanceId),
146
167
  UNIQUE (triggerId)
147
168
  )`).run(), retryConfig);
@@ -151,15 +172,22 @@ async function migrateWorkflowTable(db, currentVersion, retryConfig) {
151
172
  await migrateWorkflowTableV1ToV2(db, retryConfig);
152
173
  await migrateWorkflowTableV2V3ToV4(db, retryConfig);
153
174
  await migrateWorkflowTableV4ToV6(db, retryConfig);
175
+ await migrateWorkflowTableV6ToV8(db, retryConfig);
154
176
  return;
155
177
  }
156
178
  if (currentVersion === "v2") {
157
179
  await migrateWorkflowTableV2V3ToV4(db, retryConfig);
158
180
  await migrateWorkflowTableV4ToV6(db, retryConfig);
181
+ await migrateWorkflowTableV6ToV8(db, retryConfig);
159
182
  return;
160
183
  }
161
184
  if (currentVersion === "v4") {
162
185
  await migrateWorkflowTableV4ToV6(db, retryConfig);
186
+ await migrateWorkflowTableV6ToV8(db, retryConfig);
187
+ return;
188
+ }
189
+ if (currentVersion === "v6") {
190
+ await migrateWorkflowTableV6ToV8(db, retryConfig);
163
191
  return;
164
192
  }
165
193
  }
@@ -468,11 +496,11 @@ async function finalizeWorkflowRecord(options, { workflowStatus, endTime, instan
468
496
  *
469
497
  * @internal
470
498
  */
471
- async function prepareWorkflowInsertStatements(options, { instanceId, workflowType, workflowName, workflowMetadata, input, workflowStatus, startTime, endTime, parentInstanceId, tenantId, triggerId, dependencies }) {
499
+ async function prepareWorkflowInsertStatements(options, { instanceId, workflowType, workflowName, workflowMetadata, input, workflowStatus, startTime, endTime, parentInstanceId, tenantId, triggerId, dependencies, delaySeconds, scheduledFor }) {
472
500
  const { data: inputData, externalRef: inputRef } = await serializeWithExternalStorage(input, options.serializer, options.externalBlobStorage);
473
501
  const insertWorkflowStatement = options.D1.prepare(`INSERT INTO WorkflowTable
474
- (instanceId, workflowType, workflowName, workflowMetadata, input, inputRef, tenantId, workflowStatus, startTime, endTime, parentInstanceId, triggerId)
475
- VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`).bind(instanceId, workflowType, workflowName, options.serializer.serialize(workflowMetadata), inputData, inputRef, tenantId, workflowStatus, startTime, endTime ?? null, parentInstanceId ?? null, triggerId ?? null);
502
+ (instanceId, workflowType, workflowName, workflowMetadata, input, inputRef, tenantId, workflowStatus, startTime, endTime, parentInstanceId, triggerId, delaySeconds, scheduledFor)
503
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`).bind(instanceId, workflowType, workflowName, options.serializer.serialize(workflowMetadata), inputData, inputRef, tenantId, workflowStatus, startTime, endTime ?? null, parentInstanceId ?? null, triggerId ?? null, delaySeconds ?? null, scheduledFor ?? null);
476
504
  if (!dependencies || dependencies.length === 0) return {
477
505
  statements: [insertWorkflowStatement],
478
506
  instanceId,
@@ -777,7 +805,9 @@ async function workflowTableRowToWorkflowRun({ row, serializer, externalBlobStor
777
805
  startTime: row.startTime,
778
806
  endTime: row.endTime,
779
807
  parentInstanceId: row.parentInstanceId,
780
- triggerId: row.triggerId
808
+ triggerId: row.triggerId,
809
+ delaySeconds: row.delaySeconds ?? null,
810
+ scheduledFor: row.scheduledFor ?? null
781
811
  };
782
812
  }
783
813
  async function updateWorkflowName(context, instanceId, newWorkflowName) {
@@ -840,6 +870,14 @@ async function updateWorkflow(context, instanceId, updates) {
840
870
  setClauses.push("triggerId = ?");
841
871
  bindings.push(updates.triggerId);
842
872
  }
873
+ if (updates.delaySeconds !== void 0) {
874
+ setClauses.push("delaySeconds = ?");
875
+ bindings.push(updates.delaySeconds);
876
+ }
877
+ if (updates.scheduledFor !== void 0) {
878
+ setClauses.push("scheduledFor = ?");
879
+ bindings.push(updates.scheduledFor);
880
+ }
843
881
  if (updates.workflowMetadata !== void 0) {
844
882
  setClauses.push("workflowMetadata = ?");
845
883
  bindings.push(context.serializer.serialize(updates.workflowMetadata));
@@ -1785,7 +1823,7 @@ function createQueueWorkflowContext(options) {
1785
1823
  };
1786
1824
  const idFactory = internalContext.idFactory;
1787
1825
  const enqueueWorkflow = async (params) => {
1788
- const { workflow, tenantId, input, initialName, dependencies, triggerId: providedTriggerId } = params;
1826
+ const { workflow, tenantId, input, initialName, dependencies, triggerId: providedTriggerId, delaySeconds } = params;
1789
1827
  const triggerId = providedTriggerId ?? idFactory();
1790
1828
  const instanceId = idFactory();
1791
1829
  const startTime = Date.now();
@@ -1801,9 +1839,12 @@ function createQueueWorkflowContext(options) {
1801
1839
  parentInstanceId: void 0,
1802
1840
  tenantId,
1803
1841
  triggerId,
1804
- dependencies
1842
+ dependencies,
1843
+ delaySeconds: delaySeconds ?? null,
1844
+ scheduledFor: null
1805
1845
  });
1806
1846
  else {
1847
+ const scheduledFor = delaySeconds != null ? startTime + delaySeconds * 1e3 : null;
1807
1848
  await insertWorkflowRecord(internalContext, {
1808
1849
  instanceId,
1809
1850
  workflowType: workflow.workflowType,
@@ -1815,7 +1856,9 @@ function createQueueWorkflowContext(options) {
1815
1856
  endTime: null,
1816
1857
  parentInstanceId: void 0,
1817
1858
  tenantId,
1818
- triggerId
1859
+ triggerId,
1860
+ delaySeconds: delaySeconds ?? null,
1861
+ scheduledFor
1819
1862
  });
1820
1863
  await options.QUEUE.send({
1821
1864
  type: "workflow-run",
@@ -1826,15 +1869,42 @@ function createQueueWorkflowContext(options) {
1826
1869
  triggerId,
1827
1870
  queueIdentifier: options.queueIdentifier,
1828
1871
  scheduledInstanceId: instanceId
1829
- });
1872
+ }, delaySeconds != null ? { delaySeconds } : void 0);
1830
1873
  }
1831
1874
  return {
1832
1875
  instanceId,
1833
1876
  workflowType: workflow.workflowType
1834
1877
  };
1835
1878
  };
1836
- const enqueueRetryWorkflow = async (workflow, tenantId, oldInstanceId, reuseSuccessfulSteps) => {
1879
+ const enqueueRetryWorkflow = async (workflow, tenantId, oldInstanceId, reuseSuccessfulSteps, delaySeconds) => {
1837
1880
  const triggerId = idFactory();
1881
+ const instanceId = idFactory();
1882
+ const startTime = Date.now();
1883
+ const scheduledFor = delaySeconds != null ? startTime + delaySeconds * 1e3 : null;
1884
+ const logAccessor = createLogAccessor({
1885
+ D1: options.D1,
1886
+ externalBlobStorage: options.externalBlobStorage,
1887
+ serializer: internalContext.serializer,
1888
+ tenantId,
1889
+ retryConfig: options.retryConfig
1890
+ });
1891
+ const oldRun = await logAccessor.getWorkflowShallow(oldInstanceId, { populateInput: true });
1892
+ if (!oldRun) throw new Error(`Cannot retry: no workflow found for instanceId ${oldInstanceId}`);
1893
+ await insertWorkflowRecord(internalContext, {
1894
+ instanceId,
1895
+ workflowType: workflow.workflowType,
1896
+ workflowName: oldRun.workflowName ?? "unknown",
1897
+ workflowMetadata: workflow.metadata,
1898
+ input: oldRun.input,
1899
+ workflowStatus: "scheduled",
1900
+ startTime,
1901
+ endTime: null,
1902
+ parentInstanceId: oldInstanceId,
1903
+ tenantId,
1904
+ triggerId,
1905
+ delaySeconds: delaySeconds ?? null,
1906
+ scheduledFor
1907
+ });
1838
1908
  await options.QUEUE.send({
1839
1909
  type: "workflow-retry",
1840
1910
  workflowType: workflow.workflowType,
@@ -1842,8 +1912,13 @@ function createQueueWorkflowContext(options) {
1842
1912
  tenantId,
1843
1913
  triggerId,
1844
1914
  reuseSuccessfulSteps: reuseSuccessfulSteps ?? true,
1845
- queueIdentifier: options.queueIdentifier
1846
- });
1915
+ queueIdentifier: options.queueIdentifier,
1916
+ scheduledInstanceId: instanceId
1917
+ }, delaySeconds != null ? { delaySeconds } : void 0);
1918
+ return {
1919
+ instanceId,
1920
+ workflowType: workflow.workflowType
1921
+ };
1847
1922
  };
1848
1923
  /**
1849
1924
  * Enqueue multiple workflows in a single batch operation.
@@ -1866,10 +1941,11 @@ function createQueueWorkflowContext(options) {
1866
1941
  if (workflows.length > 100) throw new Error(`enqueueWorkflowBatch: Cannot enqueue more than 100 workflows in a single batch (received ${workflows.length}). Split into smaller chunks.`);
1867
1942
  const startTime = Date.now();
1868
1943
  console.log(`enqueueWorkflowBatch: Starting batch of ${workflows.length} workflows`);
1869
- const preparedWorkflows = await Promise.all(workflows.map(async ({ workflow, tenantId, input, initialName, dependencies, triggerId: providedTriggerId }) => {
1944
+ const preparedWorkflows = await Promise.all(workflows.map(async ({ workflow, tenantId, input, initialName, dependencies, triggerId: providedTriggerId, delaySeconds }) => {
1870
1945
  const instanceId = idFactory();
1871
1946
  const triggerId = providedTriggerId ?? idFactory();
1872
1947
  const hasDependencies = dependencies && dependencies.length > 0;
1948
+ const scheduledFor = !hasDependencies && delaySeconds != null ? startTime + delaySeconds * 1e3 : null;
1873
1949
  const prepared = await prepareWorkflowInsertStatements(internalContext, {
1874
1950
  instanceId,
1875
1951
  workflowType: workflow.workflowType,
@@ -1882,14 +1958,17 @@ function createQueueWorkflowContext(options) {
1882
1958
  parentInstanceId: void 0,
1883
1959
  tenantId,
1884
1960
  triggerId,
1885
- dependencies
1961
+ dependencies,
1962
+ delaySeconds: delaySeconds ?? null,
1963
+ scheduledFor
1886
1964
  });
1887
1965
  return {
1888
1966
  ...prepared,
1889
1967
  tenantId,
1890
1968
  triggerId,
1891
1969
  initialName,
1892
- shouldQueue: !hasDependencies
1970
+ shouldQueue: !hasDependencies,
1971
+ delaySeconds
1893
1972
  };
1894
1973
  }));
1895
1974
  const workflowsWithDeps = preparedWorkflows.filter((p) => !p.shouldQueue).length;
@@ -1900,16 +1979,19 @@ function createQueueWorkflowContext(options) {
1900
1979
  console.log(`enqueueWorkflowBatch: Executing D1 batch with ${allStatements.length} statements`);
1901
1980
  await retryD1Operation(() => options.D1.batch(allStatements), options.retryConfig);
1902
1981
  }
1903
- const messagesToQueue = preparedWorkflows.filter((p) => p.shouldQueue).map((p) => ({ body: {
1904
- type: "workflow-run",
1905
- workflowType: p.workflowType,
1906
- workflowName: p.initialName,
1907
- input: workflows.find((w) => w.workflow.workflowType === p.workflowType && w.initialName === p.initialName)?.input,
1908
- tenantId: p.tenantId,
1909
- triggerId: p.triggerId,
1910
- queueIdentifier: options.queueIdentifier,
1911
- scheduledInstanceId: p.instanceId
1912
- } }));
1982
+ const messagesToQueue = preparedWorkflows.filter((p) => p.shouldQueue).map((p) => ({
1983
+ body: {
1984
+ type: "workflow-run",
1985
+ workflowType: p.workflowType,
1986
+ workflowName: p.initialName,
1987
+ input: workflows.find((w) => w.workflow.workflowType === p.workflowType && w.initialName === p.initialName)?.input,
1988
+ tenantId: p.tenantId,
1989
+ triggerId: p.triggerId,
1990
+ queueIdentifier: options.queueIdentifier,
1991
+ scheduledInstanceId: p.instanceId
1992
+ },
1993
+ ...p.delaySeconds != null ? { delaySeconds: p.delaySeconds } : {}
1994
+ }));
1913
1995
  if (messagesToQueue.length > 0) {
1914
1996
  console.log(`enqueueWorkflowBatch: Sending ${messagesToQueue.length} messages to queue`);
1915
1997
  await options.QUEUE.sendBatch(messagesToQueue);
@@ -1942,7 +2024,8 @@ function createQueueWorkflowContext(options) {
1942
2024
  workflow: workflowFunction,
1943
2025
  retryInstanceId: message.retryInstanceId,
1944
2026
  triggerId: message.triggerId,
1945
- retryOptions: { reuseSuccessfulSteps: message.reuseSuccessfulSteps ?? true }
2027
+ retryOptions: { reuseSuccessfulSteps: message.reuseSuccessfulSteps ?? true },
2028
+ scheduledInstanceId: message.scheduledInstanceId
1946
2029
  });
1947
2030
  }
1948
2031
  };
@@ -1968,7 +2051,12 @@ function createQueueWorkflowContext(options) {
1968
2051
  const allDepsFinished = dependencies.every((dep) => dep.workflow.workflowStatus === "completed" || dep.workflow.workflowStatus === "failed");
1969
2052
  if (allDepsFinished) {
1970
2053
  console.log(`Enqueuing waiting workflow ${wf.instanceId} as all dependencies are finished`);
1971
- await updateWorkflow(internalContext, wf.instanceId, { workflowStatus: "scheduled" });
2054
+ const now = Date.now();
2055
+ const scheduledFor = wf.delaySeconds != null ? now + wf.delaySeconds * 1e3 : null;
2056
+ await updateWorkflow(internalContext, wf.instanceId, {
2057
+ workflowStatus: "scheduled",
2058
+ scheduledFor
2059
+ });
1972
2060
  await options.QUEUE.send({
1973
2061
  type: "workflow-run",
1974
2062
  workflowType: wf.workflowType,
@@ -1978,7 +2066,7 @@ function createQueueWorkflowContext(options) {
1978
2066
  triggerId: wf.triggerId,
1979
2067
  queueIdentifier: options.queueIdentifier,
1980
2068
  scheduledInstanceId: wf.instanceId
1981
- });
2069
+ }, wf.delaySeconds != null ? { delaySeconds: wf.delaySeconds } : void 0);
1982
2070
  } else {
1983
2071
  const unfinishedDeps = dependencies.filter((dep) => dep.workflow.workflowStatus !== "completed" && dep.workflow.workflowStatus !== "failed");
1984
2072
  console.log(`Workflow ${wf.instanceId} is still waiting on dependencies. Unfinished dependencies: ${unfinishedDeps.map((d) => d.workflow.instanceId + ": " + d.workflow.workflowStatus).join(", ")}`);
@@ -2244,7 +2332,7 @@ function createWorkflowContext(options) {
2244
2332
  throw error;
2245
2333
  }
2246
2334
  };
2247
- const retry = async ({ workflow, retryInstanceId, triggerId, retryOptions }) => {
2335
+ const retry = async ({ workflow, retryInstanceId, triggerId, retryOptions, scheduledInstanceId }) => {
2248
2336
  if (!ensuredTables) {
2249
2337
  await ensureTables(options.D1, options.retryConfig);
2250
2338
  ensuredTables = true;
@@ -2264,7 +2352,8 @@ function createWorkflowContext(options) {
2264
2352
  parentInstanceId: retryInstanceId,
2265
2353
  reuseSuccessfulSteps: retryOptions?.reuseSuccessfulSteps,
2266
2354
  tenantId,
2267
- triggerId
2355
+ triggerId,
2356
+ scheduledInstanceId
2268
2357
  });
2269
2358
  };
2270
2359
  return {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@brandboostinggmbh/observable-workflows",
3
- "version": "0.21.1",
3
+ "version": "0.22.0",
4
4
  "description": "My awesome typescript library",
5
5
  "type": "module",
6
6
  "license": "MIT",