@@ -11,6 +11,7 @@ set search_path to ''
1111as  $$
1212declare
1313  v_step_state pgflow .step_states %ROWTYPE;
14+   v_updated_deps int ;
1415begin 
1516
1617WITH run_lock AS  (
@@ -28,12 +29,13 @@ task AS (
2829  UPDATE  pgflow .step_tasks 
2930  SET 
3031    status =  ' completed'  ,
32+     started_at =  COALESCE(started_at, now()),
3133    completed_at =  now(),
3234    output =  complete_task .output 
3335  WHERE  pgflow .step_tasks .run_id =  complete_task .run_id 
3436    AND  pgflow .step_tasks .step_slug =  complete_task .step_slug 
3537    AND  pgflow .step_tasks .task_index =  complete_task .task_index 
36-     AND  pgflow .step_tasks .status =   ' started' 
38+     AND  pgflow .step_tasks .status IN  ( ' started' ,  ' queued ' ) 
3739  RETURNING * 
3840),
3941step_state AS  (
@@ -52,29 +54,6 @@ step_state AS (
5254  WHERE  pgflow .step_states .run_id =  complete_task .run_id 
5355    AND  pgflow .step_states .step_slug =  complete_task .step_slug 
5456  RETURNING pgflow .step_states .* 
55- ),
56- --  Find all dependent steps if the current step was completed
57- dependent_steps AS  (
58-   SELECT  d .step_slug  AS  dependent_step_slug
59-   FROM  pgflow .deps  d
60-   JOIN  step_state s ON  s .status  =  ' completed'   AND  d .flow_slug  =  s .flow_slug 
61-   WHERE  d .dep_slug  =  complete_task .step_slug 
62-   ORDER BY  d .step_slug   --  Ensure consistent ordering
63- ),
64- --  Lock dependent steps before updating
65- dependent_steps_lock AS  (
66-   SELECT  *  FROM  pgflow .step_states 
67-   WHERE  pgflow .step_states .run_id =  complete_task .run_id 
68-     AND  pgflow .step_states .step_slug IN  (SELECT  dependent_step_slug FROM  dependent_steps)
69-   FOR UPDATE 
70- ),
71- --  Update all dependent steps
72- dependent_steps_update AS  (
73-   UPDATE  pgflow .step_states 
74-   SET  remaining_deps =  pgflow .step_states .remaining_deps -  1 
75-   FROM  dependent_steps
76-   WHERE  pgflow .step_states .run_id =  complete_task .run_id 
77-     AND  pgflow .step_states .step_slug =  dependent_steps .dependent_step_slug 
7857)
7958--  Only decrement remaining_steps, don't update status
8059UPDATE  pgflow .runs 
@@ -87,6 +66,38 @@ WHERE pgflow.runs.run_id = complete_task.run_id
8766SELECT  *  INTO v_step_state FROM  pgflow .step_states 
8867WHERE  pgflow .step_states .run_id =  complete_task .run_id  AND  pgflow .step_states .step_slug =  complete_task .step_slug ;
8968
69+ --  If the step completed, update dependent steps
70+ IF v_step_state .status  =  ' completed'   THEN
71+   --  Update remaining_deps and initial_tasks for dependent steps
72+   UPDATE  pgflow .step_states  ss
73+   SET  remaining_deps =  ss .remaining_deps  -  1 ,
74+       initial_tasks =  CASE
75+         --  Only update initial_tasks for map dependents
76+         WHEN dep_step .step_type  =  ' map'   THEN
77+           CASE
78+             --  If the completed step is a single step outputting an array
79+             WHEN src_step .step_type  =  ' single'   AND  jsonb_typeof(complete_task .output ) =  ' array'   THEN
80+               jsonb_array_length(complete_task .output )
81+             --  If the completed step is a map step
82+             WHEN src_step .step_type  =  ' map'   THEN
83+               v_step_state .initial_tasks 
84+             ELSE
85+               ss .initial_tasks 
86+           END
87+         ELSE
88+           ss .initial_tasks   --  Non-map dependents keep their initial_tasks
89+       END
90+   FROM  pgflow .deps  d
91+   JOIN  pgflow .steps  dep_step ON  dep_step .flow_slug  =  v_step_state .flow_slug 
92+                               AND  dep_step .step_slug  =  d .step_slug 
93+   JOIN  pgflow .steps  src_step ON  src_step .flow_slug  =  v_step_state .flow_slug 
94+                               AND  src_step .step_slug  =  complete_task .step_slug 
95+   WHERE  d .flow_slug  =  v_step_state .flow_slug 
96+     AND  d .dep_slug  =  complete_task .step_slug 
97+     AND  ss .run_id  =  complete_task .run_id 
98+     AND  ss .step_slug  =  d .step_slug ;
99+ END IF;
100+ 
90101--  Send broadcast event for step completed if the step is completed
91102IF v_step_state .status  =  ' completed'   THEN
92103  PERFORM realtime .send (
@@ -104,6 +115,9 @@ IF v_step_state.status = 'completed' THEN
104115  );
105116END IF;
106117
118+ --  Always cascade after completing a task, in case dependent maps became taskless
119+ PERFORM pgflow .cascade_complete_taskless_steps (complete_task .run_id );
120+ 
107121--  For completed tasks: archive the message
108122PERFORM (
109123  WITH completed_tasks AS  (
@@ -132,3 +146,20 @@ WHERE step_task.run_id = complete_task.run_id
132146
133147end;
134148$$;
149+ 
150+ --  Convenience overload that accepts a JSONB task object
151+ create or replace  function  pgflow .complete_task(
152+   task jsonb,
153+   output jsonb
154+ )
155+ returns setof pgflow .step_tasks 
156+ language sql
157+ set  search_path to ' ' 
158+ as  $$
159+   select  *  from  pgflow .complete_task (
160+     (task- >> ' run_id'  )::uuid,
161+     task- >> ' step_slug'  ,
162+     (task- >> ' task_index'  )::int ,
163+     output
164+   );
165+ $$;
0 commit comments