@pgflow/core 0.1.18 → 0.1.20
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 +31 -19
- package/dist/ATLAS.md +32 -0
- package/dist/CHANGELOG.md +16 -0
- package/dist/README.md +31 -19
- package/dist/database-types.d.ts +116 -45
- package/dist/database-types.d.ts.map +1 -1
- package/dist/database-types.js +8 -1
- package/dist/package.json +2 -2
- package/dist/supabase/migrations/20250429164909_pgflow_initial.sql +579 -0
- package/package.json +3 -3
- package/dist/supabase/migrations/000000_schema.sql +0 -149
- package/dist/supabase/migrations/000005_create_flow.sql +0 -29
- package/dist/supabase/migrations/000010_add_step.sql +0 -48
- package/dist/supabase/migrations/000015_start_ready_steps.sql +0 -45
- package/dist/supabase/migrations/000020_start_flow.sql +0 -46
- package/dist/supabase/migrations/000030_read_with_poll_backport.sql +0 -70
- package/dist/supabase/migrations/000040_poll_for_tasks.sql +0 -100
- package/dist/supabase/migrations/000045_maybe_complete_run.sql +0 -30
- package/dist/supabase/migrations/000050_complete_task.sql +0 -98
- package/dist/supabase/migrations/000055_calculate_retry_delay.sql +0 -11
- package/dist/supabase/migrations/000060_fail_task.sql +0 -124
- package/dist/supabase/migrations/000_edge_worker_initial.sql +0 -86
|
@@ -1,124 +0,0 @@
|
|
|
1
|
-
create or replace function pgflow.fail_task(
|
|
2
|
-
run_id uuid,
|
|
3
|
-
step_slug text,
|
|
4
|
-
task_index int,
|
|
5
|
-
error_message text
|
|
6
|
-
)
|
|
7
|
-
returns setof pgflow.step_tasks
|
|
8
|
-
language plpgsql
|
|
9
|
-
volatile
|
|
10
|
-
set search_path to ''
|
|
11
|
-
as $$
|
|
12
|
-
begin
|
|
13
|
-
|
|
14
|
-
WITH run_lock AS (
|
|
15
|
-
SELECT * FROM pgflow.runs
|
|
16
|
-
WHERE pgflow.runs.run_id = fail_task.run_id
|
|
17
|
-
FOR UPDATE
|
|
18
|
-
),
|
|
19
|
-
step_lock AS (
|
|
20
|
-
SELECT * FROM pgflow.step_states
|
|
21
|
-
WHERE pgflow.step_states.run_id = fail_task.run_id
|
|
22
|
-
AND pgflow.step_states.step_slug = fail_task.step_slug
|
|
23
|
-
FOR UPDATE
|
|
24
|
-
),
|
|
25
|
-
flow_info AS (
|
|
26
|
-
SELECT r.flow_slug
|
|
27
|
-
FROM pgflow.runs r
|
|
28
|
-
WHERE r.run_id = fail_task.run_id
|
|
29
|
-
),
|
|
30
|
-
config AS (
|
|
31
|
-
SELECT
|
|
32
|
-
COALESCE(s.opt_max_attempts, f.opt_max_attempts) AS opt_max_attempts,
|
|
33
|
-
COALESCE(s.opt_base_delay, f.opt_base_delay) AS opt_base_delay
|
|
34
|
-
FROM pgflow.steps s
|
|
35
|
-
JOIN pgflow.flows f ON f.flow_slug = s.flow_slug
|
|
36
|
-
JOIN flow_info fi ON fi.flow_slug = s.flow_slug
|
|
37
|
-
WHERE s.flow_slug = fi.flow_slug AND s.step_slug = fail_task.step_slug
|
|
38
|
-
),
|
|
39
|
-
|
|
40
|
-
fail_or_retry_task as (
|
|
41
|
-
UPDATE pgflow.step_tasks as task
|
|
42
|
-
SET
|
|
43
|
-
status = CASE
|
|
44
|
-
WHEN task.attempts_count < (SELECT opt_max_attempts FROM config) THEN 'queued'
|
|
45
|
-
ELSE 'failed'
|
|
46
|
-
END,
|
|
47
|
-
error_message = fail_task.error_message
|
|
48
|
-
WHERE task.run_id = fail_task.run_id
|
|
49
|
-
AND task.step_slug = fail_task.step_slug
|
|
50
|
-
AND task.task_index = fail_task.task_index
|
|
51
|
-
AND task.status = 'queued'
|
|
52
|
-
RETURNING *
|
|
53
|
-
),
|
|
54
|
-
maybe_fail_step AS (
|
|
55
|
-
UPDATE pgflow.step_states
|
|
56
|
-
SET
|
|
57
|
-
status = CASE
|
|
58
|
-
WHEN (select fail_or_retry_task.status from fail_or_retry_task) = 'failed' THEN 'failed'
|
|
59
|
-
ELSE pgflow.step_states.status
|
|
60
|
-
END
|
|
61
|
-
FROM fail_or_retry_task
|
|
62
|
-
WHERE pgflow.step_states.run_id = fail_task.run_id
|
|
63
|
-
AND pgflow.step_states.step_slug = fail_task.step_slug
|
|
64
|
-
RETURNING pgflow.step_states.*
|
|
65
|
-
)
|
|
66
|
-
UPDATE pgflow.runs
|
|
67
|
-
SET status = CASE
|
|
68
|
-
WHEN (select status from maybe_fail_step) = 'failed' THEN 'failed'
|
|
69
|
-
ELSE status
|
|
70
|
-
END
|
|
71
|
-
WHERE pgflow.runs.run_id = fail_task.run_id;
|
|
72
|
-
|
|
73
|
-
-- For queued tasks: delay the message for retry with exponential backoff
|
|
74
|
-
PERFORM (
|
|
75
|
-
WITH retry_config AS (
|
|
76
|
-
SELECT
|
|
77
|
-
COALESCE(s.opt_base_delay, f.opt_base_delay) AS base_delay
|
|
78
|
-
FROM pgflow.steps s
|
|
79
|
-
JOIN pgflow.flows f ON f.flow_slug = s.flow_slug
|
|
80
|
-
JOIN pgflow.runs r ON r.flow_slug = f.flow_slug
|
|
81
|
-
WHERE r.run_id = fail_task.run_id
|
|
82
|
-
AND s.step_slug = fail_task.step_slug
|
|
83
|
-
),
|
|
84
|
-
queued_tasks AS (
|
|
85
|
-
SELECT
|
|
86
|
-
r.flow_slug,
|
|
87
|
-
st.message_id,
|
|
88
|
-
pgflow.calculate_retry_delay((SELECT base_delay FROM retry_config), st.attempts_count) AS calculated_delay
|
|
89
|
-
FROM pgflow.step_tasks st
|
|
90
|
-
JOIN pgflow.runs r ON st.run_id = r.run_id
|
|
91
|
-
WHERE st.run_id = fail_task.run_id
|
|
92
|
-
AND st.step_slug = fail_task.step_slug
|
|
93
|
-
AND st.task_index = fail_task.task_index
|
|
94
|
-
AND st.status = 'queued'
|
|
95
|
-
)
|
|
96
|
-
SELECT pgmq.set_vt(qt.flow_slug, qt.message_id, qt.calculated_delay)
|
|
97
|
-
FROM queued_tasks qt
|
|
98
|
-
WHERE EXISTS (SELECT 1 FROM queued_tasks)
|
|
99
|
-
);
|
|
100
|
-
|
|
101
|
-
-- For failed tasks: archive the message
|
|
102
|
-
PERFORM (
|
|
103
|
-
WITH failed_tasks AS (
|
|
104
|
-
SELECT r.flow_slug, st.message_id
|
|
105
|
-
FROM pgflow.step_tasks st
|
|
106
|
-
JOIN pgflow.runs r ON st.run_id = r.run_id
|
|
107
|
-
WHERE st.run_id = fail_task.run_id
|
|
108
|
-
AND st.step_slug = fail_task.step_slug
|
|
109
|
-
AND st.task_index = fail_task.task_index
|
|
110
|
-
AND st.status = 'failed'
|
|
111
|
-
)
|
|
112
|
-
SELECT pgmq.archive(ft.flow_slug, ft.message_id)
|
|
113
|
-
FROM failed_tasks ft
|
|
114
|
-
WHERE EXISTS (SELECT 1 FROM failed_tasks)
|
|
115
|
-
);
|
|
116
|
-
|
|
117
|
-
return query select *
|
|
118
|
-
from pgflow.step_tasks st
|
|
119
|
-
where st.run_id = fail_task.run_id
|
|
120
|
-
and st.step_slug = fail_task.step_slug
|
|
121
|
-
and st.task_index = fail_task.task_index;
|
|
122
|
-
|
|
123
|
-
end;
|
|
124
|
-
$$;
|
|
@@ -1,86 +0,0 @@
|
|
|
1
|
-
create extension if not exists pgmq version '1.4.4';
|
|
2
|
-
|
|
3
|
-
create schema if not exists edge_worker;
|
|
4
|
-
|
|
5
|
-
-------------------------------------------------------------------------------
|
|
6
|
-
-- Workers Table --------------------------------------------------------------
|
|
7
|
-
-------------------------------------------------------------------------------
|
|
8
|
-
create table if not exists edge_worker.workers (
|
|
9
|
-
worker_id uuid not null primary key,
|
|
10
|
-
queue_name text not null,
|
|
11
|
-
function_name text not null,
|
|
12
|
-
started_at timestamptz not null default now(),
|
|
13
|
-
stopped_at timestamptz,
|
|
14
|
-
last_heartbeat_at timestamptz not null default now()
|
|
15
|
-
);
|
|
16
|
-
|
|
17
|
-
--------------------------------------------------------------------------------
|
|
18
|
-
-- Read With Poll --------------------------------------------------------------
|
|
19
|
-
-- --
|
|
20
|
-
-- This is a backport of the pgmq.read_with_poll function from version 1.5.0 --
|
|
21
|
-
-- It is required because it fixes a bug with high CPU usage and Supabase --
|
|
22
|
-
-- is still using version 1.4.4. --
|
|
23
|
-
-- --
|
|
24
|
-
-- It is slightly modified (removed headers which are not available in 1.4.1) --
|
|
25
|
-
-- --
|
|
26
|
-
-- This will be removed once Supabase upgrades to 1.5.0 or higher. --
|
|
27
|
-
--------------------------------------------------------------------------------
|
|
28
|
-
create function edge_worker.read_with_poll(
|
|
29
|
-
queue_name text,
|
|
30
|
-
vt integer,
|
|
31
|
-
qty integer,
|
|
32
|
-
max_poll_seconds integer default 5,
|
|
33
|
-
poll_interval_ms integer default 100,
|
|
34
|
-
conditional jsonb default '{}'
|
|
35
|
-
)
|
|
36
|
-
returns setof pgmq.message_record as $$
|
|
37
|
-
DECLARE
|
|
38
|
-
r pgmq.message_record;
|
|
39
|
-
stop_at timestamp;
|
|
40
|
-
sql text;
|
|
41
|
-
qtable text := pgmq.format_table_name(queue_name, 'q');
|
|
42
|
-
BEGIN
|
|
43
|
-
stop_at := clock_timestamp() + make_interval(secs => max_poll_seconds);
|
|
44
|
-
LOOP
|
|
45
|
-
IF (SELECT clock_timestamp() >= stop_at) THEN
|
|
46
|
-
RETURN;
|
|
47
|
-
END IF;
|
|
48
|
-
|
|
49
|
-
sql := FORMAT(
|
|
50
|
-
$QUERY$
|
|
51
|
-
WITH cte AS
|
|
52
|
-
(
|
|
53
|
-
SELECT msg_id
|
|
54
|
-
FROM pgmq.%I
|
|
55
|
-
WHERE vt <= clock_timestamp() AND CASE
|
|
56
|
-
WHEN %L != '{}'::jsonb THEN (message @> %2$L)::integer
|
|
57
|
-
ELSE 1
|
|
58
|
-
END = 1
|
|
59
|
-
ORDER BY msg_id ASC
|
|
60
|
-
LIMIT $1
|
|
61
|
-
FOR UPDATE SKIP LOCKED
|
|
62
|
-
)
|
|
63
|
-
UPDATE pgmq.%I m
|
|
64
|
-
SET
|
|
65
|
-
vt = clock_timestamp() + %L,
|
|
66
|
-
read_ct = read_ct + 1
|
|
67
|
-
FROM cte
|
|
68
|
-
WHERE m.msg_id = cte.msg_id
|
|
69
|
-
RETURNING m.msg_id, m.read_ct, m.enqueued_at, m.vt, m.message;
|
|
70
|
-
$QUERY$,
|
|
71
|
-
qtable, conditional, qtable, make_interval(secs => vt)
|
|
72
|
-
);
|
|
73
|
-
|
|
74
|
-
FOR r IN
|
|
75
|
-
EXECUTE sql USING qty
|
|
76
|
-
LOOP
|
|
77
|
-
RETURN NEXT r;
|
|
78
|
-
END LOOP;
|
|
79
|
-
IF FOUND THEN
|
|
80
|
-
RETURN;
|
|
81
|
-
ELSE
|
|
82
|
-
PERFORM pg_sleep(poll_interval_ms::numeric / 1000);
|
|
83
|
-
END IF;
|
|
84
|
-
END LOOP;
|
|
85
|
-
END;
|
|
86
|
-
$$ language plpgsql;
|