-- ============================================================ -- 012_flows_increment_counter.sql -- -- Atomic increment of flows.execution_count + refresh of -- last_executed_at. Called via PostgREST RPC from the engine. -- -- Before this, startNewRun did a read-modify-write: -- UPDATE flows SET execution_count = WHERE id = ... -- so two concurrent dispatches (e.g. two webhooks for the same flow -- starting runs for different contacts in the same second) could both -- read N and both write N+1, permanently losing one count. -- -- Mirrors migration 007 for automations — same shape, same security -- posture. Idempotent: safe to re-run. -- ============================================================ CREATE OR REPLACE FUNCTION increment_flow_execution_count(p_flow_id UUID) RETURNS VOID LANGUAGE sql SECURITY DEFINER SET search_path = public AS $$ UPDATE flows SET execution_count = execution_count + 1, last_executed_at = NOW() WHERE id = p_flow_id; $$; -- Only the service role needs to call this (engine uses the -- service-role client). Explicitly lock anon / authenticated out so -- an authenticated user can't juice someone else's counter via RPC. REVOKE ALL ON FUNCTION increment_flow_execution_count(UUID) FROM PUBLIC; REVOKE ALL ON FUNCTION increment_flow_execution_count(UUID) FROM anon; REVOKE ALL ON FUNCTION increment_flow_execution_count(UUID) FROM authenticated; GRANT EXECUTE ON FUNCTION increment_flow_execution_count(UUID) TO service_role;