workerflow 0.1.0 → 0.3.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/README.md +35 -29
- package/package.json +1 -1
- package/src/definition.ts +126 -174
- package/src/json.ts +5 -7
- package/src/migrations/0000_initial.ts +98 -294
- package/src/runtime.ts +634 -998
- package/test/runtime.spec.ts +709 -1113
- package/test/tsconfig.json +1 -4
- package/test/worker.ts +1 -3
- package/demo/README.md +0 -73
- package/demo/index.html +0 -13
- package/demo/package.json +0 -33
- package/demo/public/vite.svg +0 -1
- package/demo/src/App.css +0 -0
- package/demo/src/App.tsx +0 -9
- package/demo/src/assets/Cloudflare_Logo.svg +0 -51
- package/demo/src/assets/react.svg +0 -1
- package/demo/src/index.css +0 -1
- package/demo/src/main.tsx +0 -10
- package/demo/tsconfig.app.json +0 -28
- package/demo/tsconfig.json +0 -14
- package/demo/tsconfig.node.json +0 -25
- package/demo/tsconfig.worker.json +0 -13
- package/demo/vite.config.ts +0 -9
- package/demo/worker/index.ts +0 -16
- package/demo/worker-configuration.d.ts +0 -12851
- package/demo/wrangler.jsonc +0 -32
|
@@ -5,7 +5,7 @@ export default `
|
|
|
5
5
|
id INTEGER NOT NULL PRIMARY KEY CHECK (id = 1),
|
|
6
6
|
|
|
7
7
|
status TEXT NOT NULL CHECK (
|
|
8
|
-
status IN ('pending', 'running', 'paused', 'completed', 'failed', 'cancelled')
|
|
8
|
+
status IN ('pending', 'initialized', 'running', 'paused', 'completed', 'failed', 'cancelled')
|
|
9
9
|
),
|
|
10
10
|
|
|
11
11
|
created_at INTEGER NOT NULL
|
|
@@ -15,365 +15,169 @@ export default `
|
|
|
15
15
|
updated_at INTEGER NOT NULL
|
|
16
16
|
DEFAULT (CAST(unixepoch('subsecond') * 1000 AS INTEGER)),
|
|
17
17
|
|
|
18
|
-
definition_version TEXT
|
|
19
|
-
CHECK (definition_version IS NULL OR length(definition_version) > 0),
|
|
20
18
|
definition_input TEXT
|
|
21
19
|
CHECK (definition_input IS NULL OR json_valid(definition_input)),
|
|
22
20
|
|
|
23
21
|
CHECK (updated_at >= created_at),
|
|
24
22
|
|
|
25
|
-
--
|
|
26
|
-
CHECK (
|
|
27
|
-
|
|
28
|
-
-- definition must be pinned before running/paused/completing/failing; cancelled is always allowed
|
|
29
|
-
CHECK (status IN ('pending', 'cancelled') OR definition_version IS NOT NULL)
|
|
23
|
+
-- definition_input must be NULL until create() initializes the workflow.
|
|
24
|
+
CHECK (status <> 'pending' OR definition_input IS NULL)
|
|
30
25
|
) STRICT;
|
|
31
26
|
|
|
32
27
|
CREATE TABLE steps (
|
|
33
28
|
id TEXT NOT NULL PRIMARY KEY CHECK (length(id) > 0),
|
|
34
29
|
type TEXT NOT NULL CHECK (type IN ('run', 'sleep', 'wait')),
|
|
35
|
-
|
|
36
|
-
'
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
30
|
+
created_at INTEGER NOT NULL
|
|
31
|
+
DEFAULT (CAST(unixepoch('subsecond') * 1000 AS INTEGER))
|
|
32
|
+
CHECK (created_at >= 0),
|
|
33
|
+
|
|
34
|
+
-- sleep / wait only: run rows use run_step_attempts for lifecycle
|
|
35
|
+
state TEXT CHECK (state IN (
|
|
40
36
|
'waiting',
|
|
41
37
|
'elapsed',
|
|
42
38
|
'satisfied',
|
|
43
39
|
'timed_out'
|
|
44
40
|
)),
|
|
45
|
-
created_at INTEGER NOT NULL
|
|
46
|
-
DEFAULT (CAST(unixepoch('subsecond') * 1000 AS INTEGER))
|
|
47
|
-
CHECK (created_at >= 0),
|
|
48
41
|
|
|
49
|
-
-- run-step fields
|
|
50
|
-
attempt_count INTEGER,
|
|
51
42
|
max_attempts INTEGER,
|
|
52
|
-
next_attempt_at INTEGER,
|
|
53
|
-
result TEXT,
|
|
54
|
-
error_message TEXT,
|
|
55
|
-
error_name TEXT,
|
|
56
43
|
|
|
57
|
-
|
|
58
|
-
wake_at INTEGER,
|
|
44
|
+
target_wake_at INTEGER,
|
|
59
45
|
|
|
60
|
-
-- wait-step fields
|
|
61
46
|
event_name TEXT,
|
|
62
47
|
timeout_at INTEGER,
|
|
63
|
-
payload TEXT,
|
|
64
48
|
|
|
65
|
-
-- terminal timestamp
|
|
66
49
|
resolved_at INTEGER,
|
|
67
50
|
|
|
68
|
-
-- innermost enclosing run step when this row was created (nested run / sleep / wait under a run callback)
|
|
69
51
|
parent_step_id TEXT REFERENCES steps(id) ON UPDATE RESTRICT ON DELETE RESTRICT,
|
|
70
52
|
|
|
71
|
-
CHECK (attempt_count IS NULL OR attempt_count >= 0),
|
|
72
53
|
CHECK (max_attempts IS NULL OR max_attempts >= 1),
|
|
73
|
-
CHECK (
|
|
74
|
-
CHECK (wake_at IS NULL OR wake_at >= 0),
|
|
54
|
+
CHECK (target_wake_at IS NULL OR target_wake_at >= 0),
|
|
75
55
|
CHECK (timeout_at IS NULL OR timeout_at >= 0),
|
|
76
56
|
CHECK (resolved_at IS NULL OR resolved_at >= created_at),
|
|
77
|
-
CHECK (error_name IS NULL OR length(error_name) > 0),
|
|
78
57
|
CHECK (event_name IS NULL OR length(event_name) > 0),
|
|
79
58
|
|
|
80
|
-
-- run steps may never exceed max_attempts
|
|
81
|
-
CHECK (
|
|
82
|
-
attempt_count IS NULL OR
|
|
83
|
-
max_attempts IS NULL OR
|
|
84
|
-
attempt_count <= max_attempts
|
|
85
|
-
),
|
|
86
|
-
|
|
87
59
|
CHECK (
|
|
88
60
|
(
|
|
89
61
|
type = 'run' AND
|
|
90
|
-
state
|
|
91
|
-
attempt_count IS NOT NULL AND attempt_count >= 0 AND
|
|
92
|
-
(max_attempts IS NULL OR max_attempts >= 1) AND
|
|
93
|
-
(max_attempts IS NULL OR attempt_count < max_attempts) AND
|
|
94
|
-
next_attempt_at IS NOT NULL AND
|
|
95
|
-
result IS NULL AND
|
|
96
|
-
error_message IS NULL AND
|
|
97
|
-
error_name IS NULL AND
|
|
98
|
-
wake_at IS NULL AND
|
|
99
|
-
event_name IS NULL AND
|
|
100
|
-
timeout_at IS NULL AND
|
|
101
|
-
payload IS NULL AND
|
|
102
|
-
resolved_at IS NULL
|
|
103
|
-
)
|
|
104
|
-
OR
|
|
105
|
-
(
|
|
106
|
-
type = 'run' AND
|
|
107
|
-
state = 'running' AND
|
|
108
|
-
attempt_count IS NOT NULL AND attempt_count >= 1 AND
|
|
62
|
+
state IS NULL AND
|
|
109
63
|
(max_attempts IS NULL OR max_attempts >= 1) AND
|
|
110
|
-
|
|
111
|
-
next_attempt_at IS NULL AND
|
|
112
|
-
result IS NULL AND
|
|
113
|
-
error_message IS NULL AND
|
|
114
|
-
error_name IS NULL AND
|
|
115
|
-
wake_at IS NULL AND
|
|
64
|
+
target_wake_at IS NULL AND
|
|
116
65
|
event_name IS NULL AND
|
|
117
66
|
timeout_at IS NULL AND
|
|
118
|
-
payload IS NULL AND
|
|
119
67
|
resolved_at IS NULL
|
|
120
68
|
)
|
|
121
69
|
OR
|
|
122
|
-
(
|
|
123
|
-
type = 'run' AND
|
|
124
|
-
state = 'succeeded' AND
|
|
125
|
-
attempt_count IS NOT NULL AND attempt_count >= 1 AND
|
|
126
|
-
(max_attempts IS NULL OR max_attempts >= 1) AND
|
|
127
|
-
(max_attempts IS NULL OR attempt_count <= max_attempts) AND
|
|
128
|
-
next_attempt_at IS NULL AND
|
|
129
|
-
result IS NOT NULL AND
|
|
130
|
-
error_message IS NULL AND
|
|
131
|
-
error_name IS NULL AND
|
|
132
|
-
wake_at IS NULL AND
|
|
133
|
-
event_name IS NULL AND
|
|
134
|
-
timeout_at IS NULL AND
|
|
135
|
-
payload IS NULL AND
|
|
136
|
-
resolved_at IS NOT NULL
|
|
137
|
-
)
|
|
138
|
-
OR
|
|
139
|
-
(
|
|
140
|
-
type = 'run' AND
|
|
141
|
-
state = 'failed' AND
|
|
142
|
-
attempt_count IS NOT NULL AND attempt_count >= 1 AND
|
|
143
|
-
(max_attempts IS NULL OR max_attempts >= 1) AND
|
|
144
|
-
(max_attempts IS NULL OR attempt_count <= max_attempts) AND
|
|
145
|
-
next_attempt_at IS NULL AND
|
|
146
|
-
result IS NULL AND
|
|
147
|
-
error_message IS NOT NULL AND
|
|
148
|
-
wake_at IS NULL AND
|
|
149
|
-
event_name IS NULL AND
|
|
150
|
-
timeout_at IS NULL AND
|
|
151
|
-
payload IS NULL AND
|
|
152
|
-
resolved_at IS NOT NULL
|
|
153
|
-
)
|
|
154
|
-
OR
|
|
155
70
|
(
|
|
156
71
|
type = 'sleep' AND
|
|
157
72
|
state = 'waiting' AND
|
|
158
|
-
attempt_count IS NULL AND
|
|
159
73
|
max_attempts IS NULL AND
|
|
160
|
-
|
|
161
|
-
result IS NULL AND
|
|
162
|
-
error_message IS NULL AND
|
|
163
|
-
error_name IS NULL AND
|
|
164
|
-
wake_at IS NOT NULL AND
|
|
74
|
+
target_wake_at IS NOT NULL AND
|
|
165
75
|
event_name IS NULL AND
|
|
166
76
|
timeout_at IS NULL AND
|
|
167
|
-
payload IS NULL AND
|
|
168
77
|
resolved_at IS NULL
|
|
169
78
|
)
|
|
170
79
|
OR
|
|
171
80
|
(
|
|
172
81
|
type = 'sleep' AND
|
|
173
82
|
state = 'elapsed' AND
|
|
174
|
-
attempt_count IS NULL AND
|
|
175
83
|
max_attempts IS NULL AND
|
|
176
|
-
|
|
177
|
-
result IS NULL AND
|
|
178
|
-
error_message IS NULL AND
|
|
179
|
-
error_name IS NULL AND
|
|
180
|
-
wake_at IS NULL AND
|
|
84
|
+
target_wake_at IS NOT NULL AND
|
|
181
85
|
event_name IS NULL AND
|
|
182
86
|
timeout_at IS NULL AND
|
|
183
|
-
payload IS NULL AND
|
|
184
87
|
resolved_at IS NOT NULL
|
|
185
88
|
)
|
|
186
89
|
OR
|
|
187
90
|
(
|
|
188
91
|
type = 'wait' AND
|
|
189
92
|
state = 'waiting' AND
|
|
190
|
-
attempt_count IS NULL AND
|
|
191
93
|
max_attempts IS NULL AND
|
|
192
|
-
|
|
193
|
-
result IS NULL AND
|
|
194
|
-
error_message IS NULL AND
|
|
195
|
-
error_name IS NULL AND
|
|
196
|
-
wake_at IS NULL AND
|
|
94
|
+
target_wake_at IS NULL AND
|
|
197
95
|
event_name IS NOT NULL AND
|
|
198
|
-
payload IS NULL AND
|
|
199
96
|
resolved_at IS NULL
|
|
200
97
|
)
|
|
201
98
|
OR
|
|
202
99
|
(
|
|
203
100
|
type = 'wait' AND
|
|
204
101
|
state = 'satisfied' AND
|
|
205
|
-
attempt_count IS NULL AND
|
|
206
102
|
max_attempts IS NULL AND
|
|
207
|
-
|
|
208
|
-
result IS NULL AND
|
|
209
|
-
error_message IS NULL AND
|
|
210
|
-
error_name IS NULL AND
|
|
211
|
-
wake_at IS NULL AND
|
|
103
|
+
target_wake_at IS NULL AND
|
|
212
104
|
event_name IS NOT NULL AND
|
|
213
|
-
timeout_at IS NULL AND
|
|
214
|
-
payload IS NOT NULL AND
|
|
215
105
|
resolved_at IS NOT NULL
|
|
216
106
|
)
|
|
217
107
|
OR
|
|
218
108
|
(
|
|
219
109
|
type = 'wait' AND
|
|
220
110
|
state = 'timed_out' AND
|
|
221
|
-
attempt_count IS NULL AND
|
|
222
111
|
max_attempts IS NULL AND
|
|
223
|
-
|
|
224
|
-
result IS NULL AND
|
|
225
|
-
error_message IS NULL AND
|
|
226
|
-
error_name IS NULL AND
|
|
227
|
-
wake_at IS NULL AND
|
|
112
|
+
target_wake_at IS NULL AND
|
|
228
113
|
event_name IS NOT NULL AND
|
|
229
|
-
timeout_at IS NULL AND
|
|
230
|
-
payload IS NULL AND
|
|
114
|
+
timeout_at IS NOT NULL AND
|
|
231
115
|
resolved_at IS NOT NULL
|
|
232
116
|
)
|
|
233
117
|
),
|
|
234
118
|
CHECK (parent_step_id IS NULL OR parent_step_id <> id)
|
|
235
119
|
) STRICT;
|
|
236
120
|
|
|
237
|
-
CREATE TABLE
|
|
121
|
+
CREATE TABLE run_step_attempts (
|
|
238
122
|
id TEXT NOT NULL PRIMARY KEY
|
|
239
123
|
DEFAULT (lower(hex(randomblob(16))))
|
|
240
124
|
CHECK (length(id) > 0),
|
|
241
125
|
|
|
242
|
-
step_id TEXT NOT NULL,
|
|
243
|
-
|
|
126
|
+
step_id TEXT NOT NULL REFERENCES steps(id) ON UPDATE RESTRICT ON DELETE RESTRICT,
|
|
127
|
+
|
|
128
|
+
started_at INTEGER NOT NULL
|
|
244
129
|
DEFAULT (CAST(unixepoch('subsecond') * 1000 AS INTEGER))
|
|
245
|
-
CHECK (
|
|
130
|
+
CHECK (started_at >= 0),
|
|
246
131
|
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
132
|
+
state TEXT NOT NULL CHECK (state IN ('started', 'succeeded', 'failed')),
|
|
133
|
+
|
|
134
|
+
ended_at INTEGER CHECK (ended_at IS NULL OR ended_at >= started_at),
|
|
135
|
+
|
|
136
|
+
-- Discriminator for the shape of a succeeded result.
|
|
137
|
+
-- 'json' → result_json holds the raw JSON value (never NULL)
|
|
138
|
+
-- 'none' → callback returned undefined/void, result_json IS NULL
|
|
139
|
+
result_type TEXT CHECK (result_type IN ('json', 'none')),
|
|
140
|
+
|
|
141
|
+
-- Raw JSON value. No wrapper objects.
|
|
142
|
+
-- NULL when result_type is 'none', or when the attempt hasn't succeeded yet.
|
|
143
|
+
result_json TEXT CHECK (result_json IS NULL OR json_valid(result_json)),
|
|
257
144
|
|
|
258
|
-
attempt_number INTEGER,
|
|
259
|
-
result TEXT,
|
|
260
145
|
error_message TEXT,
|
|
261
146
|
error_name TEXT,
|
|
262
|
-
next_attempt_at INTEGER,
|
|
263
|
-
wake_at INTEGER,
|
|
264
|
-
event_name TEXT,
|
|
265
|
-
timeout_at INTEGER,
|
|
266
|
-
payload TEXT,
|
|
147
|
+
next_attempt_at INTEGER CHECK (next_attempt_at IS NULL OR next_attempt_at >= 0),
|
|
267
148
|
|
|
268
|
-
FOREIGN KEY (step_id) REFERENCES steps(id) ON UPDATE RESTRICT ON DELETE RESTRICT,
|
|
269
|
-
|
|
270
|
-
CHECK (attempt_number IS NULL OR attempt_number >= 1),
|
|
271
|
-
CHECK (next_attempt_at IS NULL OR next_attempt_at >= 0),
|
|
272
|
-
CHECK (wake_at IS NULL OR wake_at >= 0),
|
|
273
|
-
CHECK (timeout_at IS NULL OR timeout_at >= 0),
|
|
274
149
|
CHECK (error_name IS NULL OR length(error_name) > 0),
|
|
275
|
-
CHECK (event_name IS NULL OR length(event_name) > 0),
|
|
276
150
|
|
|
277
151
|
CHECK (
|
|
278
152
|
(
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
153
|
+
state = 'started' AND
|
|
154
|
+
ended_at IS NULL AND
|
|
155
|
+
result_type IS NULL AND
|
|
156
|
+
result_json IS NULL AND
|
|
282
157
|
error_message IS NULL AND
|
|
283
158
|
error_name IS NULL AND
|
|
284
|
-
next_attempt_at IS NULL
|
|
285
|
-
wake_at IS NULL AND
|
|
286
|
-
event_name IS NULL AND
|
|
287
|
-
timeout_at IS NULL AND
|
|
288
|
-
payload IS NULL
|
|
159
|
+
next_attempt_at IS NULL
|
|
289
160
|
)
|
|
290
161
|
OR
|
|
291
162
|
(
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
163
|
+
state = 'succeeded' AND
|
|
164
|
+
ended_at IS NOT NULL AND
|
|
165
|
+
result_type IS NOT NULL AND
|
|
166
|
+
(
|
|
167
|
+
(result_type = 'none' AND result_json IS NULL) OR
|
|
168
|
+
(result_type = 'json' AND result_json IS NOT NULL)
|
|
169
|
+
) AND
|
|
295
170
|
error_message IS NULL AND
|
|
296
171
|
error_name IS NULL AND
|
|
297
|
-
next_attempt_at IS NULL
|
|
298
|
-
wake_at IS NULL AND
|
|
299
|
-
event_name IS NULL AND
|
|
300
|
-
timeout_at IS NULL AND
|
|
301
|
-
payload IS NULL
|
|
172
|
+
next_attempt_at IS NULL
|
|
302
173
|
)
|
|
303
174
|
OR
|
|
304
175
|
(
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
result IS NULL AND
|
|
176
|
+
state = 'failed' AND
|
|
177
|
+
ended_at IS NOT NULL AND
|
|
308
178
|
error_message IS NOT NULL AND
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
timeout_at IS NULL AND
|
|
312
|
-
payload IS NULL
|
|
313
|
-
)
|
|
314
|
-
OR
|
|
315
|
-
(
|
|
316
|
-
type = 'sleep_waiting' AND
|
|
317
|
-
attempt_number IS NULL AND
|
|
318
|
-
result IS NULL AND
|
|
319
|
-
error_message IS NULL AND
|
|
320
|
-
error_name IS NULL AND
|
|
321
|
-
next_attempt_at IS NULL AND
|
|
322
|
-
wake_at IS NOT NULL AND
|
|
323
|
-
event_name IS NULL AND
|
|
324
|
-
timeout_at IS NULL AND
|
|
325
|
-
payload IS NULL
|
|
326
|
-
)
|
|
327
|
-
OR
|
|
328
|
-
(
|
|
329
|
-
type = 'sleep_elapsed' AND
|
|
330
|
-
attempt_number IS NULL AND
|
|
331
|
-
result IS NULL AND
|
|
332
|
-
error_message IS NULL AND
|
|
333
|
-
error_name IS NULL AND
|
|
334
|
-
next_attempt_at IS NULL AND
|
|
335
|
-
wake_at IS NULL AND
|
|
336
|
-
event_name IS NULL AND
|
|
337
|
-
timeout_at IS NULL AND
|
|
338
|
-
payload IS NULL
|
|
339
|
-
)
|
|
340
|
-
OR
|
|
341
|
-
(
|
|
342
|
-
type = 'wait_waiting' AND
|
|
343
|
-
attempt_number IS NULL AND
|
|
344
|
-
result IS NULL AND
|
|
345
|
-
error_message IS NULL AND
|
|
346
|
-
error_name IS NULL AND
|
|
347
|
-
next_attempt_at IS NULL AND
|
|
348
|
-
wake_at IS NULL AND
|
|
349
|
-
event_name IS NOT NULL AND
|
|
350
|
-
payload IS NULL
|
|
351
|
-
)
|
|
352
|
-
OR
|
|
353
|
-
(
|
|
354
|
-
type = 'wait_satisfied' AND
|
|
355
|
-
attempt_number IS NULL AND
|
|
356
|
-
result IS NULL AND
|
|
357
|
-
error_message IS NULL AND
|
|
358
|
-
error_name IS NULL AND
|
|
359
|
-
next_attempt_at IS NULL AND
|
|
360
|
-
wake_at IS NULL AND
|
|
361
|
-
event_name IS NULL AND
|
|
362
|
-
timeout_at IS NULL AND
|
|
363
|
-
payload IS NOT NULL
|
|
364
|
-
)
|
|
365
|
-
OR
|
|
366
|
-
(
|
|
367
|
-
type = 'wait_timed_out' AND
|
|
368
|
-
attempt_number IS NULL AND
|
|
369
|
-
result IS NULL AND
|
|
370
|
-
error_message IS NULL AND
|
|
371
|
-
error_name IS NULL AND
|
|
372
|
-
next_attempt_at IS NULL AND
|
|
373
|
-
wake_at IS NULL AND
|
|
374
|
-
event_name IS NULL AND
|
|
375
|
-
timeout_at IS NULL AND
|
|
376
|
-
payload IS NULL
|
|
179
|
+
result_type IS NULL AND
|
|
180
|
+
result_json IS NULL
|
|
377
181
|
)
|
|
378
182
|
)
|
|
379
183
|
) STRICT;
|
|
@@ -405,6 +209,8 @@ export default `
|
|
|
405
209
|
DEFAULT (lower(hex(randomblob(16))))
|
|
406
210
|
CHECK (length(id) > 0),
|
|
407
211
|
event_name TEXT NOT NULL CHECK (length(event_name) > 0),
|
|
212
|
+
-- Raw JSON value, or SQL NULL when no payload was provided (undefined).
|
|
213
|
+
-- JSON null is stored as the TEXT literal 'null', distinct from SQL NULL.
|
|
408
214
|
payload TEXT CHECK (payload IS NULL OR json_valid(payload)),
|
|
409
215
|
created_at INTEGER NOT NULL
|
|
410
216
|
DEFAULT (CAST(unixepoch('subsecond') * 1000 AS INTEGER))
|
|
@@ -414,20 +220,21 @@ export default `
|
|
|
414
220
|
|
|
415
221
|
FOREIGN KEY (claimed_by) REFERENCES steps(id) ON UPDATE RESTRICT ON DELETE RESTRICT,
|
|
416
222
|
|
|
417
|
-
-- claimed_by and claimed_at must be set together or not set at all
|
|
418
223
|
CHECK (
|
|
419
224
|
(claimed_by IS NULL AND claimed_at IS NULL) OR
|
|
420
225
|
(claimed_by IS NOT NULL AND claimed_at IS NOT NULL)
|
|
421
226
|
)
|
|
422
227
|
) STRICT;
|
|
423
228
|
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
229
|
+
CREATE INDEX run_step_attempts_by_step_time_idx
|
|
230
|
+
ON run_step_attempts(step_id, started_at, id);
|
|
231
|
+
|
|
232
|
+
CREATE INDEX run_step_attempts_started_one_idx
|
|
233
|
+
ON run_step_attempts(step_id)
|
|
234
|
+
WHERE state = 'started';
|
|
428
235
|
|
|
429
236
|
CREATE INDEX steps_sleep_waiting_by_time_idx
|
|
430
|
-
ON steps(
|
|
237
|
+
ON steps(target_wake_at, id)
|
|
431
238
|
WHERE type = 'sleep' AND state = 'waiting';
|
|
432
239
|
|
|
433
240
|
CREATE INDEX steps_wait_waiting_by_event_idx
|
|
@@ -442,20 +249,16 @@ export default `
|
|
|
442
249
|
ON steps(parent_step_id, id)
|
|
443
250
|
WHERE parent_step_id IS NOT NULL;
|
|
444
251
|
|
|
445
|
-
CREATE INDEX step_events_by_step_and_time_idx
|
|
446
|
-
ON step_events(step_id, recorded_at, id);
|
|
447
|
-
|
|
448
252
|
CREATE INDEX workflow_events_by_time_idx
|
|
449
253
|
ON workflow_events(recorded_at, id);
|
|
450
254
|
|
|
451
255
|
CREATE INDEX inbound_events_by_name_and_time_idx
|
|
452
256
|
ON inbound_events(event_name, created_at, id);
|
|
453
257
|
|
|
454
|
-
CREATE INDEX
|
|
455
|
-
ON inbound_events(claimed_by
|
|
258
|
+
CREATE UNIQUE INDEX inbound_events_claimed_by_unique
|
|
259
|
+
ON inbound_events(claimed_by)
|
|
456
260
|
WHERE claimed_by IS NOT NULL;
|
|
457
261
|
|
|
458
|
-
-- immutable identity fields
|
|
459
262
|
CREATE TRIGGER workflow_metadata_immutable_fields
|
|
460
263
|
BEFORE UPDATE ON workflow_metadata
|
|
461
264
|
FOR EACH ROW
|
|
@@ -464,15 +267,16 @@ export default `
|
|
|
464
267
|
SELECT RAISE(ABORT, 'workflow_metadata.id and workflow_metadata.created_at are immutable');
|
|
465
268
|
END;
|
|
466
269
|
|
|
467
|
-
-- valid status transitions
|
|
468
270
|
CREATE TRIGGER workflow_metadata_valid_transition
|
|
469
271
|
BEFORE UPDATE ON workflow_metadata
|
|
470
272
|
FOR EACH ROW
|
|
471
273
|
WHEN NEW.status <> OLD.status
|
|
472
274
|
BEGIN
|
|
473
275
|
SELECT CASE
|
|
474
|
-
WHEN OLD.status = 'pending' AND NEW.status NOT IN ('
|
|
475
|
-
RAISE(ABORT, 'pending can only transition to
|
|
276
|
+
WHEN OLD.status = 'pending' AND NEW.status NOT IN ('initialized', 'cancelled') THEN
|
|
277
|
+
RAISE(ABORT, 'pending can only transition to initialized or cancelled')
|
|
278
|
+
WHEN OLD.status = 'initialized' AND NEW.status NOT IN ('running', 'cancelled') THEN
|
|
279
|
+
RAISE(ABORT, 'initialized can only transition to running or cancelled')
|
|
476
280
|
WHEN OLD.status = 'running' AND NEW.status NOT IN ('paused', 'completed', 'failed', 'cancelled') THEN
|
|
477
281
|
RAISE(ABORT, 'running can only transition to paused, completed, failed, or cancelled')
|
|
478
282
|
WHEN OLD.status = 'paused' AND NEW.status NOT IN ('running', 'cancelled') THEN
|
|
@@ -482,6 +286,14 @@ export default `
|
|
|
482
286
|
END;
|
|
483
287
|
END;
|
|
484
288
|
|
|
289
|
+
CREATE TRIGGER workflow_metadata_definition_input_immutable_after_init
|
|
290
|
+
BEFORE UPDATE ON workflow_metadata
|
|
291
|
+
FOR EACH ROW
|
|
292
|
+
WHEN OLD.status <> 'pending' AND NEW.definition_input IS NOT OLD.definition_input
|
|
293
|
+
BEGIN
|
|
294
|
+
SELECT RAISE(ABORT, 'workflow_metadata.definition_input is immutable after initialization');
|
|
295
|
+
END;
|
|
296
|
+
|
|
485
297
|
CREATE TRIGGER steps_immutable_identity_fields
|
|
486
298
|
BEFORE UPDATE ON steps
|
|
487
299
|
FOR EACH ROW
|
|
@@ -507,22 +319,34 @@ export default `
|
|
|
507
319
|
SELECT RAISE(ABORT, 'steps.parent_step_id must reference a run step');
|
|
508
320
|
END;
|
|
509
321
|
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
322
|
+
CREATE TRIGGER run_step_attempts_step_must_be_run
|
|
323
|
+
BEFORE INSERT ON run_step_attempts
|
|
324
|
+
WHEN (SELECT type FROM steps WHERE id = NEW.step_id) IS NOT 'run'
|
|
325
|
+
BEGIN
|
|
326
|
+
SELECT RAISE(ABORT, 'run_step_attempts.step_id must reference a run step');
|
|
327
|
+
END;
|
|
328
|
+
|
|
329
|
+
CREATE TRIGGER run_step_attempts_at_most_one_started_ins
|
|
330
|
+
BEFORE INSERT ON run_step_attempts
|
|
331
|
+
WHEN NEW.state = 'started'
|
|
332
|
+
AND EXISTS (SELECT 1 FROM run_step_attempts WHERE step_id = NEW.step_id AND state = 'started')
|
|
514
333
|
BEGIN
|
|
515
|
-
SELECT RAISE(ABORT, '
|
|
334
|
+
SELECT RAISE(ABORT, 'run step already has an in-flight attempt');
|
|
516
335
|
END;
|
|
517
336
|
|
|
518
|
-
CREATE TRIGGER
|
|
519
|
-
BEFORE
|
|
337
|
+
CREATE TRIGGER run_step_attempts_valid_transition
|
|
338
|
+
BEFORE UPDATE ON run_step_attempts
|
|
520
339
|
FOR EACH ROW
|
|
340
|
+
WHEN NEW.state <> OLD.state
|
|
521
341
|
BEGIN
|
|
522
|
-
SELECT
|
|
342
|
+
SELECT CASE
|
|
343
|
+
WHEN OLD.state = 'started' AND NEW.state NOT IN ('succeeded', 'failed') THEN
|
|
344
|
+
RAISE(ABORT, 'started can only transition to succeeded or failed')
|
|
345
|
+
WHEN OLD.state IN ('succeeded', 'failed') THEN
|
|
346
|
+
RAISE(ABORT, 'terminal attempt state cannot transition')
|
|
347
|
+
END;
|
|
523
348
|
END;
|
|
524
349
|
|
|
525
|
-
-- append-only workflow events
|
|
526
350
|
CREATE TRIGGER workflow_events_append_only_update
|
|
527
351
|
BEFORE UPDATE ON workflow_events
|
|
528
352
|
FOR EACH ROW
|
|
@@ -536,24 +360,4 @@ export default `
|
|
|
536
360
|
BEGIN
|
|
537
361
|
SELECT RAISE(ABORT, 'workflow_events is append-only');
|
|
538
362
|
END;
|
|
539
|
-
|
|
540
|
-
-- step_events.type must match the referenced row in steps.type
|
|
541
|
-
CREATE TRIGGER step_events_parent_type_match
|
|
542
|
-
BEFORE INSERT ON step_events
|
|
543
|
-
FOR EACH ROW
|
|
544
|
-
BEGIN
|
|
545
|
-
SELECT CASE
|
|
546
|
-
WHEN NOT EXISTS (SELECT 1 FROM steps WHERE id = NEW.step_id) THEN
|
|
547
|
-
RAISE(ABORT, 'step_events.step_id does not reference an existing steps row')
|
|
548
|
-
WHEN NEW.type IN ('attempt_started', 'attempt_succeeded', 'attempt_failed')
|
|
549
|
-
AND (SELECT type FROM steps WHERE id = NEW.step_id) <> 'run' THEN
|
|
550
|
-
RAISE(ABORT, 'run attempt events require a run step')
|
|
551
|
-
WHEN NEW.type IN ('sleep_waiting', 'sleep_elapsed')
|
|
552
|
-
AND (SELECT type FROM steps WHERE id = NEW.step_id) <> 'sleep' THEN
|
|
553
|
-
RAISE(ABORT, 'sleep events require a sleep step')
|
|
554
|
-
WHEN NEW.type IN ('wait_waiting', 'wait_satisfied', 'wait_timed_out')
|
|
555
|
-
AND (SELECT type FROM steps WHERE id = NEW.step_id) <> 'wait' THEN
|
|
556
|
-
RAISE(ABORT, 'wait events require a wait step')
|
|
557
|
-
END;
|
|
558
|
-
END;
|
|
559
363
|
`;
|