Decision Framework
Queue vs Cron: Khi nào dùng gì?
Fundamental Difference
┌─────────────────────────────────────────────────────────────┐
│ QUEUE vs CRON │
├────────────────────────────┬────────────────────────────────┤
│ QUEUE │ CRON │
├────────────────────────────┼────────────────────────────────┤
│ Event-driven │ Time-driven │
│ "Do this when triggered" │ "Do this at specific time" │
│ Async processing │ Scheduled execution │
│ Variable load │ Predictable load │
└────────────────────────────┴────────────────────────────────┘
Decision Flowchart: Queue
┌─────────────────────────────────────────────────────────────┐
│ WHEN TO USE QUEUE? │
├─────────────────────────────────────────────────────────────┤
│ │
│ ┌──────────────────────────────────────────────────────┐ │
│ │ Is the task triggered by a user action or event? │ │
│ └────────────────────────┬─────────────────────────────┘ │
│ │ │
│ YES ───┴─── NO │
│ │ │ │
│ ▼ ▼ │
│ Consider Consider CRON │
│ QUEUE │
│ │ │
│ ▼ │
│ ┌──────────────────────────────────────────────────────┐ │
│ │ Does it need to complete after HTTP response? │ │
│ └────────────────────────┬─────────────────────────────┘ │
│ │ │
│ YES ───┴─── NO │
│ │ │ │
│ ▼ ▼ │
│ QUEUE Sync OK │
│ │
└─────────────────────────────────────────────────────────────┘
Queue Use Cases
| Trigger |
Example |
Why Queue? |
| User signup |
Send welcome email |
Don't block registration |
| Order placed |
Process payment |
Retry if fails |
| File uploaded |
Generate thumbnail |
Heavy processing |
| Comment posted |
Send notification |
Multiple recipients |
| Form submitted |
Validate data |
External API calls |
Decision Flowchart: Cron
┌─────────────────────────────────────────────────────────────┐
│ WHEN TO USE CRON? │
├─────────────────────────────────────────────────────────────┤
│ │
│ ┌──────────────────────────────────────────────────────┐ │
│ │ Does the task need to run at specific times? │ │
│ └────────────────────────┬─────────────────────────────┘ │
│ │ │
│ YES ───┴─── NO │
│ │ │ │
│ ▼ ▼ │
│ Consider Consider QUEUE │
│ CRON or Sync │
│ │ │
│ ▼ │
│ ┌──────────────────────────────────────────────────────┐ │
│ │ Is it independent of user actions? │ │
│ └────────────────────────┬─────────────────────────────┘ │
│ │ │
│ YES ───┴─── NO │
│ │ │ │
│ ▼ ▼ │
│ CRON Maybe Queue │
│ │
└─────────────────────────────────────────────────────────────┘
Cron Use Cases
| Schedule |
Example |
Why Cron? |
| Daily 2AM |
Cleanup old data |
Off-peak maintenance |
| Hourly |
Update statistics |
Regular aggregation |
| Daily 9AM |
Send digest emails |
User expectation |
| Weekly |
Generate reports |
Scheduled delivery |
| Monthly |
Archive old records |
Periodic maintenance |
For Queue
┌─────────────────────────────────────────────────────────────┐
│ SUPABASE vs CLOUDFLARE QUEUE │
├─────────────────────────────────────────────────────────────┤
│ │
│ ┌──────────────────────────────────────────────────────┐ │
│ │ Does consumer need complex DB queries/transactions? │ │
│ └────────────────────────┬─────────────────────────────┘ │
│ │ │
│ YES ────────┴──────── NO │
│ │ │ │
│ ▼ ▼ │
│ Supabase ┌───────────────────────┐ │
│ pgmq │ High throughput │ │
│ │ (>1000 msg/min)? │ │
│ └───────────┬───────────┘ │
│ │ │
│ YES ─────────┴──────── NO │
│ │ │ │
│ ▼ ▼ │
│ Cloudflare Either OK │
│ Queue │
│ │
└─────────────────────────────────────────────────────────────┘
For Cron
┌─────────────────────────────────────────────────────────────┐
│ SUPABASE vs CLOUDFLARE CRON │
├─────────────────────────────────────────────────────────────┤
│ │
│ ┌──────────────────────────────────────────────────────┐ │
│ │ Is task primarily database operations? │ │
│ └────────────────────────┬─────────────────────────────┘ │
│ │ │
│ YES ────────┴──────── NO │
│ │ │ │
│ ▼ ▼ │
│ Supabase ┌───────────────────────┐ │
│ pg_cron │ Needs external APIs? │ │
│ └───────────┬───────────┘ │
│ │ │
│ YES ─────────┴──────── NO │
│ │ │ │
│ ▼ ▼ │
│ Cloudflare pg_cron OK │
│ Cron Triggers │
│ │
└─────────────────────────────────────────────────────────────┘
Complete Decision Matrix
┌─────────────────────────────────────────────────────────────────────┐
│ COMPLETE DECISION MATRIX │
├────────────────────┬────────────────────┬───────────────────────────┤
│ Scenario │ Technology │ Platform │
├────────────────────┼────────────────────┼───────────────────────────┤
│ Email after signup │ Queue │ Cloudflare (external API) │
│ Payment processing │ Queue │ Cloudflare (retry needed) │
│ Webhook delivery │ Queue │ Cloudflare (external API) │
│ Order + notify │ Queue │ Supabase (transactional) │
│ Thumbnail gen │ Queue │ Cloudflare (compute) │
├────────────────────┼────────────────────┼───────────────────────────┤
│ Cleanup old data │ Cron │ Supabase (DB operation) │
│ Daily digest │ Cron │ Cloudflare (email API) │
│ Update statistics │ Cron │ Supabase (aggregation) │
│ Sync external data │ Cron │ Cloudflare (API calls) │
│ Generate reports │ Cron │ Supabase (DB queries) │
├────────────────────┼────────────────────┼───────────────────────────┤
│ Batch processing │ Cron + Queue │ CF Cron → CF Queue │
│ Scheduled notif │ Cron + Queue │ pg_cron → CF Queue │
│ DB maintenance + │ Cron + Queue │ pg_cron → pgmq │
│ notify admin │ │ │
└────────────────────┴────────────────────┴───────────────────────────┘
Quick Reference Card
Use QUEUE when:
✅ User action triggers async work
✅ Need retry on failure
✅ Want to respond fast to user
✅ Variable, unpredictable load
✅ Multiple consumers possible
✅ Decoupled architecture
Use CRON when:
✅ Time-based execution required
✅ Maintenance tasks
✅ Report generation
✅ Data synchronization
✅ Predictable, scheduled load
✅ No user waiting for result
Use Supabase (pgmq/pg_cron) when:
✅ Task is database-centric
✅ Need ACID transactions
✅ Complex SQL operations
✅ Data locality matters
✅ Included cost preference
Use Cloudflare (Queue/Cron) when:
✅ External API calls
✅ High throughput needed
✅ Complex JavaScript logic
✅ Global execution
✅ Workers integration
Anti-patterns to Avoid
❌ Wrong: Heavy DB work in Cloudflare Cron
// ❌ Multiple API calls for DB-heavy task
export default {
async scheduled() {
// This should be pg_cron!
const { data } = await supabase.from('table').select('*');
for (const row of data) {
await supabase.from('table').update({ ... }).eq('id', row.id);
}
}
};
❌ Wrong: External API in pg_cron
-- ❌ Complex HTTP in SQL
SELECT cron.schedule('send-emails', '0 * * * *',
'SELECT http_post(...) FROM users WHERE ...'
);
-- Hard to debug, error handling difficult
❌ Wrong: Queue for scheduled tasks
// ❌ Queue with artificial delay
await queue.send(
{ task: 'daily-report' },
{ delay: 86400 } // 24 hours
);
// Use Cron instead!
❌ Wrong: Cron for event-driven
-- ❌ Polling for new records
SELECT cron.schedule('check-new-orders', '* * * * *',
'SELECT process_new_orders()'
);
-- Use Queue triggered by INSERT instead!
Tổng kết
The Simple Rule
Event-driven? ──────────▶ QUEUE
Time-driven? ──────────▶ CRON
Database work? ─────────▶ SUPABASE
External APIs? ─────────▶ CLOUDFLARE
Hybrid is OK
- Cron triggers Queue (scheduled batches)
- Queue processes with Cron fallback (recovery)
- Both platforms can work together
Q&A
- Có scenario nào trong dự án khó quyết định?
- Đã thử hybrid approach chưa?
- Còn use case nào cần discuss?