Files
defi-arbitrage/db/migrations/003_outbox_state_machine.sql
T
2026-03-02 12:14:07 -08:00

46 lines
1.4 KiB
PL/PgSQL

-- 003_outbox_state_machine.sql
-- Enforce state machine constraints and valid transitions
-- Prevents invalid status transitions (e.g., FINALIZED -> QUEUED)
ALTER TABLE dual_ledger_outbox
ADD CONSTRAINT dual_ledger_outbox_status_check
CHECK (status IN ('QUEUED','SENT','ACKED','FINALIZED','FAILED'));
CREATE OR REPLACE FUNCTION enforce_outbox_status_transition()
RETURNS trigger AS $$
DECLARE
allowed boolean := false;
BEGIN
-- No-op if status unchanged
IF OLD.status = NEW.status THEN
RETURN NEW;
END IF;
-- Allowed transitions:
-- QUEUED -> SENT | FAILED
-- SENT -> ACKED | FAILED
-- ACKED -> FINALIZED | FAILED
-- FAILED -> QUEUED (retry) | FAILED (no change)
IF OLD.status = 'QUEUED' AND NEW.status IN ('SENT','FAILED') THEN
allowed := true;
ELSIF OLD.status = 'SENT' AND NEW.status IN ('ACKED','FAILED') THEN
allowed := true;
ELSIF OLD.status = 'ACKED' AND NEW.status IN ('FINALIZED','FAILED') THEN
allowed := true;
ELSIF OLD.status = 'FAILED' AND NEW.status IN ('QUEUED','FAILED') THEN
allowed := true;
END IF;
IF NOT allowed THEN
RAISE EXCEPTION 'Invalid outbox transition: % -> %', OLD.status, NEW.status;
END IF;
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
DROP TRIGGER IF EXISTS dual_ledger_outbox_status_transition ON dual_ledger_outbox;
CREATE TRIGGER dual_ledger_outbox_status_transition
BEFORE UPDATE ON dual_ledger_outbox
FOR EACH ROW EXECUTE FUNCTION enforce_outbox_status_transition();