@pgflow/core 0.0.0-pgflow-installer-45a8ec76-20251211182851 → 0.0.0-pgflow-installer-249c293d-20251211201430

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.
Files changed (51) hide show
  1. package/dist/CHANGELOG.md +2 -2
  2. package/dist/package.json +1 -5
  3. package/package.json +2 -6
  4. package/dist/migrations/_generated/m_20250429164909.d.ts +0 -3
  5. package/dist/migrations/_generated/m_20250429164909.d.ts.map +0 -1
  6. package/dist/migrations/_generated/m_20250429164909.js +0 -584
  7. package/dist/migrations/_generated/m_20250517072017.d.ts +0 -3
  8. package/dist/migrations/_generated/m_20250517072017.d.ts.map +0 -1
  9. package/dist/migrations/_generated/m_20250517072017.js +0 -106
  10. package/dist/migrations/_generated/m_20250609105135.d.ts +0 -3
  11. package/dist/migrations/_generated/m_20250609105135.d.ts.map +0 -1
  12. package/dist/migrations/_generated/m_20250609105135.js +0 -376
  13. package/dist/migrations/_generated/m_20250610180554.d.ts +0 -3
  14. package/dist/migrations/_generated/m_20250610180554.d.ts.map +0 -1
  15. package/dist/migrations/_generated/m_20250610180554.js +0 -132
  16. package/dist/migrations/_generated/m_20250614124241.d.ts +0 -3
  17. package/dist/migrations/_generated/m_20250614124241.d.ts.map +0 -1
  18. package/dist/migrations/_generated/m_20250614124241.js +0 -506
  19. package/dist/migrations/_generated/m_20250619195327.d.ts +0 -3
  20. package/dist/migrations/_generated/m_20250619195327.d.ts.map +0 -1
  21. package/dist/migrations/_generated/m_20250619195327.js +0 -190
  22. package/dist/migrations/_generated/m_20250627090700.d.ts +0 -3
  23. package/dist/migrations/_generated/m_20250627090700.d.ts.map +0 -1
  24. package/dist/migrations/_generated/m_20250627090700.js +0 -11
  25. package/dist/migrations/_generated/m_20250707210212.d.ts +0 -3
  26. package/dist/migrations/_generated/m_20250707210212.d.ts.map +0 -1
  27. package/dist/migrations/_generated/m_20250707210212.js +0 -108
  28. package/dist/migrations/_generated/m_20250719205006.d.ts +0 -3
  29. package/dist/migrations/_generated/m_20250719205006.d.ts.map +0 -1
  30. package/dist/migrations/_generated/m_20250719205006.js +0 -7
  31. package/dist/migrations/_generated/m_20251006073122.d.ts +0 -3
  32. package/dist/migrations/_generated/m_20251006073122.d.ts.map +0 -1
  33. package/dist/migrations/_generated/m_20251006073122.js +0 -1249
  34. package/dist/migrations/_generated/m_20251103222045.d.ts +0 -3
  35. package/dist/migrations/_generated/m_20251103222045.d.ts.map +0 -1
  36. package/dist/migrations/_generated/m_20251103222045.js +0 -627
  37. package/dist/migrations/_generated/m_20251104080523.d.ts +0 -3
  38. package/dist/migrations/_generated/m_20251104080523.d.ts.map +0 -1
  39. package/dist/migrations/_generated/m_20251104080523.js +0 -98
  40. package/dist/migrations/_generated/m_20251130000000.d.ts +0 -3
  41. package/dist/migrations/_generated/m_20251130000000.d.ts.map +0 -1
  42. package/dist/migrations/_generated/m_20251130000000.js +0 -273
  43. package/dist/migrations/_generated/m_20251209074533.d.ts +0 -3
  44. package/dist/migrations/_generated/m_20251209074533.d.ts.map +0 -1
  45. package/dist/migrations/_generated/m_20251209074533.js +0 -278
  46. package/dist/migrations/index.d.ts +0 -11
  47. package/dist/migrations/index.d.ts.map +0 -1
  48. package/dist/migrations/index.js +0 -39
  49. package/dist/migrations/types.d.ts +0 -12
  50. package/dist/migrations/types.d.ts.map +0 -1
  51. package/dist/migrations/types.js +0 -1
