@brandboostinggmbh/observable-workflows 0.20.0-beta.4 → 0.20.0-beta.5
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 +9 -15
- package/dist/index.js +105 -98
- package/package.json +3 -3
package/dist/index.d.ts
CHANGED
|
@@ -14,14 +14,15 @@ declare function createStepContext(context: StepContextOptions): Promise<{
|
|
|
14
14
|
* This function is idempotent and can be safely run multiple times.
|
|
15
15
|
*
|
|
16
16
|
* @param db - D1Database instance
|
|
17
|
+
* @param retryConfig - Optional retry configuration for D1 operations
|
|
17
18
|
*/
|
|
18
|
-
declare function ensureTables(db: D1Database): Promise<void>;
|
|
19
|
+
declare function ensureTables(db: D1Database, retryConfig?: RetryConfig): Promise<void>;
|
|
19
20
|
//#endregion
|
|
20
21
|
//#region src/observableWorkflows/helperFunctions.d.ts
|
|
21
22
|
/**
|
|
22
23
|
* Configuration for retry behavior on D1 operations
|
|
23
24
|
*/
|
|
24
|
-
interface RetryConfig
|
|
25
|
+
interface RetryConfig {
|
|
25
26
|
/** Maximum number of retry attempts (default: 3) */
|
|
26
27
|
maxAttempts?: number;
|
|
27
28
|
/** Initial delay in milliseconds (default: 100) */
|
|
@@ -49,7 +50,7 @@ interface RetryConfig$1 {
|
|
|
49
50
|
* )
|
|
50
51
|
* ```
|
|
51
52
|
*/
|
|
52
|
-
declare function retryD1Operation<T>(operation: () => Promise<T>, config?: RetryConfig
|
|
53
|
+
declare function retryD1Operation<T>(operation: () => Promise<T>, config?: RetryConfig): Promise<T>;
|
|
53
54
|
declare function finalizeWorkflowRecord(options: InternalWorkflowContextOptions, {
|
|
54
55
|
workflowStatus,
|
|
55
56
|
endTime,
|
|
@@ -231,6 +232,7 @@ declare function workflowTableRowToWorkflowRun({
|
|
|
231
232
|
}): Promise<WorkflowRun>;
|
|
232
233
|
declare function updateWorkflowName(context: {
|
|
233
234
|
D1: D1Database;
|
|
235
|
+
retryConfig?: RetryConfig;
|
|
234
236
|
}, instanceId: string, newWorkflowName: string): Promise<D1Result<Record<string, unknown>>>;
|
|
235
237
|
/**
|
|
236
238
|
* Update workflow fields by instanceId. Only provided fields will be updated.
|
|
@@ -441,6 +443,8 @@ type StepContextOptions = {
|
|
|
441
443
|
reuseSuccessfulSteps?: boolean;
|
|
442
444
|
/** Optional external blob storage for large data that exceeds D1 size limits */
|
|
443
445
|
externalBlobStorage?: ExternalBlobStorage;
|
|
446
|
+
/** Optional retry configuration for D1 operations */
|
|
447
|
+
retryConfig?: RetryConfig;
|
|
444
448
|
};
|
|
445
449
|
type ConsoleWrapper = {
|
|
446
450
|
log: (message?: any, ...optionalParams: any[]) => void;
|
|
@@ -637,18 +641,6 @@ type ExternalBlobStorage = {
|
|
|
637
641
|
get: (id: string) => Promise<string>;
|
|
638
642
|
delete: (...keys: string[]) => Promise<number>;
|
|
639
643
|
};
|
|
640
|
-
type RetryConfig = {
|
|
641
|
-
/** Maximum number of retry attempts (default: 3) */
|
|
642
|
-
maxAttempts?: number;
|
|
643
|
-
/** Initial delay in milliseconds (default: 100) */
|
|
644
|
-
initialDelayMs?: number;
|
|
645
|
-
/** Maximum delay in milliseconds (default: 5000) */
|
|
646
|
-
maxDelayMs?: number;
|
|
647
|
-
/** Multiplier for exponential backoff (default: 2) */
|
|
648
|
-
backoffMultiplier?: number;
|
|
649
|
-
/** Whether to add jitter to delays (default: true) */
|
|
650
|
-
useJitter?: boolean;
|
|
651
|
-
};
|
|
652
644
|
type WorkflowContextOptions = {
|
|
653
645
|
D1: D1Database;
|
|
654
646
|
idFactory?: () => string;
|
|
@@ -774,6 +766,7 @@ declare const createCleanupManager: (context: {
|
|
|
774
766
|
tenantId: string;
|
|
775
767
|
serializer?: Serializer;
|
|
776
768
|
externalBlobStorage?: ExternalBlobStorage;
|
|
769
|
+
retryConfig?: RetryConfig;
|
|
777
770
|
}) => {
|
|
778
771
|
countAffectedWorkflows: (config: DeleteConfig, limit: number) => Promise<{
|
|
779
772
|
count: number;
|
|
@@ -820,6 +813,7 @@ declare const createLogAccessor: (context: {
|
|
|
820
813
|
tenantId: string;
|
|
821
814
|
serializer?: Serializer;
|
|
822
815
|
externalBlobStorage?: ExternalBlobStorage;
|
|
816
|
+
retryConfig?: RetryConfig;
|
|
823
817
|
}) => {
|
|
824
818
|
listSteps: {
|
|
825
819
|
(limit: number, offset: number, instanceId?: string): Promise<Step[]>;
|
package/dist/index.js
CHANGED
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
/**
|
|
3
3
|
* Detect the current schema version for each table
|
|
4
4
|
*/
|
|
5
|
-
async function detectSchemaVersion(db) {
|
|
6
|
-
const workflowTableInfo = await retryD1Operation(() => db.prepare(`SELECT sql FROM sqlite_master WHERE type='table' AND name='WorkflowTable'`).first());
|
|
5
|
+
async function detectSchemaVersion(db, retryConfig) {
|
|
6
|
+
const workflowTableInfo = await retryD1Operation(() => db.prepare(`SELECT sql FROM sqlite_master WHERE type='table' AND name='WorkflowTable'`).first(), retryConfig);
|
|
7
7
|
let workflowTable = "missing";
|
|
8
8
|
if (workflowTableInfo) {
|
|
9
9
|
const hasInputRef = workflowTableInfo.sql.includes("inputRef");
|
|
@@ -16,7 +16,7 @@ async function detectSchemaVersion(db) {
|
|
|
16
16
|
else if (!hasInputRef && inputHasNotNull) workflowTable = "v1";
|
|
17
17
|
else workflowTable = "v1";
|
|
18
18
|
}
|
|
19
|
-
const stepTableInfo = await retryD1Operation(() => db.prepare(`SELECT sql FROM sqlite_master WHERE type='table' AND name='StepTable'`).first());
|
|
19
|
+
const stepTableInfo = await retryD1Operation(() => db.prepare(`SELECT sql FROM sqlite_master WHERE type='table' AND name='StepTable'`).first(), retryConfig);
|
|
20
20
|
let stepTable = "missing";
|
|
21
21
|
if (stepTableInfo) {
|
|
22
22
|
const hasResultRef = stepTableInfo.sql.includes("resultRef");
|
|
@@ -26,7 +26,7 @@ async function detectSchemaVersion(db) {
|
|
|
26
26
|
else if (hasResultRef && hasErrorRef) stepTable = "v2";
|
|
27
27
|
else stepTable = "v1";
|
|
28
28
|
}
|
|
29
|
-
const logTableInfo = await retryD1Operation(() => db.prepare(`SELECT sql FROM sqlite_master WHERE type='table' AND name='LogTable'`).first());
|
|
29
|
+
const logTableInfo = await retryD1Operation(() => db.prepare(`SELECT sql FROM sqlite_master WHERE type='table' AND name='LogTable'`).first(), retryConfig);
|
|
30
30
|
let logTable = "missing";
|
|
31
31
|
if (logTableInfo) {
|
|
32
32
|
const hasStepTableCascadeFK = logTableInfo.sql.includes("FOREIGN KEY (instanceId, stepName) REFERENCES StepTable(instanceId, stepName) ON DELETE CASCADE");
|
|
@@ -34,7 +34,7 @@ async function detectSchemaVersion(db) {
|
|
|
34
34
|
if (hasStepTableCascadeFK && hasWorkflowTableFK) logTable = "v5";
|
|
35
35
|
else logTable = "v1";
|
|
36
36
|
}
|
|
37
|
-
const workflowPropertiesInfo = await retryD1Operation(() => db.prepare(`SELECT sql FROM sqlite_master WHERE type='table' AND name='WorkflowProperties'`).first());
|
|
37
|
+
const workflowPropertiesInfo = await retryD1Operation(() => db.prepare(`SELECT sql FROM sqlite_master WHERE type='table' AND name='WorkflowProperties'`).first(), retryConfig);
|
|
38
38
|
let workflowProperties = "missing";
|
|
39
39
|
if (workflowPropertiesInfo) workflowProperties = "v1";
|
|
40
40
|
const workflowDependenciesInfo = await db.prepare(`SELECT sql FROM sqlite_master WHERE type='table' AND name='WorkflowDependencies'`).first();
|
|
@@ -52,8 +52,8 @@ async function detectSchemaVersion(db) {
|
|
|
52
52
|
* Migrate WorkflowTable from V1 to V2 schema
|
|
53
53
|
* Adds inputRef column and makes input nullable
|
|
54
54
|
*/
|
|
55
|
-
async function migrateWorkflowTableV1ToV2(db) {
|
|
56
|
-
const workflowTableInfo = await retryD1Operation(() => db.prepare(`SELECT sql FROM sqlite_master WHERE type='table' AND name='WorkflowTable'`).first());
|
|
55
|
+
async function migrateWorkflowTableV1ToV2(db, retryConfig) {
|
|
56
|
+
const workflowTableInfo = await retryD1Operation(() => db.prepare(`SELECT sql FROM sqlite_master WHERE type='table' AND name='WorkflowTable'`).first(), retryConfig);
|
|
57
57
|
const hasInputRef = workflowTableInfo.sql.includes("inputRef");
|
|
58
58
|
const inputHasNotNull = workflowTableInfo.sql.includes("input TEXT NOT NULL");
|
|
59
59
|
if (!hasInputRef || inputHasNotNull) await retryD1Operation(() => db.batch([
|
|
@@ -78,14 +78,14 @@ async function migrateWorkflowTableV1ToV2(db) {
|
|
|
78
78
|
FROM WorkflowTable`),
|
|
79
79
|
db.prepare(`DROP TABLE WorkflowTable`),
|
|
80
80
|
db.prepare(`ALTER TABLE WorkflowTable_new RENAME TO WorkflowTable`)
|
|
81
|
-
]));
|
|
81
|
+
]), retryConfig);
|
|
82
82
|
}
|
|
83
83
|
/**
|
|
84
84
|
* Migrate WorkflowTable from V2/V3 to V4 schema
|
|
85
85
|
* Adds triggerId column with UNIQUE constraint
|
|
86
86
|
*/
|
|
87
|
-
async function migrateWorkflowTableV2V3ToV4(db) {
|
|
88
|
-
const workflowTableInfo = await retryD1Operation(() => db.prepare(`SELECT sql FROM sqlite_master WHERE type='table' AND name='WorkflowTable'`).first());
|
|
87
|
+
async function migrateWorkflowTableV2V3ToV4(db, retryConfig) {
|
|
88
|
+
const workflowTableInfo = await retryD1Operation(() => db.prepare(`SELECT sql FROM sqlite_master WHERE type='table' AND name='WorkflowTable'`).first(), retryConfig);
|
|
89
89
|
const hasTriggerId = workflowTableInfo.sql.includes("triggerId");
|
|
90
90
|
if (!hasTriggerId) await retryD1Operation(() => db.batch([
|
|
91
91
|
db.prepare(`CREATE TABLE WorkflowTable_new (
|
|
@@ -111,21 +111,21 @@ async function migrateWorkflowTableV2V3ToV4(db) {
|
|
|
111
111
|
FROM WorkflowTable`),
|
|
112
112
|
db.prepare(`DROP TABLE WorkflowTable`),
|
|
113
113
|
db.prepare(`ALTER TABLE WorkflowTable_new RENAME TO WorkflowTable`)
|
|
114
|
-
]));
|
|
114
|
+
]), retryConfig);
|
|
115
115
|
}
|
|
116
116
|
/**
|
|
117
117
|
* Migrate WorkflowTable from V4 to V6 schema
|
|
118
118
|
* Adds result and resultRef columns for external storage support
|
|
119
119
|
*/
|
|
120
|
-
async function migrateWorkflowTableV4ToV6(db) {
|
|
121
|
-
const workflowTableInfo = await db.prepare(`SELECT sql FROM sqlite_master WHERE type='table' AND name='WorkflowTable'`).first();
|
|
120
|
+
async function migrateWorkflowTableV4ToV6(db, retryConfig) {
|
|
121
|
+
const workflowTableInfo = await retryD1Operation(() => db.prepare(`SELECT sql FROM sqlite_master WHERE type='table' AND name='WorkflowTable'`).first(), retryConfig);
|
|
122
122
|
const hasResultRef = workflowTableInfo.sql.includes("resultRef");
|
|
123
|
-
if (!hasResultRef) await db.batch([db.prepare(`ALTER TABLE WorkflowTable ADD COLUMN result TEXT`), db.prepare(`ALTER TABLE WorkflowTable ADD COLUMN resultRef TEXT`)]);
|
|
123
|
+
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
124
|
}
|
|
125
125
|
/**
|
|
126
126
|
* Create or migrate WorkflowTable to the latest schema
|
|
127
127
|
*/
|
|
128
|
-
async function migrateWorkflowTable(db, currentVersion) {
|
|
128
|
+
async function migrateWorkflowTable(db, currentVersion, retryConfig) {
|
|
129
129
|
if (currentVersion === "missing") {
|
|
130
130
|
await retryD1Operation(() => db.prepare(`CREATE TABLE WorkflowTable (
|
|
131
131
|
instanceId TEXT NOT NULL,
|
|
@@ -144,29 +144,29 @@ async function migrateWorkflowTable(db, currentVersion) {
|
|
|
144
144
|
triggerId TEXT,
|
|
145
145
|
PRIMARY KEY (instanceId),
|
|
146
146
|
UNIQUE (triggerId)
|
|
147
|
-
)`).run());
|
|
147
|
+
)`).run(), retryConfig);
|
|
148
148
|
return;
|
|
149
149
|
}
|
|
150
150
|
if (currentVersion === "v1") {
|
|
151
|
-
await migrateWorkflowTableV1ToV2(db);
|
|
152
|
-
await migrateWorkflowTableV2V3ToV4(db);
|
|
153
|
-
await migrateWorkflowTableV4ToV6(db);
|
|
151
|
+
await migrateWorkflowTableV1ToV2(db, retryConfig);
|
|
152
|
+
await migrateWorkflowTableV2V3ToV4(db, retryConfig);
|
|
153
|
+
await migrateWorkflowTableV4ToV6(db, retryConfig);
|
|
154
154
|
return;
|
|
155
155
|
}
|
|
156
156
|
if (currentVersion === "v2") {
|
|
157
|
-
await migrateWorkflowTableV2V3ToV4(db);
|
|
158
|
-
await migrateWorkflowTableV4ToV6(db);
|
|
157
|
+
await migrateWorkflowTableV2V3ToV4(db, retryConfig);
|
|
158
|
+
await migrateWorkflowTableV4ToV6(db, retryConfig);
|
|
159
159
|
return;
|
|
160
160
|
}
|
|
161
161
|
if (currentVersion === "v4") {
|
|
162
|
-
await migrateWorkflowTableV4ToV6(db);
|
|
162
|
+
await migrateWorkflowTableV4ToV6(db, retryConfig);
|
|
163
163
|
return;
|
|
164
164
|
}
|
|
165
165
|
}
|
|
166
166
|
/**
|
|
167
167
|
* Create or migrate StepTable to the latest schema
|
|
168
168
|
*/
|
|
169
|
-
async function migrateStepTable(db, currentVersion) {
|
|
169
|
+
async function migrateStepTable(db, currentVersion, retryConfig) {
|
|
170
170
|
if (currentVersion === "missing") {
|
|
171
171
|
await retryD1Operation(() => db.prepare(`CREATE TABLE StepTable (
|
|
172
172
|
instanceId TEXT NOT NULL,
|
|
@@ -182,21 +182,21 @@ async function migrateStepTable(db, currentVersion) {
|
|
|
182
182
|
tenantId TEXT NOT NULL,
|
|
183
183
|
PRIMARY KEY (instanceId, stepName),
|
|
184
184
|
FOREIGN KEY (instanceId) REFERENCES WorkflowTable(instanceId) ON DELETE CASCADE
|
|
185
|
-
)`).run());
|
|
185
|
+
)`).run(), retryConfig);
|
|
186
186
|
return;
|
|
187
187
|
}
|
|
188
188
|
if (currentVersion === "v1") {
|
|
189
|
-
const stepTableInfo = await retryD1Operation(() => db.prepare(`SELECT sql FROM sqlite_master WHERE type='table' AND name='StepTable'`).first());
|
|
189
|
+
const stepTableInfo = await retryD1Operation(() => db.prepare(`SELECT sql FROM sqlite_master WHERE type='table' AND name='StepTable'`).first(), retryConfig);
|
|
190
190
|
const hasResultRef = stepTableInfo.sql.includes("resultRef");
|
|
191
191
|
const hasErrorRef = stepTableInfo.sql.includes("errorRef");
|
|
192
|
-
if (!hasResultRef) await retryD1Operation(() => db.prepare(`ALTER TABLE StepTable ADD COLUMN resultRef TEXT`).run());
|
|
193
|
-
if (!hasErrorRef) await retryD1Operation(() => db.prepare(`ALTER TABLE StepTable ADD COLUMN errorRef TEXT`).run());
|
|
192
|
+
if (!hasResultRef) await retryD1Operation(() => db.prepare(`ALTER TABLE StepTable ADD COLUMN resultRef TEXT`).run(), retryConfig);
|
|
193
|
+
if (!hasErrorRef) await retryD1Operation(() => db.prepare(`ALTER TABLE StepTable ADD COLUMN errorRef TEXT`).run(), retryConfig);
|
|
194
194
|
}
|
|
195
195
|
}
|
|
196
196
|
/**
|
|
197
197
|
* Create or migrate LogTable to the latest schema
|
|
198
198
|
*/
|
|
199
|
-
async function migrateLogTable(db, currentVersion) {
|
|
199
|
+
async function migrateLogTable(db, currentVersion, retryConfig) {
|
|
200
200
|
if (currentVersion === "missing") {
|
|
201
201
|
await retryD1Operation(() => db.prepare(`CREATE TABLE LogTable (
|
|
202
202
|
instanceId TEXT NOT NULL,
|
|
@@ -208,14 +208,14 @@ async function migrateLogTable(db, currentVersion) {
|
|
|
208
208
|
tenantId TEXT NOT NULL,
|
|
209
209
|
FOREIGN KEY (instanceId, stepName) REFERENCES StepTable(instanceId, stepName) ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED,
|
|
210
210
|
FOREIGN KEY (instanceId) REFERENCES WorkflowTable(instanceId) ON DELETE CASCADE
|
|
211
|
-
)`).run());
|
|
211
|
+
)`).run(), retryConfig);
|
|
212
212
|
return;
|
|
213
213
|
}
|
|
214
214
|
}
|
|
215
215
|
/**
|
|
216
216
|
* Create or migrate WorkflowProperties table to the latest schema
|
|
217
217
|
*/
|
|
218
|
-
async function migrateWorkflowPropertiesTable(db, currentVersion) {
|
|
218
|
+
async function migrateWorkflowPropertiesTable(db, currentVersion, retryConfig) {
|
|
219
219
|
if (currentVersion === "missing") {
|
|
220
220
|
await retryD1Operation(() => db.prepare(`CREATE TABLE WorkflowProperties (
|
|
221
221
|
instanceId TEXT NOT NULL,
|
|
@@ -226,16 +226,16 @@ async function migrateWorkflowPropertiesTable(db, currentVersion) {
|
|
|
226
226
|
PRIMARY KEY (instanceId, key),
|
|
227
227
|
FOREIGN KEY (instanceId) REFERENCES WorkflowTable(instanceId)
|
|
228
228
|
ON DELETE CASCADE
|
|
229
|
-
)`).run());
|
|
229
|
+
)`).run(), retryConfig);
|
|
230
230
|
return;
|
|
231
231
|
}
|
|
232
232
|
}
|
|
233
233
|
/**
|
|
234
234
|
* Create or migrate WorkflowDependencies table to the latest schema
|
|
235
235
|
*/
|
|
236
|
-
async function migrateWorkflowDependenciesTable(db, currentVersion) {
|
|
236
|
+
async function migrateWorkflowDependenciesTable(db, currentVersion, retryConfig) {
|
|
237
237
|
if (currentVersion === "missing") {
|
|
238
|
-
await db.prepare(`CREATE TABLE WorkflowDependencies (
|
|
238
|
+
await retryD1Operation(() => db.prepare(`CREATE TABLE WorkflowDependencies (
|
|
239
239
|
dependencyWorkflowId TEXT NOT NULL,
|
|
240
240
|
dependentWorkflowId TEXT NOT NULL,
|
|
241
241
|
tenantId TEXT NOT NULL,
|
|
@@ -243,15 +243,15 @@ async function migrateWorkflowDependenciesTable(db, currentVersion) {
|
|
|
243
243
|
PRIMARY KEY (dependencyWorkflowId, dependentWorkflowId),
|
|
244
244
|
FOREIGN KEY (dependencyWorkflowId) REFERENCES WorkflowTable(instanceId) ON DELETE CASCADE,
|
|
245
245
|
FOREIGN KEY (dependentWorkflowId) REFERENCES WorkflowTable(instanceId) ON DELETE CASCADE
|
|
246
|
-
)`).run();
|
|
246
|
+
)`).run(), retryConfig);
|
|
247
247
|
return;
|
|
248
248
|
}
|
|
249
249
|
}
|
|
250
250
|
/**
|
|
251
251
|
* Create necessary indexes
|
|
252
252
|
*/
|
|
253
|
-
async function createIndexes(db) {
|
|
254
|
-
const existingIndexes = await retryD1Operation(() => db.prepare(`SELECT name FROM sqlite_master WHERE type='index' AND name LIKE 'idx_%'`).all());
|
|
253
|
+
async function createIndexes(db, retryConfig) {
|
|
254
|
+
const existingIndexes = await retryD1Operation(() => db.prepare(`SELECT name FROM sqlite_master WHERE type='index' AND name LIKE 'idx_%'`).all(), retryConfig);
|
|
255
255
|
const existingIndexNames = new Set(existingIndexes.results?.map((row) => row.name) || []);
|
|
256
256
|
const indexes = [
|
|
257
257
|
{
|
|
@@ -341,23 +341,24 @@ async function createIndexes(db) {
|
|
|
341
341
|
];
|
|
342
342
|
const preparedStatements = [];
|
|
343
343
|
for (const index of indexes) if (!existingIndexNames.has(index.name)) preparedStatements.push(db.prepare(index.sql));
|
|
344
|
-
if (preparedStatements.length > 0) await retryD1Operation(() => db.batch(preparedStatements));
|
|
344
|
+
if (preparedStatements.length > 0) await retryD1Operation(() => db.batch(preparedStatements), retryConfig);
|
|
345
345
|
}
|
|
346
346
|
/**
|
|
347
347
|
* Main migration function that ensures all tables exist and are up-to-date.
|
|
348
348
|
* This function is idempotent and can be safely run multiple times.
|
|
349
349
|
*
|
|
350
350
|
* @param db - D1Database instance
|
|
351
|
+
* @param retryConfig - Optional retry configuration for D1 operations
|
|
351
352
|
*/
|
|
352
|
-
async function ensureTables(db) {
|
|
353
|
-
await retryD1Operation(() => db.prepare(`PRAGMA foreign_keys = ON`).run());
|
|
354
|
-
const schemaVersion = await detectSchemaVersion(db);
|
|
355
|
-
await migrateWorkflowTable(db, schemaVersion.workflowTable);
|
|
356
|
-
await migrateStepTable(db, schemaVersion.stepTable);
|
|
357
|
-
await migrateLogTable(db, schemaVersion.logTable);
|
|
358
|
-
await migrateWorkflowPropertiesTable(db, schemaVersion.workflowProperties);
|
|
359
|
-
await migrateWorkflowDependenciesTable(db, schemaVersion.workflowDependencies);
|
|
360
|
-
await createIndexes(db);
|
|
353
|
+
async function ensureTables(db, retryConfig) {
|
|
354
|
+
await retryD1Operation(() => db.prepare(`PRAGMA foreign_keys = ON`).run(), retryConfig);
|
|
355
|
+
const schemaVersion = await detectSchemaVersion(db, retryConfig);
|
|
356
|
+
await migrateWorkflowTable(db, schemaVersion.workflowTable, retryConfig);
|
|
357
|
+
await migrateStepTable(db, schemaVersion.stepTable, retryConfig);
|
|
358
|
+
await migrateLogTable(db, schemaVersion.logTable, retryConfig);
|
|
359
|
+
await migrateWorkflowPropertiesTable(db, schemaVersion.workflowProperties, retryConfig);
|
|
360
|
+
await migrateWorkflowDependenciesTable(db, schemaVersion.workflowDependencies, retryConfig);
|
|
361
|
+
await createIndexes(db, retryConfig);
|
|
361
362
|
}
|
|
362
363
|
|
|
363
364
|
//#endregion
|
|
@@ -397,12 +398,12 @@ function sleep(ms) {
|
|
|
397
398
|
}
|
|
398
399
|
/**
|
|
399
400
|
* Retry a D1 operation with exponential backoff for transient network errors
|
|
400
|
-
*
|
|
401
|
+
*
|
|
401
402
|
* @param operation - The async operation to retry
|
|
402
403
|
* @param config - Retry configuration options
|
|
403
404
|
* @returns The result of the operation
|
|
404
405
|
* @throws The last error if all retry attempts fail
|
|
405
|
-
*
|
|
406
|
+
*
|
|
406
407
|
* @example
|
|
407
408
|
* ```typescript
|
|
408
409
|
* const result = await retryD1Operation(
|
|
@@ -436,11 +437,11 @@ async function finalizeWorkflowRecord(options, { workflowStatus, endTime, instan
|
|
|
436
437
|
const { data: resultData, externalRef: resultRef } = await serializeWithExternalStorage(result, options.serializer, options.externalBlobStorage);
|
|
437
438
|
return retryD1Operation(() => options.D1.prepare(`UPDATE WorkflowTable
|
|
438
439
|
SET workflowStatus = ?, endTime = ?, result = ?, resultRef = ?
|
|
439
|
-
WHERE instanceId = ?`).bind(workflowStatus, endTime, resultData, resultRef, instanceId).run());
|
|
440
|
+
WHERE instanceId = ?`).bind(workflowStatus, endTime, resultData, resultRef, instanceId).run(), options.retryConfig);
|
|
440
441
|
}
|
|
441
442
|
return retryD1Operation(() => options.D1.prepare(`UPDATE WorkflowTable
|
|
442
443
|
SET workflowStatus = ?, endTime = ?
|
|
443
|
-
WHERE instanceId = ?`).bind(workflowStatus, endTime, instanceId).run());
|
|
444
|
+
WHERE instanceId = ?`).bind(workflowStatus, endTime, instanceId).run(), options.retryConfig);
|
|
444
445
|
}
|
|
445
446
|
/**
|
|
446
447
|
* Insert a new workflow record into the database.
|
|
@@ -471,7 +472,7 @@ async function insertWorkflowRecord(options, { instanceId, workflowType, workflo
|
|
|
471
472
|
(instanceId, workflowType, workflowName, workflowMetadata, input, inputRef, tenantId, workflowStatus, startTime, endTime, parentInstanceId, triggerId)
|
|
472
473
|
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`).bind(instanceId, workflowType, workflowName, options.serializer.serialize(workflowMetadata), inputData, inputRef, tenantId, workflowStatus, startTime, endTime ?? null, parentInstanceId ?? null, triggerId ?? null);
|
|
473
474
|
if (!dependencies || dependencies.length === 0) {
|
|
474
|
-
const result = await retryD1Operation(() => insertWorkflowStatement.run());
|
|
475
|
+
const result = await retryD1Operation(() => insertWorkflowStatement.run(), options.retryConfig);
|
|
475
476
|
return {
|
|
476
477
|
success: result.success,
|
|
477
478
|
meta: result.meta
|
|
@@ -485,7 +486,7 @@ async function insertWorkflowRecord(options, { instanceId, workflowType, workflo
|
|
|
485
486
|
tenantId,
|
|
486
487
|
createdAt
|
|
487
488
|
}));
|
|
488
|
-
const results = await retryD1Operation(() => options.D1.batch([insertWorkflowStatement, ...dependencyStatements]));
|
|
489
|
+
const results = await retryD1Operation(() => options.D1.batch([insertWorkflowStatement, ...dependencyStatements]), options.retryConfig);
|
|
489
490
|
const allSucceeded = results.every((result) => result.success);
|
|
490
491
|
return {
|
|
491
492
|
success: allSucceeded,
|
|
@@ -495,10 +496,10 @@ async function insertWorkflowRecord(options, { instanceId, workflowType, workflo
|
|
|
495
496
|
function insertStepRecordFull(context, { instanceId, name, status, metadata, startTime, endTime, result, error, resultRef, errorRef }) {
|
|
496
497
|
return retryD1Operation(() => context.D1.prepare(`INSERT INTO StepTable
|
|
497
498
|
(instanceId, stepName, stepStatus, stepMetadata, startTime, endTime, result, error, resultRef, errorRef, tenantId)
|
|
498
|
-
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`).bind(instanceId, name, status, metadata, startTime, endTime, result, error, resultRef ?? null, errorRef ?? null, context.tenantId).run());
|
|
499
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`).bind(instanceId, name, status, metadata, startTime, endTime, result, error, resultRef ?? null, errorRef ?? null, context.tenantId).run(), context.retryConfig);
|
|
499
500
|
}
|
|
500
501
|
async function getStepRecord(context, stepName, instanceId) {
|
|
501
|
-
const existingStep = await retryD1Operation(() => context.D1.prepare(`SELECT * FROM StepTable WHERE instanceId = ? AND stepName = ? AND tenantId = ?`).bind(instanceId, stepName, context.tenantId).first());
|
|
502
|
+
const existingStep = await retryD1Operation(() => context.D1.prepare(`SELECT * FROM StepTable WHERE instanceId = ? AND stepName = ? AND tenantId = ?`).bind(instanceId, stepName, context.tenantId).first(), context.retryConfig);
|
|
502
503
|
const row = existingStep;
|
|
503
504
|
if (row) {
|
|
504
505
|
const result = await deserializeWithExternalStorage(row.result, row.resultRef, context.serializer, context.externalBlobStorage);
|
|
@@ -574,7 +575,7 @@ function pushLogToDB(options, { instanceId, stepName, message, timestamp, type,
|
|
|
574
575
|
const truncatedMessage = truncateLogMessage(message);
|
|
575
576
|
return retryD1Operation(() => options.D1.prepare(`INSERT INTO LogTable
|
|
576
577
|
(instanceId, stepName, log, timestamp, type, logOrder, tenantId)
|
|
577
|
-
VALUES (?, ?, ?, ?, ?, ?, ?)`).bind(instanceId, stepName, truncatedMessage, timestamp, type, logOrder, tenantId).run());
|
|
578
|
+
VALUES (?, ?, ?, ?, ?, ?, ?)`).bind(instanceId, stepName, truncatedMessage, timestamp, type, logOrder, tenantId).run(), options.retryConfig);
|
|
578
579
|
}
|
|
579
580
|
var LogBatcher = class {
|
|
580
581
|
batch = [];
|
|
@@ -614,7 +615,7 @@ var LogBatcher = class {
|
|
|
614
615
|
(instanceId, stepName, log, timestamp, type, logOrder, tenantId)
|
|
615
616
|
VALUES (?, ?, ?, ?, ?, ?, ?)`).bind(entry.instanceId, entry.stepName, entry.message, entry.timestamp, entry.type, entry.logOrder, entry.tenantId));
|
|
616
617
|
return await this.options.D1.batch(statements);
|
|
617
|
-
});
|
|
618
|
+
}, this.options.retryConfig);
|
|
618
619
|
} catch (error) {
|
|
619
620
|
console.error("Batch log insert failed, falling back to individual inserts:", error);
|
|
620
621
|
await Promise.all(logsToFlush.map((entry) => pushLogToDB(this.options, entry)));
|
|
@@ -744,7 +745,7 @@ async function workflowTableRowToWorkflowRun({ row, serializer, externalBlobStor
|
|
|
744
745
|
async function updateWorkflowName(context, instanceId, newWorkflowName) {
|
|
745
746
|
return await retryD1Operation(() => context.D1.prepare(`UPDATE WorkflowTable
|
|
746
747
|
SET workflowName = ?
|
|
747
|
-
WHERE instanceId = ?`).bind(newWorkflowName, instanceId).run());
|
|
748
|
+
WHERE instanceId = ?`).bind(newWorkflowName, instanceId).run(), context.retryConfig);
|
|
748
749
|
}
|
|
749
750
|
/**
|
|
750
751
|
* Update workflow fields by instanceId. Only provided fields will be updated.
|
|
@@ -821,7 +822,7 @@ async function updateWorkflow(context, instanceId, updates) {
|
|
|
821
822
|
};
|
|
822
823
|
bindings.push(instanceId);
|
|
823
824
|
const sql = `UPDATE WorkflowTable SET ${setClauses.join(", ")} WHERE instanceId = ?`;
|
|
824
|
-
return await retryD1Operation(() => context.D1.prepare(sql).bind(...bindings).run());
|
|
825
|
+
return await retryD1Operation(() => context.D1.prepare(sql).bind(...bindings).run(), context.retryConfig);
|
|
825
826
|
}
|
|
826
827
|
/**
|
|
827
828
|
* Serialize a workflow property value for storage
|
|
@@ -856,7 +857,7 @@ async function upsertWorkflowProperty({ context, instanceId, key, value, tenantI
|
|
|
856
857
|
const { serializedValue, valueType } = serializeWorkflowPropertyValue(value);
|
|
857
858
|
const res = await retryD1Operation(() => context.D1.prepare(`INSERT OR REPLACE INTO WorkflowProperties
|
|
858
859
|
(instanceId, key, value, valueType, tenantId)
|
|
859
|
-
VALUES (?, ?, ?, ?, ?)`).bind(instanceId, key, serializedValue, valueType, tenantId).run());
|
|
860
|
+
VALUES (?, ?, ?, ?, ?)`).bind(instanceId, key, serializedValue, valueType, tenantId).run(), context.retryConfig);
|
|
860
861
|
if (res.error) {
|
|
861
862
|
console.error("Error inserting workflow property:", res.error);
|
|
862
863
|
return false;
|
|
@@ -917,7 +918,7 @@ async function createWorkflowDependency({ context, dependencyWorkflowId, depende
|
|
|
917
918
|
dependencyWorkflowId,
|
|
918
919
|
dependentWorkflowId,
|
|
919
920
|
tenantId
|
|
920
|
-
}).run());
|
|
921
|
+
}).run(), context.retryConfig);
|
|
921
922
|
}
|
|
922
923
|
/**
|
|
923
924
|
* Create multiple workflow dependencies in a single transaction.
|
|
@@ -950,7 +951,7 @@ async function createWorkflowDependencies({ context, dependencies, tenantId }) {
|
|
|
950
951
|
tenantId,
|
|
951
952
|
createdAt
|
|
952
953
|
}));
|
|
953
|
-
return await retryD1Operation(() => context.D1.batch(statements));
|
|
954
|
+
return await retryD1Operation(() => context.D1.batch(statements), context.retryConfig);
|
|
954
955
|
}
|
|
955
956
|
/**
|
|
956
957
|
* Delete a specific workflow dependency relationship.
|
|
@@ -968,7 +969,7 @@ async function createWorkflowDependencies({ context, dependencies, tenantId }) {
|
|
|
968
969
|
*/
|
|
969
970
|
async function deleteWorkflowDependency({ context, dependencyWorkflowId, dependentWorkflowId, tenantId }) {
|
|
970
971
|
return await retryD1Operation(() => context.D1.prepare(`DELETE FROM WorkflowDependencies
|
|
971
|
-
WHERE dependencyWorkflowId = ? AND dependentWorkflowId = ? AND tenantId = ?`).bind(dependencyWorkflowId, dependentWorkflowId, tenantId).run());
|
|
972
|
+
WHERE dependencyWorkflowId = ? AND dependentWorkflowId = ? AND tenantId = ?`).bind(dependencyWorkflowId, dependentWorkflowId, tenantId).run(), context.retryConfig);
|
|
972
973
|
}
|
|
973
974
|
|
|
974
975
|
//#endregion
|
|
@@ -996,7 +997,7 @@ const createCleanupManager = (context) => {
|
|
|
996
997
|
AND workflowStatus IN (${statusPlaceholders})
|
|
997
998
|
ORDER BY instanceId
|
|
998
999
|
LIMIT ?
|
|
999
|
-
`).bind(context.tenantId, config.deleteWorkflowsOlderThanDays, ...statuses, limit).all());
|
|
1000
|
+
`).bind(context.tenantId, config.deleteWorkflowsOlderThanDays, ...statuses, limit).all(), context.retryConfig);
|
|
1000
1001
|
return result.results;
|
|
1001
1002
|
};
|
|
1002
1003
|
const getAffectedSteps = async (config, limit) => {
|
|
@@ -1015,7 +1016,7 @@ const createCleanupManager = (context) => {
|
|
|
1015
1016
|
LIMIT ?
|
|
1016
1017
|
)
|
|
1017
1018
|
ORDER BY s.instanceId, s.stepName
|
|
1018
|
-
`).bind(context.tenantId, config.deleteWorkflowsOlderThanDays, ...statuses, limit).all());
|
|
1019
|
+
`).bind(context.tenantId, config.deleteWorkflowsOlderThanDays, ...statuses, limit).all(), context.retryConfig);
|
|
1019
1020
|
return result.results;
|
|
1020
1021
|
};
|
|
1021
1022
|
const collectExternalStorageKeys = (workflows, steps) => {
|
|
@@ -1068,7 +1069,7 @@ const createCleanupManager = (context) => {
|
|
|
1068
1069
|
}
|
|
1069
1070
|
if (deletedWorkflows.length > 0) {
|
|
1070
1071
|
console.log(`Proceeding to delete workflows from the database...`);
|
|
1071
|
-
await retryD1Operation(() => context.D1.prepare(`PRAGMA foreign_keys = ON`).run());
|
|
1072
|
+
await retryD1Operation(() => context.D1.prepare(`PRAGMA foreign_keys = ON`).run(), context.retryConfig);
|
|
1072
1073
|
let totalDeletedCount = 0;
|
|
1073
1074
|
for (let i = 0; i < deletedWorkflows.length; i += 100) {
|
|
1074
1075
|
const batch = deletedWorkflows.slice(i, i + 100);
|
|
@@ -1076,7 +1077,7 @@ const createCleanupManager = (context) => {
|
|
|
1076
1077
|
const result = await retryD1Operation(() => context.D1.prepare(`
|
|
1077
1078
|
DELETE FROM WorkflowTable
|
|
1078
1079
|
WHERE instanceId IN (${workflowIds})
|
|
1079
|
-
`).bind(...batch.map((w) => w.instanceId)).run());
|
|
1080
|
+
`).bind(...batch.map((w) => w.instanceId)).run(), context.retryConfig);
|
|
1080
1081
|
totalDeletedCount += result.meta.changes || 0;
|
|
1081
1082
|
}
|
|
1082
1083
|
return {
|
|
@@ -1092,7 +1093,7 @@ const createCleanupManager = (context) => {
|
|
|
1092
1093
|
};
|
|
1093
1094
|
};
|
|
1094
1095
|
const cleanupOrphanedSteps = async (config, limit) => {
|
|
1095
|
-
await retryD1Operation(() => context.D1.prepare(`PRAGMA foreign_keys = ON`).run());
|
|
1096
|
+
await retryD1Operation(() => context.D1.prepare(`PRAGMA foreign_keys = ON`).run(), context.retryConfig);
|
|
1096
1097
|
const orphanedSteps = await retryD1Operation(() => context.D1.prepare(`
|
|
1097
1098
|
SELECT s.instanceId, s.stepName, s.errorRef, s.resultRef
|
|
1098
1099
|
FROM StepTable s
|
|
@@ -1103,7 +1104,7 @@ const createCleanupManager = (context) => {
|
|
|
1103
1104
|
)
|
|
1104
1105
|
ORDER BY s.instanceId, s.stepName
|
|
1105
1106
|
LIMIT ?
|
|
1106
|
-
`).bind(context.tenantId, context.tenantId, limit).all());
|
|
1107
|
+
`).bind(context.tenantId, context.tenantId, limit).all(), context.retryConfig);
|
|
1107
1108
|
const orphanedStepResults = orphanedSteps.results;
|
|
1108
1109
|
let deletedExternalStorageKeysCount = 0;
|
|
1109
1110
|
if (config.deleteRefsFromExternalStorage && context.externalBlobStorage && orphanedStepResults.length > 0) {
|
|
@@ -1123,7 +1124,7 @@ const createCleanupManager = (context) => {
|
|
|
1123
1124
|
DELETE FROM StepTable
|
|
1124
1125
|
WHERE tenantId = ?
|
|
1125
1126
|
AND instanceId IN (${instanceIds})
|
|
1126
|
-
`).bind(context.tenantId, ...batch.map((s) => s.instanceId)).run());
|
|
1127
|
+
`).bind(context.tenantId, ...batch.map((s) => s.instanceId)).run(), context.retryConfig);
|
|
1127
1128
|
totalDeletedSteps += deletedStepsResult.meta.changes || 0;
|
|
1128
1129
|
}
|
|
1129
1130
|
return {
|
|
@@ -1139,7 +1140,7 @@ const createCleanupManager = (context) => {
|
|
|
1139
1140
|
};
|
|
1140
1141
|
};
|
|
1141
1142
|
const cleanupOrphanedLogs = async (limit) => {
|
|
1142
|
-
await retryD1Operation(() => context.D1.prepare(`PRAGMA foreign_keys = ON`).run());
|
|
1143
|
+
await retryD1Operation(() => context.D1.prepare(`PRAGMA foreign_keys = ON`).run(), context.retryConfig);
|
|
1143
1144
|
const deletedLogsResult = await retryD1Operation(() => context.D1.prepare(`
|
|
1144
1145
|
DELETE FROM LogTable
|
|
1145
1146
|
WHERE tenantId = ?
|
|
@@ -1155,7 +1156,7 @@ const createCleanupManager = (context) => {
|
|
|
1155
1156
|
))
|
|
1156
1157
|
)
|
|
1157
1158
|
LIMIT ?
|
|
1158
|
-
`).bind(context.tenantId, context.tenantId, context.tenantId, limit).run());
|
|
1159
|
+
`).bind(context.tenantId, context.tenantId, context.tenantId, limit).run(), context.retryConfig);
|
|
1159
1160
|
return { deletedOrphanedLogs: deletedLogsResult.meta.changes || 0 };
|
|
1160
1161
|
};
|
|
1161
1162
|
return {
|
|
@@ -1343,7 +1344,7 @@ const createLogAccessor = (context) => {
|
|
|
1343
1344
|
const limitClause = limit !== void 0 && actualOffset !== void 0 ? "LIMIT ? OFFSET ?" : "";
|
|
1344
1345
|
const sql = `SELECT * FROM StepTable ${whereClause} ORDER BY startTime ASC ${limitClause}`;
|
|
1345
1346
|
if (limit !== void 0 && actualOffset !== void 0) bindings.push(limit, actualOffset);
|
|
1346
|
-
result = await retryD1Operation(() => context.D1.prepare(sql).bind(...bindings).all());
|
|
1347
|
+
result = await retryD1Operation(() => context.D1.prepare(sql).bind(...bindings).all(), context.retryConfig);
|
|
1347
1348
|
if (result.results) {
|
|
1348
1349
|
const steps = await Promise.all(result.results.map(async (row) => {
|
|
1349
1350
|
let deserializedResult = null;
|
|
@@ -1370,7 +1371,7 @@ const createLogAccessor = (context) => {
|
|
|
1370
1371
|
const listWorkflows = async (limit, offset, filter, options) => {
|
|
1371
1372
|
const { sql, bindings } = buildFilteredWorkflowQuery(filter, { ignoreTenant: options?.ignoreTenant });
|
|
1372
1373
|
if (options?.debugLogs) console.log("listWorkflows SQL:", sql, "Bindings:", JSON.stringify(bindings));
|
|
1373
|
-
const result = await retryD1Operation(() => context.D1.prepare(sql).bind(...bindings, limit, offset).all());
|
|
1374
|
+
const result = await retryD1Operation(() => context.D1.prepare(sql).bind(...bindings, limit, offset).all(), context.retryConfig);
|
|
1374
1375
|
if (options?.debugLogs) console.log("listWorkflows SQL Query executed");
|
|
1375
1376
|
if (result.results) {
|
|
1376
1377
|
const workflows = await Promise.all(result.results.map((row) => workflowTableRowToWorkflowRun({
|
|
@@ -1387,7 +1388,7 @@ const createLogAccessor = (context) => {
|
|
|
1387
1388
|
for (let i = 0; i < instanceIds.length; i += BATCH_SIZE) {
|
|
1388
1389
|
const batchIds = instanceIds.slice(i, i + BATCH_SIZE);
|
|
1389
1390
|
const placeholders = batchIds.map(() => "?").join(", ");
|
|
1390
|
-
const propertiesResult = await retryD1Operation(() => context.D1.prepare(`SELECT * FROM WorkflowProperties WHERE instanceId IN (${placeholders})`).bind(...batchIds).all());
|
|
1391
|
+
const propertiesResult = await retryD1Operation(() => context.D1.prepare(`SELECT * FROM WorkflowProperties WHERE instanceId IN (${placeholders})`).bind(...batchIds).all(), context.retryConfig);
|
|
1391
1392
|
if (propertiesResult.results) for (const row of propertiesResult.results) {
|
|
1392
1393
|
const property = {
|
|
1393
1394
|
key: row.key,
|
|
@@ -1411,7 +1412,7 @@ const createLogAccessor = (context) => {
|
|
|
1411
1412
|
const dependenciesResult = await retryD1Operation(() => context.D1.prepare(`SELECT w.*, wd.createdAt, wd.dependentWorkflowId
|
|
1412
1413
|
FROM WorkflowDependencies wd
|
|
1413
1414
|
JOIN WorkflowTable w ON wd.dependencyWorkflowId = w.instanceId
|
|
1414
|
-
WHERE wd.dependentWorkflowId IN (${placeholders})`).bind(...batchIds).all());
|
|
1415
|
+
WHERE wd.dependentWorkflowId IN (${placeholders})`).bind(...batchIds).all(), context.retryConfig);
|
|
1415
1416
|
if (dependenciesResult.results) for (const row of dependenciesResult.results) {
|
|
1416
1417
|
const depWorkflow = await workflowTableRowToWorkflowRun({
|
|
1417
1418
|
row,
|
|
@@ -1441,7 +1442,7 @@ const createLogAccessor = (context) => {
|
|
|
1441
1442
|
const dependentsResult = await retryD1Operation(() => context.D1.prepare(`SELECT w.*, wd.createdAt, wd.dependencyWorkflowId
|
|
1442
1443
|
FROM WorkflowDependencies wd
|
|
1443
1444
|
JOIN WorkflowTable w ON wd.dependentWorkflowId = w.instanceId
|
|
1444
|
-
WHERE wd.dependencyWorkflowId IN (${placeholders})`).bind(...batchIds).all());
|
|
1445
|
+
WHERE wd.dependencyWorkflowId IN (${placeholders})`).bind(...batchIds).all(), context.retryConfig);
|
|
1445
1446
|
if (dependentsResult.results) for (const row of dependentsResult.results) {
|
|
1446
1447
|
const depWorkflow = await workflowTableRowToWorkflowRun({
|
|
1447
1448
|
row,
|
|
@@ -1466,7 +1467,7 @@ const createLogAccessor = (context) => {
|
|
|
1466
1467
|
return [];
|
|
1467
1468
|
};
|
|
1468
1469
|
const getWorkflowByParentId = async (parentInstanceId) => {
|
|
1469
|
-
const result = await retryD1Operation(() => context.D1.prepare(`SELECT * FROM WorkflowTable WHERE parentInstanceId = ? AND tenantId = ?`).bind(parentInstanceId, context.tenantId).all());
|
|
1470
|
+
const result = await retryD1Operation(() => context.D1.prepare(`SELECT * FROM WorkflowTable WHERE parentInstanceId = ? AND tenantId = ?`).bind(parentInstanceId, context.tenantId).all(), context.retryConfig);
|
|
1470
1471
|
if (result.results) {
|
|
1471
1472
|
const workflows = await Promise.all(result.results.map((row) => workflowTableRowToWorkflowRun({
|
|
1472
1473
|
row,
|
|
@@ -1478,7 +1479,7 @@ const createLogAccessor = (context) => {
|
|
|
1478
1479
|
return null;
|
|
1479
1480
|
};
|
|
1480
1481
|
const getWorkflowByTriggerId = async (triggerId) => {
|
|
1481
|
-
const result = await retryD1Operation(() => context.D1.prepare(`SELECT * FROM WorkflowTable WHERE triggerId = ? AND tenantId = ?`).bind(triggerId, context.tenantId).first());
|
|
1482
|
+
const result = await retryD1Operation(() => context.D1.prepare(`SELECT * FROM WorkflowTable WHERE triggerId = ? AND tenantId = ?`).bind(triggerId, context.tenantId).first(), context.retryConfig);
|
|
1482
1483
|
if (result) {
|
|
1483
1484
|
const workflow = await workflowTableRowToWorkflowRun({
|
|
1484
1485
|
row: result,
|
|
@@ -1490,12 +1491,12 @@ const createLogAccessor = (context) => {
|
|
|
1490
1491
|
return null;
|
|
1491
1492
|
};
|
|
1492
1493
|
const getWorkflowTypesByTenantId = async (tenantId) => {
|
|
1493
|
-
const result = await retryD1Operation(() => context.D1.prepare(`SELECT DISTINCT workflowType FROM WorkflowTable WHERE tenantId = ?`).bind(tenantId).all());
|
|
1494
|
+
const result = await retryD1Operation(() => context.D1.prepare(`SELECT DISTINCT workflowType FROM WorkflowTable WHERE tenantId = ?`).bind(tenantId).all(), context.retryConfig);
|
|
1494
1495
|
if (!result.results) return [];
|
|
1495
1496
|
return result.results.map((row) => row.workflowType);
|
|
1496
1497
|
};
|
|
1497
1498
|
const getWorkflowProperties = async (instanceId) => {
|
|
1498
|
-
const result = await retryD1Operation(() => context.D1.prepare(`SELECT * FROM WorkflowProperties WHERE instanceId = ?`).bind(instanceId).all());
|
|
1499
|
+
const result = await retryD1Operation(() => context.D1.prepare(`SELECT * FROM WorkflowProperties WHERE instanceId = ?`).bind(instanceId).all(), context.retryConfig);
|
|
1499
1500
|
if (!result.results) return [];
|
|
1500
1501
|
return result.results.map((row) => ({
|
|
1501
1502
|
key: row.key,
|
|
@@ -1505,7 +1506,7 @@ const createLogAccessor = (context) => {
|
|
|
1505
1506
|
};
|
|
1506
1507
|
/** This function gets the basic data of a workflow, without populating any of it's complex fields */
|
|
1507
1508
|
const getWorkflowShallow = async (instanceId, options) => {
|
|
1508
|
-
const result = await retryD1Operation(() => context.D1.prepare(`SELECT * FROM WorkflowTable WHERE instanceId = ? AND tenantId = ?`).bind(instanceId, context.tenantId).first());
|
|
1509
|
+
const result = await retryD1Operation(() => context.D1.prepare(`SELECT * FROM WorkflowTable WHERE instanceId = ? AND tenantId = ?`).bind(instanceId, context.tenantId).first(), context.retryConfig);
|
|
1509
1510
|
if (!result) return null;
|
|
1510
1511
|
const workflow = await workflowTableRowToWorkflowRun({
|
|
1511
1512
|
row: result,
|
|
@@ -1536,7 +1537,7 @@ const createLogAccessor = (context) => {
|
|
|
1536
1537
|
retryWorkflow.isRetryOf = workflow;
|
|
1537
1538
|
});
|
|
1538
1539
|
workflow.isRetryOf = parentWorkflow;
|
|
1539
|
-
const allLogs = await retryD1Operation(() => context.D1.prepare(`SELECT * FROM LogTable WHERE instanceId = ? ORDER BY timestamp ASC, logOrder ASC`).bind(instanceId).all());
|
|
1540
|
+
const allLogs = await retryD1Operation(() => context.D1.prepare(`SELECT * FROM LogTable WHERE instanceId = ? ORDER BY timestamp ASC, logOrder ASC`).bind(instanceId).all(), context.retryConfig);
|
|
1540
1541
|
const logs = allLogs.results?.map((logRow) => ({
|
|
1541
1542
|
instanceId: logRow.instanceId,
|
|
1542
1543
|
stepName: logRow.stepName,
|
|
@@ -1555,7 +1556,7 @@ const createLogAccessor = (context) => {
|
|
|
1555
1556
|
const dependenciesResult = await retryD1Operation(() => context.D1.prepare(`SELECT w.*, wd.createdAt
|
|
1556
1557
|
FROM WorkflowDependencies wd
|
|
1557
1558
|
JOIN WorkflowTable w ON wd.dependencyWorkflowId = w.instanceId
|
|
1558
|
-
WHERE wd.dependentWorkflowId = ? AND wd.tenantId = ?`).bind(instanceId, context.tenantId).all());
|
|
1559
|
+
WHERE wd.dependentWorkflowId = ? AND wd.tenantId = ?`).bind(instanceId, context.tenantId).all(), context.retryConfig);
|
|
1559
1560
|
if (dependenciesResult.results) workflow.dependencies = await Promise.all(dependenciesResult.results.map(async (row) => {
|
|
1560
1561
|
const depWorkflow = await workflowTableRowToWorkflowRun({
|
|
1561
1562
|
row,
|
|
@@ -1574,7 +1575,7 @@ const createLogAccessor = (context) => {
|
|
|
1574
1575
|
const dependentsResult = await retryD1Operation(() => context.D1.prepare(`SELECT w.*, wd.createdAt
|
|
1575
1576
|
FROM WorkflowDependencies wd
|
|
1576
1577
|
JOIN WorkflowTable w ON wd.dependentWorkflowId = w.instanceId
|
|
1577
|
-
WHERE wd.dependencyWorkflowId = ? AND wd.tenantId = ?`).bind(instanceId, context.tenantId).all());
|
|
1578
|
+
WHERE wd.dependencyWorkflowId = ? AND wd.tenantId = ?`).bind(instanceId, context.tenantId).all(), context.retryConfig);
|
|
1578
1579
|
if (dependentsResult.results) workflow.dependents = await Promise.all(dependentsResult.results.map(async (row) => {
|
|
1579
1580
|
const depWorkflow = await workflowTableRowToWorkflowRun({
|
|
1580
1581
|
row,
|
|
@@ -1592,7 +1593,7 @@ const createLogAccessor = (context) => {
|
|
|
1592
1593
|
return workflow;
|
|
1593
1594
|
};
|
|
1594
1595
|
const getStep = async (instanceId, stepName) => {
|
|
1595
|
-
const result = await retryD1Operation(() => context.D1.prepare(`SELECT * FROM StepTable WHERE instanceId = ? AND stepName = ? AND tenantId = ?`).bind(instanceId, stepName, context.tenantId).all());
|
|
1596
|
+
const result = await retryD1Operation(() => context.D1.prepare(`SELECT * FROM StepTable WHERE instanceId = ? AND stepName = ? AND tenantId = ?`).bind(instanceId, stepName, context.tenantId).all(), context.retryConfig);
|
|
1596
1597
|
if (!result.results || result.results.length === 0) return null;
|
|
1597
1598
|
const row = result.results[0];
|
|
1598
1599
|
if (!row) return null;
|
|
@@ -1609,7 +1610,7 @@ const createLogAccessor = (context) => {
|
|
|
1609
1610
|
error: deserializedError,
|
|
1610
1611
|
logs: []
|
|
1611
1612
|
};
|
|
1612
|
-
const logResult = await retryD1Operation(() => context.D1.prepare(`SELECT * FROM LogTable WHERE instanceId = ? AND stepName = ? ORDER BY logOrder ASC`).bind(instanceId, stepName).all());
|
|
1613
|
+
const logResult = await retryD1Operation(() => context.D1.prepare(`SELECT * FROM LogTable WHERE instanceId = ? AND stepName = ? ORDER BY logOrder ASC`).bind(instanceId, stepName).all(), context.retryConfig);
|
|
1613
1614
|
if (logResult.results) step.logs = logResult.results.map((logRow) => ({
|
|
1614
1615
|
instanceId: logRow.instanceId,
|
|
1615
1616
|
stepName: logRow.stepName,
|
|
@@ -1623,7 +1624,7 @@ const createLogAccessor = (context) => {
|
|
|
1623
1624
|
const result = await retryD1Operation(() => context.D1.prepare(`
|
|
1624
1625
|
SELECT DISTINCT key, valueType FROM WorkflowProperties
|
|
1625
1626
|
WHERE tenantId = ? AND (? IS NULL OR instanceId = ?)
|
|
1626
|
-
`).bind(context.tenantId, instanceId ?? null, instanceId ?? null).all());
|
|
1627
|
+
`).bind(context.tenantId, instanceId ?? null, instanceId ?? null).all(), context.retryConfig);
|
|
1627
1628
|
console.log(`debug getPropertiesKeys: ${JSON.stringify(result)}`);
|
|
1628
1629
|
if (!result.results) return [];
|
|
1629
1630
|
return result.results.map((row) => ({
|
|
@@ -1689,7 +1690,7 @@ const createLogAccessor = (context) => {
|
|
|
1689
1690
|
${whereClause}
|
|
1690
1691
|
GROUP BY workflowType
|
|
1691
1692
|
ORDER BY workflowCount DESC
|
|
1692
|
-
`).bind(...bindings).all());
|
|
1693
|
+
`).bind(...bindings).all(), context.retryConfig);
|
|
1693
1694
|
if (!result.results) return [];
|
|
1694
1695
|
return result.results.map((row) => ({
|
|
1695
1696
|
workflowType: row.workflowType,
|
|
@@ -1877,7 +1878,8 @@ function createQueueWorkflowContext(options) {
|
|
|
1877
1878
|
D1: options.D1,
|
|
1878
1879
|
externalBlobStorage: options.externalBlobStorage,
|
|
1879
1880
|
serializer: internalContext.serializer,
|
|
1880
|
-
tenantId: "unknown"
|
|
1881
|
+
tenantId: "unknown",
|
|
1882
|
+
retryConfig: options.retryConfig
|
|
1881
1883
|
});
|
|
1882
1884
|
const waitingWorkflows = await logAccessor.listWorkflows(250, 0, { workflowStatus: "waiting" }, {
|
|
1883
1885
|
ignoreTenant: true,
|
|
@@ -1924,7 +1926,7 @@ function createQueueWorkflowContext(options) {
|
|
|
1924
1926
|
async function createStepContext(context) {
|
|
1925
1927
|
const instanceId = context.instanceId;
|
|
1926
1928
|
const reuseSuccessfulSteps = context.reuseSuccessfulSteps ?? true;
|
|
1927
|
-
await ensureTables(context.D1);
|
|
1929
|
+
await ensureTables(context.D1, context.retryConfig);
|
|
1928
1930
|
const step = async (step$1, callback) => {
|
|
1929
1931
|
const stepNameParam = typeof step$1 === "string" ? step$1 : step$1.name;
|
|
1930
1932
|
const stepMetadataParam = typeof step$1 === "string" ? void 0 : step$1.metadata;
|
|
@@ -2004,7 +2006,7 @@ async function createStepContext(context) {
|
|
|
2004
2006
|
const stepError$1 = null;
|
|
2005
2007
|
await retryD1Operation(() => context.D1.prepare(`UPDATE StepTable
|
|
2006
2008
|
SET stepStatus = ?, endTime = ?, result = ?, error = ?, resultRef = ?, errorRef = ?
|
|
2007
|
-
WHERE instanceId = ? AND stepName = ?`).bind(stepStatus$1, endTime, resultData, stepError$1, resultRef, null, instanceId, stepName).run());
|
|
2009
|
+
WHERE instanceId = ? AND stepName = ?`).bind(stepStatus$1, endTime, resultData, stepError$1, resultRef, null, instanceId, stepName).run(), context.retryConfig);
|
|
2008
2010
|
await logBatcher.destroy();
|
|
2009
2011
|
return result;
|
|
2010
2012
|
} catch (error) {
|
|
@@ -2014,7 +2016,7 @@ async function createStepContext(context) {
|
|
|
2014
2016
|
const { data: errorData, externalRef: errorRef } = await serializeWithExternalStorage(error, context.serializer, context.externalBlobStorage);
|
|
2015
2017
|
await retryD1Operation(() => context.D1.prepare(`UPDATE StepTable
|
|
2016
2018
|
SET stepStatus = ?, endTime = ?, result = ?, error = ?, resultRef = ?, errorRef = ?
|
|
2017
|
-
WHERE instanceId = ? AND stepName = ?`).bind(stepStatus$1, endTime, stepResult$1, errorData, null, errorRef, instanceId, stepName).run());
|
|
2019
|
+
WHERE instanceId = ? AND stepName = ?`).bind(stepStatus$1, endTime, stepResult$1, errorData, null, errorRef, instanceId, stepName).run(), context.retryConfig);
|
|
2018
2020
|
await logBatcher.destroy();
|
|
2019
2021
|
throw error;
|
|
2020
2022
|
}
|
|
@@ -2033,14 +2035,15 @@ function createWorkflowContext(options) {
|
|
|
2033
2035
|
};
|
|
2034
2036
|
const call = async ({ workflow, input, workflowName, tenantId, parentInstanceId, reuseSuccessfulSteps, triggerId, scheduledInstanceId }) => {
|
|
2035
2037
|
if (!ensuredTables) {
|
|
2036
|
-
await ensureTables(options.D1);
|
|
2038
|
+
await ensureTables(options.D1, options.retryConfig);
|
|
2037
2039
|
ensuredTables = true;
|
|
2038
2040
|
}
|
|
2039
2041
|
const logAccessor = createLogAccessor({
|
|
2040
2042
|
D1: internalContext.D1,
|
|
2041
2043
|
externalBlobStorage: internalContext.externalBlobStorage,
|
|
2042
2044
|
serializer: internalContext.serializer,
|
|
2043
|
-
tenantId
|
|
2045
|
+
tenantId,
|
|
2046
|
+
retryConfig: options.retryConfig
|
|
2044
2047
|
});
|
|
2045
2048
|
if (scheduledInstanceId) {
|
|
2046
2049
|
const existingWorkflow = await logAccessor.getWorkflowShallow(scheduledInstanceId);
|
|
@@ -2096,7 +2099,8 @@ function createWorkflowContext(options) {
|
|
|
2096
2099
|
idFactory: internalContext.idFactory,
|
|
2097
2100
|
parentInstanceId,
|
|
2098
2101
|
reuseSuccessfulSteps,
|
|
2099
|
-
externalBlobStorage: options.externalBlobStorage
|
|
2102
|
+
externalBlobStorage: options.externalBlobStorage,
|
|
2103
|
+
retryConfig: options.retryConfig
|
|
2100
2104
|
});
|
|
2101
2105
|
try {
|
|
2102
2106
|
const result = await workflow._callback(input, {
|
|
@@ -2116,7 +2120,10 @@ function createWorkflowContext(options) {
|
|
|
2116
2120
|
}
|
|
2117
2121
|
},
|
|
2118
2122
|
async setWorkflowName(newName) {
|
|
2119
|
-
await updateWorkflowName({
|
|
2123
|
+
await updateWorkflowName({
|
|
2124
|
+
D1: options.D1,
|
|
2125
|
+
retryConfig: options.retryConfig
|
|
2126
|
+
}, instanceId, newName);
|
|
2120
2127
|
},
|
|
2121
2128
|
async setWorkflowProperty(key, value) {
|
|
2122
2129
|
await upsertWorkflowProperty({
|
|
@@ -2166,10 +2173,10 @@ function createWorkflowContext(options) {
|
|
|
2166
2173
|
};
|
|
2167
2174
|
const retry = async ({ workflow, retryInstanceId, triggerId, retryOptions }) => {
|
|
2168
2175
|
if (!ensuredTables) {
|
|
2169
|
-
await ensureTables(options.D1);
|
|
2176
|
+
await ensureTables(options.D1, options.retryConfig);
|
|
2170
2177
|
ensuredTables = true;
|
|
2171
2178
|
}
|
|
2172
|
-
const oldRun = await retryD1Operation(() => options.D1.prepare(`SELECT input, workflowName, tenantId, inputRef FROM WorkflowTable WHERE instanceId = ? `).bind(retryInstanceId).first());
|
|
2179
|
+
const oldRun = await retryD1Operation(() => options.D1.prepare(`SELECT input, workflowName, tenantId, inputRef FROM WorkflowTable WHERE instanceId = ? `).bind(retryInstanceId).first(), options.retryConfig);
|
|
2173
2180
|
const oldWorkflowName = oldRun?.workflowName;
|
|
2174
2181
|
const tenantId = oldRun?.tenantId;
|
|
2175
2182
|
if (!tenantId) throw new Error(`No tenantId found for instanceId ${retryInstanceId}`);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@brandboostinggmbh/observable-workflows",
|
|
3
|
-
"version": "0.20.0-beta.
|
|
3
|
+
"version": "0.20.0-beta.5",
|
|
4
4
|
"description": "My awesome typescript library",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -53,7 +53,7 @@
|
|
|
53
53
|
"test": "vitest run",
|
|
54
54
|
"typecheck": "tsc --noEmit",
|
|
55
55
|
"format": "prettier --cache --write .",
|
|
56
|
-
"release": "bumpp && pnpm publish",
|
|
57
|
-
"release:beta": "bumpp --preid beta && pnpm publish --tag beta"
|
|
56
|
+
"release": "npm login && bumpp && pnpm publish",
|
|
57
|
+
"release:beta": "npm login && bumpp --preid beta && pnpm publish --tag beta"
|
|
58
58
|
}
|
|
59
59
|
}
|