-- v1.1.9: queue:receive trigger kind + OutboxSourceKind::Invoke. -- -- queue:receive is the new trigger kind that fires a script per claimed -- message. Layout E parent + per-kind detail (mirrors pubsub). -- -- 'invoke' is added to outbox.source_kind for invoke_async() — a -- fire-and-forget function-composition call writes an outbox row that -- the dispatcher fires through the standard executor path. -- -- Queue itself does NOT need an outbox.source_kind variant (the queue -- table IS the outbox for queue semantics — see 0034). ALTER TABLE triggers DROP CONSTRAINT triggers_kind_check; ALTER TABLE triggers ADD CONSTRAINT triggers_kind_check CHECK (kind IN ('kv', 'dead_letter', 'docs', 'cron', 'files', 'pubsub', 'email', 'queue')); ALTER TABLE outbox DROP CONSTRAINT outbox_source_kind_check; ALTER TABLE outbox ADD CONSTRAINT outbox_source_kind_check CHECK (source_kind IN ('http', 'kv', 'dead_letter', 'docs', 'cron', 'files', 'pubsub', 'email', 'invoke')); -- Per-queue-trigger config. Retry policy lives on the parent triggers -- row (retry_max_attempts, retry_backoff, retry_base_ms) — same -- pattern as every other trigger kind. visibility_timeout_secs is -- queue-specific. -- -- "Exactly one consumer per (app_id, queue_name)" is enforced at the -- API layer via a pg_advisory_xact_lock on hashtext(app_id || queue_name) -- + a SELECT-then-INSERT in one transaction (a partial unique index -- can't reference the parent's app_id column from the detail table). CREATE TABLE queue_trigger_details ( trigger_id UUID PRIMARY KEY REFERENCES triggers(id) ON DELETE CASCADE, queue_name TEXT NOT NULL, visibility_timeout_secs INT NOT NULL DEFAULT 30, last_fired_at TIMESTAMPTZ NULL ); -- Help the dispatcher's "find all active queue consumers" query. CREATE INDEX idx_queue_trigger_details_queue_name ON queue_trigger_details (queue_name);