We use analytics cookies.We use cookies to analyze site traffic and improve your experience.
Loading...
4 system design questions lean on this idea. Each walks through the full answer.
System Design Masterclass · Messaging Event Systems
Free preview: the first 2 parts of this 7-part lesson.
Already bought the course? Sign in to read the whole lesson.
this lesson is part of
System Design Masterclass
Unlock this lesson and the 751 other paid lessons
$25 once, by PayPal
See the System Design courseread the rest of this lesson in
System Design Masterclass
Unlock this lesson and the 751 other paid lessons
$25 once, by PayPal
See the System Design coursein Messaging Event Systems
This lesson is part of the full System Design Masterclass. Unlock it along with 769 other lessons for a one-time payment.
One-time payment by card or PayPal
Get Lifetime AccessOne-time payment: UPI, card or netbanking
Get Lifetime Access18 Foundation lessons are free, no payment needed. Try them now
It is easy and good
“It is really nice and good Please join the course”
You set an alarm for 7 AM. The alarm doesn't ring immediately. It waits until the scheduled time. You don't have to stay awake watching the clock. The alarm system handles the timing for you.
Delayed queues work the same way. A message is published to the queue but isn't delivered to consumers until a specified delay has passed. The message sits in a holding area, invisible to consumers, until its "alarm" goes off.
This is useful whenever you need to schedule future work:
Without delayed queues, you'd need a separate scheduling system (cron jobs, timers, a scheduler service) that polls the database every minute looking for work. GitHub's Actions scheduler, for instance, used to poll a Postgres table every 10 seconds for scheduled workflows. They migrated to a sorted set delay pattern and cut their scheduler's CPU usage by 85%.
The key advantage: scheduling becomes part of your messaging infrastructure. No extra services to deploy, monitor, and scale.
Per-message delay: Each message specifies its own delay. "Deliver this message 5 minutes from now."
queue.publish({
body: { userId: '123', action: 'send-reminder' },
delay: 86400000 // 24 hours in ms
});
Queue-level delay: Every message in the queue is delayed by the same fixed amount. SQS calls this "delivery delay" (0-15 minutes max).
The RabbitMQ + DLX trick. If you don't have the delayed exchange plugin, you can create a "parking" queue with a TTL and a dead letter exchange pointing to the real queue. Messages expire from the parking queue after the TTL and are routed to the real queue. Clever, but limited to a single delay duration per parking queue. If you need varying delays, you need multiple parking queues (one per delay value) or the plugin.
The sorted set pattern. This is what Sidekiq, Resque, and dozens of background job frameworks use internally. ZADD with score equal to the delivery timestamp. A worker polls ZRANGEBYSCORE 0 now every second. Matching entries are atomically popped (ZPOPMIN in Redis 5+) and processed. Shopify processes 40M+ delayed jobs per day using this exact pattern.