@@ -9,92 +9,102 @@ returns setof pgflow.step_task_record
9
9
volatile
10
10
set search_path to ' '
11
11
as $$
12
-
13
- with read_messages as (
14
- select *
12
+ declare
13
+ msg_ids bigint [];
14
+ begin
15
+ -- First statement: Read messages and capture their IDs
16
+ -- This gets its own snapshot and can see newly committed messages
17
+ select array_agg(msg_id)
18
+ into msg_ids
15
19
from pgflow .read_with_poll (
16
20
queue_name,
17
21
vt,
18
22
qty,
19
23
max_poll_seconds,
20
24
poll_interval_ms
25
+ );
26
+
27
+ -- If no messages were read, return empty set
28
+ if msg_ids is null or array_length(msg_ids, 1 ) is null then
29
+ return;
30
+ end if;
31
+
32
+ -- Second statement: Process tasks with fresh snapshot
33
+ -- This can now see step_tasks that were committed during the poll
34
+ return query
35
+ with tasks as (
36
+ select
37
+ task .flow_slug ,
38
+ task .run_id ,
39
+ task .step_slug ,
40
+ task .task_index ,
41
+ task .message_id
42
+ from pgflow .step_tasks as task
43
+ where task .message_id = any(msg_ids)
44
+ and task .status = ' queued'
45
+ ),
46
+ increment_attempts as (
47
+ update pgflow .step_tasks
48
+ set attempts_count = attempts_count + 1
49
+ from tasks
50
+ where step_tasks .message_id = tasks .message_id
51
+ and status = ' queued'
52
+ ),
53
+ runs as (
54
+ select
55
+ r .run_id ,
56
+ r .input
57
+ from pgflow .runs r
58
+ where r .run_id in (select run_id from tasks)
59
+ ),
60
+ deps as (
61
+ select
62
+ st .run_id ,
63
+ st .step_slug ,
64
+ dep .dep_slug ,
65
+ dep_task .output as dep_output
66
+ from tasks st
67
+ join pgflow .deps dep on dep .flow_slug = st .flow_slug and dep .step_slug = st .step_slug
68
+ join pgflow .step_tasks dep_task on
69
+ dep_task .run_id = st .run_id and
70
+ dep_task .step_slug = dep .dep_slug and
71
+ dep_task .status = ' completed'
72
+ ),
73
+ deps_outputs as (
74
+ select
75
+ d .run_id ,
76
+ d .step_slug ,
77
+ jsonb_object_agg(d .dep_slug , d .dep_output ) as deps_output
78
+ from deps d
79
+ group by d .run_id , d .step_slug
80
+ ),
81
+ timeouts as (
82
+ select
83
+ task .message_id ,
84
+ coalesce(step .opt_timeout , flow .opt_timeout ) + 2 as vt_delay
85
+ from tasks task
86
+ join pgflow .flows flow on flow .flow_slug = task .flow_slug
87
+ join pgflow .steps step on step .flow_slug = task .flow_slug and step .step_slug = task .step_slug
21
88
)
22
- ),
23
- tasks as (
24
- select
25
- task .flow_slug ,
26
- task .run_id ,
27
- task .step_slug ,
28
- task .task_index ,
29
- task .message_id
30
- from pgflow .step_tasks as task
31
- join read_messages as message on message .msg_id = task .message_id
32
- where task .message_id = message .msg_id
33
- and task .status = ' queued'
34
- ),
35
- increment_attempts as (
36
- update pgflow .step_tasks
37
- set attempts_count = attempts_count + 1
38
- from tasks
39
- where step_tasks .message_id = tasks .message_id
40
- and status = ' queued'
41
- ),
42
- runs as (
43
- select
44
- r .run_id ,
45
- r .input
46
- from pgflow .runs r
47
- where r .run_id in (select run_id from tasks)
48
- ),
49
- deps as (
50
89
select
90
+ st .flow_slug ,
51
91
st .run_id ,
52
92
st .step_slug ,
53
- dep .dep_slug ,
54
- dep_task .output as dep_output
93
+ jsonb_build_object(' run' , r .input ) ||
94
+ coalesce(dep_out .deps_output , ' {}' ::jsonb) as input,
95
+ st .message_id as msg_id
55
96
from tasks st
56
- join pgflow .deps dep on dep .flow_slug = st .flow_slug and dep .step_slug = st .step_slug
57
- join pgflow .step_tasks dep_task on
58
- dep_task .run_id = st .run_id and
59
- dep_task .step_slug = dep .dep_slug and
60
- dep_task .status = ' completed'
61
- ),
62
- deps_outputs as (
63
- select
64
- d .run_id ,
65
- d .step_slug ,
66
- jsonb_object_agg(d .dep_slug , d .dep_output ) as deps_output
67
- from deps d
68
- group by d .run_id , d .step_slug
69
- ),
70
- timeouts as (
71
- select
72
- task .message_id ,
73
- coalesce(step .opt_timeout , flow .opt_timeout ) + 2 as vt_delay
74
- from tasks task
75
- join pgflow .flows flow on flow .flow_slug = task .flow_slug
76
- join pgflow .steps step on step .flow_slug = task .flow_slug and step .step_slug = task .step_slug
77
- )
78
-
79
- select
80
- st .flow_slug ,
81
- st .run_id ,
82
- st .step_slug ,
83
- jsonb_build_object(' run' , r .input ) ||
84
- coalesce(dep_out .deps_output , ' {}' ::jsonb) as input,
85
- st .message_id as msg_id
86
- from tasks st
87
- join runs r on st .run_id = r .run_id
88
- left join deps_outputs dep_out on
89
- dep_out .run_id = st .run_id and
90
- dep_out .step_slug = st .step_slug
91
- cross join lateral (
92
- -- TODO: this is slow because it calls set_vt for each row, and set_vt
93
- -- builds dynamic query from string every time it is called
94
- -- implement set_vt_batch(msgs_ids bigint[], vt_delays int[])
95
- select pgmq .set_vt (queue_name, st .message_id ,
96
- (select t .vt_delay from timeouts t where t .message_id = st .message_id )
97
- )
98
- ) set_vt;
99
-
100
- $$ language sql;
97
+ join runs r on st .run_id = r .run_id
98
+ left join deps_outputs dep_out on
99
+ dep_out .run_id = st .run_id and
100
+ dep_out .step_slug = st .step_slug
101
+ cross join lateral (
102
+ -- TODO: this is slow because it calls set_vt for each row, and set_vt
103
+ -- builds dynamic query from string every time it is called
104
+ -- implement set_vt_batch(msgs_ids bigint[], vt_delays int[])
105
+ select pgmq .set_vt (queue_name, st .message_id ,
106
+ (select t .vt_delay from timeouts t where t .message_id = st .message_id )
107
+ )
108
+ ) set_vt;
109
+ end;
110
+ $$ language plpgsql;
0 commit comments