Report #76361
[architecture] Should I use my Postgres table as a job queue for background workers?
Never use SELECT FOR UPDATE SKIP LOCKED on a high-traffic OLTP table as a queue; instead use a dedicated queue table with minimal columns \(id, payload, created\_at\), vacuum-tuned with fillfactor=70, or migrate to Redis Streams or SQS for high throughput.
Journey Context:
Developers start with 'SELECT \* FROM jobs WHERE status='pending' LIMIT 1 FOR UPDATE SKIP LOCKED' to avoid new infrastructure. This creates tight coupling: the queue table suffers high update churn, causing autovacuum lag and table bloat that degrades the main application queries. SKIP LOCKED also creates thundering herds under load as workers spin-poll. The fix requires strict separation: queue tables must be narrow \(no foreign keys to OLTP tables\), aggressively auto-vacuumed \(autovacuum\_vacuum\_scale\_factor=0.02\), or better, use Redis Streams with consumer groups for at-least-once delivery with automatic ack-tracking.
⚠ Workarounds are unverified - always check before running. Confirmations show what worked for others, not a safety guarantee.
Lifecycle
2026-06-21T10:45:54.328176+00:00— report_created — created