Queue: Supabase vs Cloudflare
Tổng quan so sánh
┌─────────────────────────────────────────────────────────────────┐
│ QUEUE COMPARISON │
├────────────────────────────┬────────────────────────────────────┤
│ SUPABASE (pgmq) │ CLOUDFLARE QUEUE │
├────────────────────────────┼────────────────────────────────────┤
│ PostgreSQL extension │ Distributed message queue │
│ In-database │ Edge-native │
│ SQL operations │ JavaScript API │
│ ACID compliant │ Eventually consistent │
│ Included in plan │ Pay per operation │
└────────────────────────────┴────────────────────────────────────┘
So sánh chi tiết
| Tiêu chí |
Supabase Queue (pgmq) |
Cloudflare Queue |
| Kiến trúc |
PostgreSQL extension |
Distributed, edge-native |
| Độ trễ |
~10-50ms (DB round-trip) |
~1-5ms (edge) |
| Throughput |
Limited by DB connections |
Auto-scale, very high |
| Persistence |
ACID, durable |
Eventually consistent |
| Max message size |
~1GB (JSONB limit) |
128KB |
| Batch size |
Unlimited |
Max 100 messages |
| Retry |
Manual implementation |
Built-in với backoff |
| Dead Letter Queue |
Manual |
Built-in |
| Visibility timeout |
Configurable |
Configurable |
| Chi phí |
Included |
$0.40/million ops |
Supabase Queue (pgmq)
Ưu điểm
✅ ACID Transactions
- Message + DB update trong 1 transaction
- Không mất data khi crash
✅ Direct Database Access
- Query data khi process message
- Không cần external API calls
✅ Complex Logic
- Joins, aggregations trong consumer
- Full SQL power
✅ Cost
- Included trong Supabase plan
- Không extra cost
Nhược điểm
❌ Scalability
- Limited by database connections
- Single region
❌ Latency
- Database round-trip required
- Higher than edge solutions
❌ Manual Implementation
- Retry logic tự viết
- DLQ tự implement
❌ Monitoring
- Basic (job_run_details table)
- Không có built-in dashboard
Cloudflare Queue
Ưu điểm
✅ Performance
- Edge-native, global
- Very low latency
✅ Auto-scaling
- Handles traffic spikes
- No connection limits
✅ Built-in Features
- Automatic retries
- Dead letter queue
- Batch processing
✅ Integration
- Native với Workers
- Cron Triggers compatible
Nhược điểm
❌ Cost
- Pay per operation
- Can add up at scale
❌ Message Size
- Max 128KB
- Need external storage for large data
❌ No Direct DB Access
- Must call Supabase API
- Extra latency
❌ Eventually Consistent
- Not ACID
- Rare message loss possible
Architecture Comparison
Supabase Queue Flow
┌─────────────────────────────────────────────────────────────┐
│ SUPABASE QUEUE │
│ │
│ ┌─────────┐ ┌─────────┐ ┌─────────┐ │
│ │ Next.js │────▶│ pgmq │────▶│Consumer │ │
│ │ API │ │ (Queue) │ │(CF/Edge)│ │
│ └─────────┘ └────┬────┘ └────┬────┘ │
│ │ │ │
│ ▼ ▼ │
│ ┌─────────────────────┐ │
│ │ PostgreSQL │ │
│ │ (Same database) │ │
│ └─────────────────────┘ │
│ │
│ Transaction: enqueue + insert = atomic │
└─────────────────────────────────────────────────────────────┘
Cloudflare Queue Flow
┌─────────────────────────────────────────────────────────────┐
│ CLOUDFLARE QUEUE │
│ │
│ ┌─────────┐ ┌─────────┐ ┌─────────┐ │
│ │ Next.js │────▶│ Queue │────▶│Consumer │ │
│ │ Worker │ │ (CF) │ │ Worker │ │
│ └─────────┘ └─────────┘ └────┬────┘ │
│ │ │
│ ▼ │
│ ┌─────────────┐ │
│ │ Supabase │ │
│ │ API │ │
│ └─────────────┘ │
│ │
│ Distributed: high throughput, global │
└─────────────────────────────────────────────────────────────┘
Use Case: Email Notifications
Supabase Queue Approach
// Producer: Enqueue with database transaction
const { data: order, error } = await supabase
.rpc('create_order_with_notification', {
order_data: { ... },
notification: {
type: 'order_confirmation',
email: user.email,
}
});
// SQL Function (atomic operation)
CREATE FUNCTION create_order_with_notification(
order_data JSONB,
notification JSONB
) RETURNS orders AS $$
DECLARE
new_order orders;
BEGIN
-- Insert order
INSERT INTO orders (...) VALUES (...)
RETURNING * INTO new_order;
-- Enqueue notification (same transaction)
PERFORM pgmq.send('email_queue', notification);
RETURN new_order;
END;
$$ LANGUAGE plpgsql;
Cloudflare Queue Approach
// Producer: Separate operations
export async function POST(request: Request) {
const { env } = getRequestContext();
// Create order
const { data: order } = await supabase
.from('orders')
.insert({ ... })
.select()
.single();
// Enqueue notification (separate)
await env.EMAIL_QUEUE.send({
type: 'order_confirmation',
email: user.email,
orderId: order.id,
});
return Response.json(order);
}
// Consumer: Process queue
export default {
async queue(batch: MessageBatch) {
for (const msg of batch.messages) {
await sendEmail(msg.body);
msg.ack();
}
}
};
Use Case: High-throughput Event Processing
Supabase Queue (NOT recommended)
// ❌ Will hit connection limits
for (const event of events) { // 10,000 events
await supabase.rpc('pgmq_send', {
queue: 'events',
message: event,
});
}
// Slow, may timeout, connection exhaustion
Cloudflare Queue (Recommended)
// ✅ Designed for high throughput
export async function POST(request: Request) {
const { env } = getRequestContext();
const events = await request.json();
// Batch send (efficient)
await env.EVENT_QUEUE.sendBatch(
events.map(e => ({ body: e }))
);
return Response.json({ queued: events.length });
}
// Consumer with batch processing
export default {
async queue(batch: MessageBatch) {
// Process up to 100 messages at once
const results = await Promise.all(
batch.messages.map(msg => processEvent(msg.body))
);
batch.ackAll();
}
};
Decision Matrix
Chọn Supabase Queue khi:
┌─────────────────────────────────────────────────────────────┐
│ ✅ Cần ACID transactions với database operations │
│ ✅ Volume thấp-trung bình (< 1000 msgs/min) │
│ ✅ Consumer cần query database phức tạp │
│ ✅ Không muốn thêm chi phí │
│ ✅ Data locality quan trọng (cùng region với DB) │
└─────────────────────────────────────────────────────────────┘
Chọn Cloudflare Queue khi:
┌─────────────────────────────────────────────────────────────┐
│ ✅ High throughput (> 1000 msgs/min) │
│ ✅ Low latency critical │
│ ✅ Global distribution cần thiết │
│ ✅ Simple processing (không cần complex DB queries) │
│ ✅ Cần built-in retry và DLQ │
│ ✅ External API calls (webhooks, notifications) │
└─────────────────────────────────────────────────────────────┘
Hybrid Approach
Best of Both Worlds
┌─────────────────────────────────────────────────────────────┐
│ HYBRID ARCHITECTURE │
│ │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ Cloudflare Queue (Entry) │ │
│ │ High throughput, global ingestion │ │
│ └────────────────────────┬────────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ Worker (Batch) │ │
│ │ Aggregate, validate, transform │ │
│ └────────────────────────┬────────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ Supabase pgmq (Processing) │ │
│ │ Complex DB operations, transactions │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────┘
Tổng kết
Quick Reference
| Scenario |
Recommendation |
| Order + Notification (transactional) |
Supabase |
| Webhook delivery |
Cloudflare |
| High-volume events |
Cloudflare |
| Complex data processing |
Supabase |
| Global users, low latency |
Cloudflare |
| Simple CRUD background |
Either |
Key Takeaways
- Supabase = Transactional, DB-integrated, lower throughput
- Cloudflare = Distributed, high-throughput, edge-native
- Hybrid = Use both for complex architectures
Q&A
- Dự án của bạn cần throughput như thế nào?
- Có cần transactional guarantees không?
- Consumer logic có phức tạp không?