Bỏ qua

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

// ❌ 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
// ✅ 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

  1. Supabase = Transactional, DB-integrated, lower throughput
  2. Cloudflare = Distributed, high-throughput, edge-native
  3. Hybrid = Use both for complex architectures

Q&A

  1. Dự án của bạn cần throughput như thế nào?
  2. Có cần transactional guarantees không?
  3. Consumer logic có phức tạp không?