@@ -1,506 +0,0 @@
1
- export const migration = {
2
- timestamp: '20250614124241',
3
- filename: '20250614124241_pgflow_add_realtime.sql',
4
- content: `-- Modify "step_states" table
5
- ALTER TABLE "pgflow"."step_states" ADD COLUMN "error_message" text NULL;
6
- -- Create index "idx_step_states_run_id" to table: "step_states"
7
- CREATE INDEX "idx_step_states_run_id" ON "pgflow"."step_states" ("run_id");
8
- -- Modify "maybe_complete_run" function
9
- CREATE OR REPLACE FUNCTION "pgflow"."maybe_complete_run" ("run_id" uuid) RETURNS void LANGUAGE plpgsql SET "search_path" = '' AS $$
10
- declare
11
- v_completed_run pgflow.runs%ROWTYPE;
12
- begin
13
- -- Update run status to completed and set output when there are no remaining steps
14
- WITH run_output AS (
15
- -- Get outputs from final steps (steps that are not dependencies for other steps)
16
- SELECT jsonb_object_agg(st.step_slug, st.output) as final_output
17
- FROM pgflow.step_tasks st
18
- JOIN pgflow.step_states ss ON ss.run_id = st.run_id AND ss.step_slug = st.step_slug
19
- JOIN pgflow.runs r ON r.run_id = ss.run_id AND r.flow_slug = ss.flow_slug
20
- WHERE st.run_id = maybe_complete_run.run_id
21
- AND st.status = 'completed'
22
- AND NOT EXISTS (
23
- SELECT 1
24
- FROM pgflow.deps d
25
- WHERE d.flow_slug = ss.flow_slug
26
- AND d.dep_slug = ss.step_slug
27
- )
28
- )
29
- UPDATE pgflow.runs
30
- SET
31
- status = 'completed',
32
- completed_at = now(),
33
- output = (SELECT final_output FROM run_output)
34
- WHERE pgflow.runs.run_id = maybe_complete_run.run_id
35
- AND pgflow.runs.remaining_steps = 0
36
- AND pgflow.runs.status != 'completed'
37
- RETURNING * INTO v_completed_run;
38
-
39
- -- Only send broadcast if run was completed
40
- IF v_completed_run.run_id IS NOT NULL THEN
41
- PERFORM realtime.send(
42
- jsonb_build_object(
43
- 'event_type', 'run:completed',
44
- 'run_id', v_completed_run.run_id,
45
- 'flow_slug', v_completed_run.flow_slug,
46
- 'status', 'completed',
47
- 'output', v_completed_run.output,
48
- 'completed_at', v_completed_run.completed_at
49
- ),
50
- 'run:completed',
51
- concat('pgflow:run:', v_completed_run.run_id),
52
- false
53
- );
54
- END IF;
55
- end;
56
- $$;
57
- -- Modify "start_ready_steps" function
58
- CREATE OR REPLACE FUNCTION "pgflow"."start_ready_steps" ("run_id" uuid) RETURNS void LANGUAGE sql SET "search_path" = '' AS $$
59
- WITH ready_steps AS (
60
- SELECT *
61
- FROM pgflow.step_states AS step_state
62
- WHERE step_state.run_id = start_ready_steps.run_id
63
- AND step_state.status = 'created'
64
- AND step_state.remaining_deps = 0
65
- ORDER BY step_state.step_slug
66
- FOR UPDATE
67
- ),
68
- started_step_states AS (
69
- UPDATE pgflow.step_states
70
- SET status = 'started',
71
- started_at = now()
72
- FROM ready_steps
73
- WHERE pgflow.step_states.run_id = start_ready_steps.run_id
74
- AND pgflow.step_states.step_slug = ready_steps.step_slug
75
- RETURNING pgflow.step_states.*
76
- ),
77
- sent_messages AS (
78
- SELECT
79
- started_step.flow_slug,
80
- started_step.run_id,
81
- started_step.step_slug,
82
- pgmq.send(started_step.flow_slug, jsonb_build_object(
83
- 'flow_slug', started_step.flow_slug,
84
- 'run_id', started_step.run_id,
85
- 'step_slug', started_step.step_slug,
86
- 'task_index', 0
87
- )) AS msg_id
88
- FROM started_step_states AS started_step
89
- ),
90
- broadcast_events AS (
91
- SELECT
92
- realtime.send(
93
- jsonb_build_object(
94
- 'event_type', 'step:started',
95
- 'run_id', started_step.run_id,
96
- 'step_slug', started_step.step_slug,
97
- 'status', 'started',
98
- 'started_at', started_step.started_at,
99
- 'remaining_tasks', 1,
100
- 'remaining_deps', started_step.remaining_deps
101
- ),
102
- concat('step:', started_step.step_slug, ':started'),
103
- concat('pgflow:run:', started_step.run_id),
104
- false
105
- )
106
- FROM started_step_states AS started_step
107
- )
108
- INSERT INTO pgflow.step_tasks (flow_slug, run_id, step_slug, message_id)
109
- SELECT
110
- sent_messages.flow_slug,
111
- sent_messages.run_id,
112
- sent_messages.step_slug,
113
- sent_messages.msg_id
114
- FROM sent_messages;
115
- $$;
116
- -- Modify "complete_task" function
117
- CREATE OR REPLACE FUNCTION "pgflow"."complete_task" ("run_id" uuid, "step_slug" text, "task_index" integer, "output" jsonb) RETURNS SETOF "pgflow"."step_tasks" LANGUAGE plpgsql SET "search_path" = '' AS $$
118
- declare
119
- v_step_state pgflow.step_states%ROWTYPE;
120
- begin
121
-
122
- WITH run_lock AS (
123
- SELECT * FROM pgflow.runs
124
- WHERE pgflow.runs.run_id = complete_task.run_id
125
- FOR UPDATE
126
- ),
127
- step_lock AS (
128
- SELECT * FROM pgflow.step_states
129
- WHERE pgflow.step_states.run_id = complete_task.run_id
130
- AND pgflow.step_states.step_slug = complete_task.step_slug
131
- FOR UPDATE
132
- ),
133
- task AS (
134
- UPDATE pgflow.step_tasks
135
- SET
136
- status = 'completed',
137
- completed_at = now(),
138
- output = complete_task.output
139
- WHERE pgflow.step_tasks.run_id = complete_task.run_id
140
- AND pgflow.step_tasks.step_slug = complete_task.step_slug
141
- AND pgflow.step_tasks.task_index = complete_task.task_index
142
- AND pgflow.step_tasks.status = 'started'
143
- RETURNING *
144
- ),
145
- step_state AS (
146
- UPDATE pgflow.step_states
147
- SET
148
- status = CASE
149
- WHEN pgflow.step_states.remaining_tasks = 1 THEN 'completed' -- Will be 0 after decrement
150
- ELSE 'started'
151
- END,
152
- completed_at = CASE
153
- WHEN pgflow.step_states.remaining_tasks = 1 THEN now() -- Will be 0 after decrement
154
- ELSE NULL
155
- END,
156
- remaining_tasks = pgflow.step_states.remaining_tasks - 1
157
- FROM task
158
- WHERE pgflow.step_states.run_id = complete_task.run_id
159
- AND pgflow.step_states.step_slug = complete_task.step_slug
160
- RETURNING pgflow.step_states.*
161
- ),
162
- -- Find all dependent steps if the current step was completed
163
- dependent_steps AS (
164
- SELECT d.step_slug AS dependent_step_slug
165
- FROM pgflow.deps d
166
- JOIN step_state s ON s.status = 'completed' AND d.flow_slug = s.flow_slug
167
- WHERE d.dep_slug = complete_task.step_slug
168
- ORDER BY d.step_slug -- Ensure consistent ordering
169
- ),
170
- -- Lock dependent steps before updating
171
- dependent_steps_lock AS (
172
- SELECT * FROM pgflow.step_states
173
- WHERE pgflow.step_states.run_id = complete_task.run_id
174
- AND pgflow.step_states.step_slug IN (SELECT dependent_step_slug FROM dependent_steps)
175
- FOR UPDATE
176
- ),
177
- -- Update all dependent steps
178
- dependent_steps_update AS (
179
- UPDATE pgflow.step_states
180
- SET remaining_deps = pgflow.step_states.remaining_deps - 1
181
- FROM dependent_steps
182
- WHERE pgflow.step_states.run_id = complete_task.run_id
183
- AND pgflow.step_states.step_slug = dependent_steps.dependent_step_slug
184
- )
185
- -- Only decrement remaining_steps, don't update status
186
- UPDATE pgflow.runs
187
- SET remaining_steps = pgflow.runs.remaining_steps - 1
188
- FROM step_state
189
- WHERE pgflow.runs.run_id = complete_task.run_id
190
- AND step_state.status = 'completed';
191
-
192
- -- Get the updated step state for broadcasting
193
- SELECT * INTO v_step_state FROM pgflow.step_states
194
- WHERE pgflow.step_states.run_id = complete_task.run_id AND pgflow.step_states.step_slug = complete_task.step_slug;
195
-
196
- -- Send broadcast event for step completed if the step is completed
197
- IF v_step_state.status = 'completed' THEN
198
- PERFORM realtime.send(
199
- jsonb_build_object(
200
- 'event_type', 'step:completed',
201
- 'run_id', complete_task.run_id,
202
- 'step_slug', complete_task.step_slug,
203
- 'status', 'completed',
204
- 'output', complete_task.output,
205
- 'completed_at', v_step_state.completed_at
206
- ),
207
- concat('step:', complete_task.step_slug, ':completed'),
208
- concat('pgflow:run:', complete_task.run_id),
209
- false
210
- );
211
- END IF;
212
-
213
- -- For completed tasks: archive the message
214
- PERFORM (
215
- WITH completed_tasks AS (
216
- SELECT r.flow_slug, st.message_id
217
- FROM pgflow.step_tasks st
218
- JOIN pgflow.runs r ON st.run_id = r.run_id
219
- WHERE st.run_id = complete_task.run_id
220
- AND st.step_slug = complete_task.step_slug
221
- AND st.task_index = complete_task.task_index
222
- AND st.status = 'completed'
223
- )
224
- SELECT pgmq.archive(ct.flow_slug, ct.message_id)
225
- FROM completed_tasks ct
226
- WHERE EXISTS (SELECT 1 FROM completed_tasks)
227
- );
228
-
229
- PERFORM pgflow.start_ready_steps(complete_task.run_id);
230
-
231
- PERFORM pgflow.maybe_complete_run(complete_task.run_id);
232
-
233
- RETURN QUERY SELECT *
234
- FROM pgflow.step_tasks AS step_task
235
- WHERE step_task.run_id = complete_task.run_id
236
- AND step_task.step_slug = complete_task.step_slug
237
- AND step_task.task_index = complete_task.task_index;
238
-
239
- end;
240
- $$;
241
- -- Modify "fail_task" function
242
- CREATE OR REPLACE FUNCTION "pgflow"."fail_task" ("run_id" uuid, "step_slug" text, "task_index" integer, "error_message" text) RETURNS SETOF "pgflow"."step_tasks" LANGUAGE plpgsql SET "search_path" = '' AS $$
243
- DECLARE
244
- v_run_failed boolean;
245
- begin
246
-
247
- WITH run_lock AS (
248
- SELECT * FROM pgflow.runs
249
- WHERE pgflow.runs.run_id = fail_task.run_id
250
- FOR UPDATE
251
- ),
252
- step_lock AS (
253
- SELECT * FROM pgflow.step_states
254
- WHERE pgflow.step_states.run_id = fail_task.run_id
255
- AND pgflow.step_states.step_slug = fail_task.step_slug
256
- FOR UPDATE
257
- ),
258
- flow_info AS (
259
- SELECT r.flow_slug
260
- FROM pgflow.runs r
261
- WHERE r.run_id = fail_task.run_id
262
- ),
263
- config AS (
264
- SELECT
265
- COALESCE(s.opt_max_attempts, f.opt_max_attempts) AS opt_max_attempts,
266
- COALESCE(s.opt_base_delay, f.opt_base_delay) AS opt_base_delay
267
- FROM pgflow.steps s
268
- JOIN pgflow.flows f ON f.flow_slug = s.flow_slug
269
- JOIN flow_info fi ON fi.flow_slug = s.flow_slug
270
- WHERE s.flow_slug = fi.flow_slug AND s.step_slug = fail_task.step_slug
271
- ),
272
- fail_or_retry_task as (
273
- UPDATE pgflow.step_tasks as task
274
- SET
275
- status = CASE
276
- WHEN task.attempts_count < (SELECT opt_max_attempts FROM config) THEN 'queued'
277
- ELSE 'failed'
278
- END,
279
- failed_at = CASE
280
- WHEN task.attempts_count >= (SELECT opt_max_attempts FROM config) THEN now()
281
- ELSE NULL
282
- END,
283
- started_at = CASE
284
- WHEN task.attempts_count < (SELECT opt_max_attempts FROM config) THEN NULL
285
- ELSE task.started_at
286
- END,
287
- error_message = fail_task.error_message
288
- WHERE task.run_id = fail_task.run_id
289
- AND task.step_slug = fail_task.step_slug
290
- AND task.task_index = fail_task.task_index
291
- AND task.status = 'started'
292
- RETURNING *
293
- ),
294
- maybe_fail_step AS (
295
- UPDATE pgflow.step_states
296
- SET
297
- status = CASE
298
- WHEN (select fail_or_retry_task.status from fail_or_retry_task) = 'failed' THEN 'failed'
299
- ELSE pgflow.step_states.status
300
- END,
301
- failed_at = CASE
302
- WHEN (select fail_or_retry_task.status from fail_or_retry_task) = 'failed' THEN now()
303
- ELSE NULL
304
- END,
305
- error_message = CASE
306
- WHEN (select fail_or_retry_task.status from fail_or_retry_task) = 'failed' THEN fail_task.error_message
307
- ELSE NULL
308
- END
309
- FROM fail_or_retry_task
310
- WHERE pgflow.step_states.run_id = fail_task.run_id
311
- AND pgflow.step_states.step_slug = fail_task.step_slug
312
- RETURNING pgflow.step_states.*
313
- ),
314
- -- Send broadcast event for step failed if necessary
315
- broadcast_step_failed AS (
316
- SELECT
317
- realtime.send(
318
- jsonb_build_object(
319
- 'event_type', 'step:failed',
320
- 'run_id', fail_task.run_id,
321
- 'step_slug', fail_task.step_slug,
322
- 'status', 'failed',
323
- 'error_message', fail_task.error_message,
324
- 'failed_at', now()
325
- ),
326
- concat('step:', fail_task.step_slug, ':failed'),
327
- concat('pgflow:run:', fail_task.run_id),
328
- false
329
- )
330
- FROM maybe_fail_step
331
- WHERE maybe_fail_step.status = 'failed'
332
- )
333
- -- Only decrement remaining_steps, don't update status
334
- UPDATE pgflow.runs
335
- SET status = CASE
336
- WHEN (select status from maybe_fail_step) = 'failed' THEN 'failed'
337
- ELSE status
338
- END,
339
- failed_at = CASE
340
- WHEN (select status from maybe_fail_step) = 'failed' THEN now()
341
- ELSE NULL
342
- END
343
- WHERE pgflow.runs.run_id = fail_task.run_id
344
- RETURNING (status = 'failed') INTO v_run_failed;
345
-
346
- -- Send broadcast event for run failure if the run was failed
347
- IF v_run_failed THEN
348
- DECLARE
349
- v_flow_slug text;
350
- BEGIN
351
- SELECT flow_slug INTO v_flow_slug FROM pgflow.runs WHERE pgflow.runs.run_id = fail_task.run_id;
352
-
353
- PERFORM realtime.send(
354
- jsonb_build_object(
355
- 'event_type', 'run:failed',
356
- 'run_id', fail_task.run_id,
357
- 'flow_slug', v_flow_slug,
358
- 'status', 'failed',
359
- 'error_message', fail_task.error_message,
360
- 'failed_at', now()
361
- ),
362
- 'run:failed',
363
- concat('pgflow:run:', fail_task.run_id),
364
- false
365
- );
366
- END;
367
- END IF;
368
-
369
- -- For queued tasks: delay the message for retry with exponential backoff
370
- PERFORM (
371
- WITH retry_config AS (
372
- SELECT
373
- COALESCE(s.opt_base_delay, f.opt_base_delay) AS base_delay
374
- FROM pgflow.steps s
375
- JOIN pgflow.flows f ON f.flow_slug = s.flow_slug
376
- JOIN pgflow.runs r ON r.flow_slug = f.flow_slug
377
- WHERE r.run_id = fail_task.run_id
378
- AND s.step_slug = fail_task.step_slug
379
- ),
380
- queued_tasks AS (
381
- SELECT
382
- r.flow_slug,
383
- st.message_id,
384
- pgflow.calculate_retry_delay((SELECT base_delay FROM retry_config), st.attempts_count) AS calculated_delay
385
- FROM pgflow.step_tasks st
386
- JOIN pgflow.runs r ON st.run_id = r.run_id
387
- WHERE st.run_id = fail_task.run_id
388
- AND st.step_slug = fail_task.step_slug
389
- AND st.task_index = fail_task.task_index
390
- AND st.status = 'queued'
391
- )
392
- SELECT pgmq.set_vt(qt.flow_slug, qt.message_id, qt.calculated_delay)
393
- FROM queued_tasks qt
394
- WHERE EXISTS (SELECT 1 FROM queued_tasks)
395
- );
396
-
397
- -- For failed tasks: archive the message
398
- PERFORM (
399
- WITH failed_tasks AS (
400
- SELECT r.flow_slug, st.message_id
401
- FROM pgflow.step_tasks st
402
- JOIN pgflow.runs r ON st.run_id = r.run_id
403
- WHERE st.run_id = fail_task.run_id
404
- AND st.step_slug = fail_task.step_slug
405
- AND st.task_index = fail_task.task_index
406
- AND st.status = 'failed'
407
- )
408
- SELECT pgmq.archive(ft.flow_slug, ft.message_id)
409
- FROM failed_tasks ft
410
- WHERE EXISTS (SELECT 1 FROM failed_tasks)
411
- );
412
-
413
- return query select *
414
- from pgflow.step_tasks st
415
- where st.run_id = fail_task.run_id
416
- and st.step_slug = fail_task.step_slug
417
- and st.task_index = fail_task.task_index;
418
-
419
- end;
420
- $$;
421
- -- Create "get_run_with_states" function
422
- CREATE FUNCTION "pgflow"."get_run_with_states" ("run_id" uuid) RETURNS jsonb LANGUAGE sql SECURITY DEFINER AS $$
423
- SELECT jsonb_build_object(
424
- 'run', to_jsonb(r),
425
- 'steps', COALESCE(jsonb_agg(to_jsonb(s)) FILTER (WHERE s.run_id IS NOT NULL), '[]'::jsonb)
426
- )
427
- FROM pgflow.runs r
428
- LEFT JOIN pgflow.step_states s ON s.run_id = r.run_id
429
- WHERE r.run_id = get_run_with_states.run_id
430
- GROUP BY r.run_id;
431
- $$;
432
- -- Create "start_flow" function
433
- CREATE FUNCTION "pgflow"."start_flow" ("flow_slug" text, "input" jsonb, "run_id" uuid DEFAULT NULL::uuid) RETURNS SETOF "pgflow"."runs" LANGUAGE plpgsql SET "search_path" = '' AS $$
434
- declare
435
- v_created_run pgflow.runs%ROWTYPE;
436
- begin
437
-
438
- WITH
439
- flow_steps AS (
440
- SELECT steps.flow_slug, steps.step_slug, steps.deps_count
441
- FROM pgflow.steps
442
- WHERE steps.flow_slug = start_flow.flow_slug
443
- ),
444
- created_run AS (
445
- INSERT INTO pgflow.runs (run_id, flow_slug, input, remaining_steps)
446
- VALUES (
447
- COALESCE(start_flow.run_id, gen_random_uuid()),
448
- start_flow.flow_slug,
449
- start_flow.input,
450
- (SELECT count(*) FROM flow_steps)
451
- )
452
- RETURNING *
453
- ),
454
- created_step_states AS (
455
- INSERT INTO pgflow.step_states (flow_slug, run_id, step_slug, remaining_deps)
456
- SELECT
457
- fs.flow_slug,
458
- (SELECT created_run.run_id FROM created_run),
459
- fs.step_slug,
460
- fs.deps_count
461
- FROM flow_steps fs
462
- )
463
- SELECT * FROM created_run INTO v_created_run;
464
-
465
- -- Send broadcast event for run started
466
- PERFORM realtime.send(
467
- jsonb_build_object(
468
- 'event_type', 'run:started',
469
- 'run_id', v_created_run.run_id,
470
- 'flow_slug', v_created_run.flow_slug,
471
- 'input', v_created_run.input,
472
- 'status', 'started',
473
- 'remaining_steps', v_created_run.remaining_steps,
474
- 'started_at', v_created_run.started_at
475
- ),
476
- 'run:started',
477
- concat('pgflow:run:', v_created_run.run_id),
478
- false
479
- );
480
-
481
- PERFORM pgflow.start_ready_steps(v_created_run.run_id);
482
-
483
- RETURN QUERY SELECT * FROM pgflow.runs where pgflow.runs.run_id = v_created_run.run_id;
484
-
485
- end;
486
- $$;
487
- -- Create "start_flow_with_states" function
488
- CREATE FUNCTION "pgflow"."start_flow_with_states" ("flow_slug" text, "input" jsonb, "run_id" uuid DEFAULT NULL::uuid) RETURNS jsonb LANGUAGE plpgsql SECURITY DEFINER AS $$
489
- DECLARE
490
- v_run_id UUID;
491
- BEGIN
492
- -- Start the flow using existing function
493
- SELECT r.run_id INTO v_run_id FROM pgflow.start_flow(
494
- start_flow_with_states.flow_slug,
495
- start_flow_with_states.input,
496
- start_flow_with_states.run_id
497
- ) AS r LIMIT 1;
498
-
499
- -- Use get_run_with_states to return the complete state
500
- RETURN pgflow.get_run_with_states(v_run_id);
501
- END;
502
- $$;
503
- -- Drop "start_flow" function
504
- DROP FUNCTION "pgflow"."start_flow" (text, jsonb);
505
- `,
506
- };
@@ -1,3 +0,0 @@
1
- import type { Migration } from '../types.js';
2
- export declare const migration: Migration;
3
- //# sourceMappingURL=m_20250619195327.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"m_20250619195327.d.ts","sourceRoot":"","sources":["../../../src/migrations/_generated/m_20250619195327.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAE7C,eAAO,MAAM,SAAS,EAAE,SA6LvB,CAAC"}
@@ -1,190 +0,0 @@
1
- export const migration = {
2
- timestamp: '20250619195327',
3
- filename: '20250619195327_pgflow_fix_fail_task_missing_realtime_event.sql',
4
- content: `-- Modify "fail_task" function
5
- CREATE OR REPLACE FUNCTION "pgflow"."fail_task" ("run_id" uuid, "step_slug" text, "task_index" integer, "error_message" text) RETURNS SETOF "pgflow"."step_tasks" LANGUAGE plpgsql SET "search_path" = '' AS $$
6
- DECLARE
7
- v_run_failed boolean;
8
- v_step_failed boolean;
9
- begin
10
-
11
- WITH run_lock AS (
12
- SELECT * FROM pgflow.runs
13
- WHERE pgflow.runs.run_id = fail_task.run_id
14
- FOR UPDATE
15
- ),
16
- step_lock AS (
17
- SELECT * FROM pgflow.step_states
18
- WHERE pgflow.step_states.run_id = fail_task.run_id
19
- AND pgflow.step_states.step_slug = fail_task.step_slug
20
- FOR UPDATE
21
- ),
22
- flow_info AS (
23
- SELECT r.flow_slug
24
- FROM pgflow.runs r
25
- WHERE r.run_id = fail_task.run_id
26
- ),
27
- config AS (
28
- SELECT
29
- COALESCE(s.opt_max_attempts, f.opt_max_attempts) AS opt_max_attempts,
30
- COALESCE(s.opt_base_delay, f.opt_base_delay) AS opt_base_delay
31
- FROM pgflow.steps s
32
- JOIN pgflow.flows f ON f.flow_slug = s.flow_slug
33
- JOIN flow_info fi ON fi.flow_slug = s.flow_slug
34
- WHERE s.flow_slug = fi.flow_slug AND s.step_slug = fail_task.step_slug
35
- ),
36
- fail_or_retry_task as (
37
- UPDATE pgflow.step_tasks as task
38
- SET
39
- status = CASE
40
- WHEN task.attempts_count < (SELECT opt_max_attempts FROM config) THEN 'queued'
41
- ELSE 'failed'
42
- END,
43
- failed_at = CASE
44
- WHEN task.attempts_count >= (SELECT opt_max_attempts FROM config) THEN now()
45
- ELSE NULL
46
- END,
47
- started_at = CASE
48
- WHEN task.attempts_count < (SELECT opt_max_attempts FROM config) THEN NULL
49
- ELSE task.started_at
50
- END,
51
- error_message = fail_task.error_message
52
- WHERE task.run_id = fail_task.run_id
53
- AND task.step_slug = fail_task.step_slug
54
- AND task.task_index = fail_task.task_index
55
- AND task.status = 'started'
56
- RETURNING *
57
- ),
58
- maybe_fail_step AS (
59
- UPDATE pgflow.step_states
60
- SET
61
- status = CASE
62
- WHEN (select fail_or_retry_task.status from fail_or_retry_task) = 'failed' THEN 'failed'
63
- ELSE pgflow.step_states.status
64
- END,
65
- failed_at = CASE
66
- WHEN (select fail_or_retry_task.status from fail_or_retry_task) = 'failed' THEN now()
67
- ELSE NULL
68
- END,
69
- error_message = CASE
70
- WHEN (select fail_or_retry_task.status from fail_or_retry_task) = 'failed' THEN fail_task.error_message
71
- ELSE NULL
72
- END
73
- FROM fail_or_retry_task
74
- WHERE pgflow.step_states.run_id = fail_task.run_id
75
- AND pgflow.step_states.step_slug = fail_task.step_slug
76
- RETURNING pgflow.step_states.*
77
- )
78
- -- Update run status
79
- UPDATE pgflow.runs
80
- SET status = CASE
81
- WHEN (select status from maybe_fail_step) = 'failed' THEN 'failed'
82
- ELSE status
83
- END,
84
- failed_at = CASE
85
- WHEN (select status from maybe_fail_step) = 'failed' THEN now()
86
- ELSE NULL
87
- END
88
- WHERE pgflow.runs.run_id = fail_task.run_id
89
- RETURNING (status = 'failed') INTO v_run_failed;
90
-
91
- -- Check if step failed by querying the step_states table
92
- SELECT (status = 'failed') INTO v_step_failed
93
- FROM pgflow.step_states
94
- WHERE pgflow.step_states.run_id = fail_task.run_id
95
- AND pgflow.step_states.step_slug = fail_task.step_slug;
96
-
97
- -- Send broadcast event for step failure if the step was failed
98
- IF v_step_failed THEN
99
- PERFORM realtime.send(
100
- jsonb_build_object(
101
- 'event_type', 'step:failed',
102
- 'run_id', fail_task.run_id,
103
- 'step_slug', fail_task.step_slug,
104
- 'status', 'failed',
105
- 'error_message', fail_task.error_message,
106
- 'failed_at', now()
107
- ),
108
- concat('step:', fail_task.step_slug, ':failed'),
109
- concat('pgflow:run:', fail_task.run_id),
110
- false
111
- );
112
- END IF;
113
-
114
- -- Send broadcast event for run failure if the run was failed
115
- IF v_run_failed THEN
116
- DECLARE
117
- v_flow_slug text;
118
- BEGIN
119
- SELECT flow_slug INTO v_flow_slug FROM pgflow.runs WHERE pgflow.runs.run_id = fail_task.run_id;
120
-
121
- PERFORM realtime.send(
122
- jsonb_build_object(
123
- 'event_type', 'run:failed',
124
- 'run_id', fail_task.run_id,
125
- 'flow_slug', v_flow_slug,
126
- 'status', 'failed',
127
- 'error_message', fail_task.error_message,
128
- 'failed_at', now()
129
- ),
130
- 'run:failed',
131
- concat('pgflow:run:', fail_task.run_id),
132
- false
133
- );
134
- END;
135
- END IF;
136
-
137
- -- For queued tasks: delay the message for retry with exponential backoff
138
- PERFORM (
139
- WITH retry_config AS (
140
- SELECT
141
- COALESCE(s.opt_base_delay, f.opt_base_delay) AS base_delay
142
- FROM pgflow.steps s
143
- JOIN pgflow.flows f ON f.flow_slug = s.flow_slug
144
- JOIN pgflow.runs r ON r.flow_slug = f.flow_slug
145
- WHERE r.run_id = fail_task.run_id
146
- AND s.step_slug = fail_task.step_slug
147
- ),
148
- queued_tasks AS (
149
- SELECT
150
- r.flow_slug,
151
- st.message_id,
152
- pgflow.calculate_retry_delay((SELECT base_delay FROM retry_config), st.attempts_count) AS calculated_delay
153
- FROM pgflow.step_tasks st
154
- JOIN pgflow.runs r ON st.run_id = r.run_id
155
- WHERE st.run_id = fail_task.run_id
156
- AND st.step_slug = fail_task.step_slug
157
- AND st.task_index = fail_task.task_index
158
- AND st.status = 'queued'
159
- )
160
- SELECT pgmq.set_vt(qt.flow_slug, qt.message_id, qt.calculated_delay)
161
- FROM queued_tasks qt
162
- WHERE EXISTS (SELECT 1 FROM queued_tasks)
163
- );
164
-
165
- -- For failed tasks: archive the message
166
- PERFORM (
167
- WITH failed_tasks AS (
168
- SELECT r.flow_slug, st.message_id
169
- FROM pgflow.step_tasks st
170
- JOIN pgflow.runs r ON st.run_id = r.run_id
171
- WHERE st.run_id = fail_task.run_id
172
- AND st.step_slug = fail_task.step_slug
173
- AND st.task_index = fail_task.task_index
174
- AND st.status = 'failed'
175
- )
176
- SELECT pgmq.archive(ft.flow_slug, ft.message_id)
177
- FROM failed_tasks ft
178
- WHERE EXISTS (SELECT 1 FROM failed_tasks)
179
- );
180
-
181
- return query select *
182
- from pgflow.step_tasks st
183
- where st.run_id = fail_task.run_id
184
- and st.step_slug = fail_task.step_slug
185
- and st.task_index = fail_task.task_index;
186
-
187
- end;
188
- $$;
189
- `,
190
- };
@@ -1,3 +0,0 @@
1
- import type { Migration } from '../types.js';
2
- export declare const migration: Migration;
3
- //# sourceMappingURL=m_20250627090700.d.ts.map