-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathschema.sql
More file actions
121 lines (98 loc) · 4.37 KB
/
schema.sql
File metadata and controls
121 lines (98 loc) · 4.37 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
-- ============================================================================
-- OpenQueue Database Schema
-- PostgreSQL-backed job queue service
-- ============================================================================
-- ============================================================================
-- Users Table (Tenants)
-- ============================================================================
CREATE TABLE users (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
email TEXT UNIQUE,
api_token_hash TEXT NOT NULL UNIQUE, -- SHA-256 hash of API token
is_active BOOLEAN NOT NULL DEFAULT TRUE,
created_at TIMESTAMP NOT NULL DEFAULT NOW(),
last_seen_at TIMESTAMP
);
-- ============================================================================
-- Jobs Table (Queue Items)
-- ============================================================================
CREATE TABLE jobs (
-- Identity
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE,
queue_name TEXT NOT NULL,
-- Payload
payload JSONB NOT NULL,
-- Status lifecycle:
-- pending -> processing -> completed
-- pending -> cancelled
-- processing -> failed -> (optional) pending (retry) OR dead (DLQ)
status TEXT NOT NULL DEFAULT 'pending',
priority INTEGER NOT NULL DEFAULT 0,
-- Retry configuration
retry_count INTEGER NOT NULL DEFAULT 0,
max_retries INTEGER NOT NULL DEFAULT 3,
-- Scheduling: job should not be leased before run_at
run_at TIMESTAMP NOT NULL DEFAULT NOW(),
-- Leasing / visibility-timeout support
locked_until TIMESTAMP,
locked_by TEXT,
lease_token UUID,
-- Timing metadata
created_at TIMESTAMP NOT NULL DEFAULT NOW(),
updated_at TIMESTAMP NOT NULL DEFAULT NOW(),
started_at TIMESTAMP,
finished_at TIMESTAMP,
-- Output
result JSONB,
error_text TEXT,
-- Dead-letter queue (DLQ) fields
dead_at TIMESTAMP,
dead_reason TEXT,
-- Lease metadata
lease_lost_count INTEGER NOT NULL DEFAULT 0
);
-- ============================================================================
-- Constraints
-- ============================================================================
-- Enforce valid statuses at the DB level
ALTER TABLE jobs
ADD CONSTRAINT jobs_status_check
CHECK (status IN ('pending', 'processing', 'completed', 'failed', 'cancelled', 'dead'));
-- Retry bounds must be non-negative
ALTER TABLE jobs
ADD CONSTRAINT jobs_retry_count_non_negative CHECK (retry_count >= 0),
ADD CONSTRAINT jobs_max_retries_non_negative CHECK (max_retries >= 0);
-- ============================================================================
-- Indexes (Hot Paths)
-- ============================================================================
-- Payload search (optional - for JSON querying)
CREATE INDEX idx_jobs_payload_gin ON jobs USING GIN (payload);
-- Status filtering (optional)
CREATE INDEX idx_jobs_status ON jobs(status);
-- --------------------------------------------------------------------------
-- Multi-tenant Indexes
-- --------------------------------------------------------------------------
-- Producer/dashboard listing: filter by user, queue, status, created
CREATE INDEX idx_jobs_user_queue_status_created
ON jobs(user_id, queue_name, status, created_at);
-- Worker lease hot path: find next eligible pending job
CREATE INDEX idx_jobs_user_queue_pending_ready
ON jobs(user_id, queue_name, run_at, priority DESC, created_at)
WHERE status = 'pending';
-- Worker lease recovery: re-lease expired processing jobs
CREATE INDEX idx_jobs_user_queue_processing_expired
ON jobs(user_id, queue_name, locked_until)
WHERE status = 'processing';
-- DLQ listing: find dead jobs per tenant
CREATE INDEX idx_jobs_user_queue_dead
ON jobs(user_id, queue_name, dead_at)
WHERE status = 'dead';
-- ============================================================================
-- Default User (Development)
-- ============================================================================
-- Token: oq_live_qXxA5liMxzRhz3uVTFYziaQSrw8tB05y2hU5O7VivyA
-- SHA256: a8000977a3ac8b4524c6ccd95a9935bc34b3be9fae30baaf15e5b103e293398a
INSERT INTO users (email, api_token_hash, is_active)
VALUES ('admin@openqueue.local', 'a8000977a3ac8b4524c6ccd95a9935bc34b3be9fae30baaf15e5b103e293398a', TRUE)
ON CONFLICT (api_token_hash) DO NOTHING;