mirror of
https://github.com/Luchexx/wacrm.git
synced 2026-11-02 09:19:51 +00:00
Merge pull request #40 from ArnasDon/fix/automations-atomic-execution-counter
fix(automations): atomic execution_count via SQL function (migration 007)
This commit is contained in:
commit
348dbb7d6c
@ -159,13 +159,16 @@ async function executeAutomation(automation: Automation, input: DispatchInput) {
|
|||||||
triggerEvent: input.triggerType,
|
triggerEvent: input.triggerType,
|
||||||
})
|
})
|
||||||
|
|
||||||
await db
|
// Atomic counter update via the SQL function from migration 007.
|
||||||
.from('automations')
|
// Doing this with a client-side read-modify-write raced when the
|
||||||
.update({
|
// same automation fired for two contacts simultaneously — both
|
||||||
execution_count: (automation.execution_count ?? 0) + 1,
|
// would read N and both write N+1, losing one count permanently.
|
||||||
last_executed_at: new Date().toISOString(),
|
const { error: rpcErr } = await db.rpc('increment_automation_execution_count', {
|
||||||
|
p_automation_id: automation.id,
|
||||||
})
|
})
|
||||||
.eq('id', automation.id)
|
if (rpcErr) {
|
||||||
|
console.error('[automations] increment counter failed:', rpcErr)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
interface ExecuteArgs {
|
interface ExecuteArgs {
|
||||||
|
|||||||
35
supabase/migrations/007_automations_increment_counter.sql
Normal file
35
supabase/migrations/007_automations_increment_counter.sql
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
-- ============================================================
|
||||||
|
-- 007_automations_increment_counter.sql
|
||||||
|
--
|
||||||
|
-- Atomic increment of automations.execution_count + refresh of
|
||||||
|
-- last_executed_at. Called via PostgREST RPC from the engine.
|
||||||
|
--
|
||||||
|
-- Before this, the engine did a read-modify-write:
|
||||||
|
-- UPDATE automations SET execution_count = <cached + 1> WHERE id = ...
|
||||||
|
-- so two concurrent dispatches (e.g. the same automation firing for
|
||||||
|
-- two different contacts in the same second) could both read N and
|
||||||
|
-- both write N+1, permanently losing one count.
|
||||||
|
--
|
||||||
|
-- Idempotent — safe to re-run.
|
||||||
|
-- ============================================================
|
||||||
|
|
||||||
|
CREATE OR REPLACE FUNCTION increment_automation_execution_count(p_automation_id UUID)
|
||||||
|
RETURNS VOID
|
||||||
|
LANGUAGE sql
|
||||||
|
SECURITY DEFINER
|
||||||
|
SET search_path = public
|
||||||
|
AS $$
|
||||||
|
UPDATE automations
|
||||||
|
SET
|
||||||
|
execution_count = execution_count + 1,
|
||||||
|
last_executed_at = NOW()
|
||||||
|
WHERE id = p_automation_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_automation_execution_count(UUID) FROM PUBLIC;
|
||||||
|
REVOKE ALL ON FUNCTION increment_automation_execution_count(UUID) FROM anon;
|
||||||
|
REVOKE ALL ON FUNCTION increment_automation_execution_count(UUID) FROM authenticated;
|
||||||
|
GRANT EXECUTE ON FUNCTION increment_automation_execution_count(UUID) TO service_role;
|
||||||
Loading…
Reference in New Issue
Block a user