new-site/api/migrations/015_job_queue.sql
justin f8cd37ac8c Initial commit — Performance West telecom compliance platform
Includes: API (Express/TypeScript), Astro site, Python workers,
document generators, FCC compliance tools, Canada CRTC formation,
Ansible infrastructure, and deployment scripts.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-27 06:54:22 -05:00

46 lines
2 KiB
PL/PgSQL

-- 015_job_queue.sql
-- Persistent job queue for portal automation with retry and deferral.
--
-- Replaces the fire-and-forget in-memory job dispatch.
-- A scheduler thread in job_server.py polls this table every 60s.
--
-- Portal hours awareness:
-- BC Corporate Online: Mon-Sat 06:00-22:00 PT, Sun 13:00-22:00 PT
-- IRS EIN Assistant: Mon-Fri 07:00-22:00 ET
-- All others: 24/7 (no deferral needed)
--
-- Retry policy: exponential backoff, 5 attempts max, then escalate to admin.
BEGIN;
CREATE TABLE IF NOT EXISTS job_queue (
id SERIAL PRIMARY KEY,
job_type TEXT NOT NULL, -- 'file_entity' | 'obtain_ein' | 'name_search' | 'process_crtc' | 'deliver'
payload JSONB NOT NULL, -- order details, state_code, order_name, etc.
status TEXT NOT NULL DEFAULT 'pending'
CHECK (status IN ('pending', 'running', 'completed', 'failed', 'deferred', 'cancelled')),
attempts INTEGER NOT NULL DEFAULT 0,
max_attempts INTEGER NOT NULL DEFAULT 5,
run_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), -- next eligible run time
started_at TIMESTAMPTZ,
completed_at TIMESTAMPTZ,
last_error TEXT,
-- Portal context
portal_tz TEXT, -- e.g. 'America/Vancouver' for BC jobs
portal_hours JSONB, -- {mon:[6,22], tue:[6,22], ..., sun:[13,22]}
-- Linkage
order_id TEXT, -- denormalized for easy lookup
order_type TEXT, -- 'canada_crtc' | 'formation'
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
-- Scheduler polls this index every 60s for due, runnable jobs
CREATE INDEX IF NOT EXISTS idx_job_queue_runnable
ON job_queue (run_at, created_at)
WHERE status IN ('pending', 'deferred');
CREATE INDEX IF NOT EXISTS idx_job_queue_order
ON job_queue (order_id)
WHERE status NOT IN ('completed', 'cancelled');
COMMIT;