Modul 08Term 3 · Reliabilitas dan skala10 item poster

Async, Event, dan Real-Time

Masuk untuk menyimpan progres Anda di semua perangkat. Sampai saat itu, progres disimpan di browser ini.

Mengapa ini penting

Mengirim email, membuat PDF, memanggil agen LLM, memproses webhook: jika semua ini berjalan di dalam request pengguna, request menjadi lambat, terkena timeout karena batas serverless, dan kehilangan pekerjaan setiap kali terjadi crash. Desain async adalah cara sistem yang serius tetap cepat dan tidak kehilangan apa pun.

Capaian pembelajaran

  1. Memindahkan pekerjaan yang lambat atau tidak andal ke background job yang durable.
  2. Memilih antara queue, pub/sub, dan desain event-driven.
  3. Menangani webhook dengan aman (verifikasi, dedupe, ack cepat, proses secara async).
  4. Mengoordinasikan workflow multi-langkah dengan saga dan outbox pattern.
  5. Memilih transport real-time yang tepat: WebSockets, SSE, atau long polling.
  6. Menjalankan scheduled job yang aman jika tumpang tindih dan aman jika terlewat.

Materi

8.1 Queue dan worker (15)

Polanya: request memvalidasi, menulis intent ke DB, memasukkan job ke queue, mengembalikan 202 Accepted dengan job ID. Worker memproses, memperbarui status, memberi notifikasi.

  • Dalam praktiknya, pengiriman bersifat at-least-once: rancang setiap job handler agar idempotent.
  • Pilihan: managed (SQS, Cloud Tasks), berbasis Redis (BullMQ), berbasis Postgres (pg-boss, Graphile Worker), durable workflow engine (Inngest, Trigger.dev, Temporal).
  • Durable workflow engine sering kali paling cocok untuk agen AI: setiap langkah di-checkpoint dan di-retry secara independen.

8.2 Pub/Sub dan arsitektur event-driven (16, 17)

  • Queue: satu pesan, satu consumer (tugas yang harus dikerjakan).
  • Pub/Sub: satu event, banyak subscriber independen (fakta yang sudah terjadi: order.paid).
  • Event-driven: service bereaksi terhadap event alih-alih saling memanggil secara langsung. Lebih terlepas (decoupled), tapi lebih sulit dilacak; membutuhkan schema untuk event dan observability yang baik.
  • Beri nama event dalam bentuk lampau; beri versi pada schema event; sertakan event ID untuk dedupe.

8.3 Transaksi terdistribusi, outbox, dan saga (18, 19)

  • Anda tidak bisa punya satu transaksi ACID yang mencakup DB Anda, Stripe, dan penyedia email.
  • Transactional outbox: dalam transaksi DB yang sama, tulis perubahan bisnis dan satu baris outbox; sebuah relay mempublikasikan baris-baris outbox. Mencegah kasus "tersimpan tapi tidak pernah dipublikasikan" atau "dipublikasikan tapi tidak tersimpan."
  • Saga: rangkaian langkah lokal yang masing-masing punya compensating action (reservasi stok → tagih kartu → buat pengiriman; jika pengiriman gagal: refund, lepas stok). Diorkestrasi (ada koordinator) atau dikoreografikan (lewat event).
  • Two-phase commit memang ada, tapi jarang tepat untuk sistem web modern.

8.4 Webhook (101)

Menerima:

  1. Verifikasi tanda tangan (HMAC dengan shared secret) dan timestamp untuk mencegah pemalsuan dan replay.
  2. Dedupe berdasarkan event ID dari penyedia (unique constraint).
  3. Ack cepat (2xx dalam hitungan detik), lalu proses di background job.
  4. Tangani pengiriman yang urutannya acak; ambil state terkini dari penyedia jika ragu. Mengirim: tanda tangani payload, retry dengan backoff, sediakan log pengiriman dan fitur replay untuk pelanggan, lindungi dari SSRF pada URL yang diberikan pelanggan.

8.5 Cron job (21)

  • Asumsikan sebuah eksekusi bisa terlewat, tertunda, atau berjalan dua kali. Buat job yang idempotent dan bisa dilanjutkan.
  • Cegah tumpang tindih dengan lock (DB advisory lock).
  • Proses per batch dengan checkpoint, bukan satu transaksi raksasa.
  • Pantau dengan heartbeat "dead man's switch" (alert jika job tidak berjalan).
  • Simpan jadwal dalam UTC; waspadai daylight saving di pasar lain.

8.6 Transport real-time (22, 23, 24)

Transport Arah Gunakan saat
SSE Server ke klien Streaming token LLM, notifikasi, progres. Sederhana, berjalan di atas HTTP, reconnect otomatis
WebSockets Dua arah Chat, kolaborasi, game live, suara
Long polling Push simulasi Fallback ketika streaming diblokir
Pertimbangan: autentikasi koneksi, otorisasi ulang pada koneksi berumur panjang, tangani reconnect dan pesan yang terlewat (lanjutkan dari event ID terakhir), platform serverless bisa membatasi durasi koneksi; gunakan layanan real-time terkelola (Supabase Realtime, Pusher, Ably, Cloudflare Durable Objects) saat skala membesar.

Lab 8: Jadikan async

  1. Pindahkan operasi sinkron Anda yang paling lambat (panggilan LLM, PDF, email) ke durable job dengan polling status atau progres lewat SSE.
  2. Implementasikan penerima webhook (Stripe atau Resend) dengan verifikasi tanda tangan, dedupe, dan pemrosesan async. Putar ulang event yang sama 10 kali; buktikan efeknya hanya satu.
  3. Implementasikan saga 3 langkah dengan kompensasi; suntikkan kegagalan di langkah 3; buktikan rollback.
  4. Tambahkan cron job dengan lock anti-tumpang tindih dan alert heartbeat.

Definition of Done

Paket prompt AI

  • "Identifikasi setiap operasi di request handler yang memanggil service eksternal atau bisa memakan waktu lebih dari 1 detik. Usulkan mana yang perlu dipindah ke background job."
  • "Implementasikan webhook handler ini: verifikasi tanda tangan dengan constant-time compare, tolak timestamp kedaluwarsa, dedupe berdasarkan event id dengan unique constraint, masukkan pemrosesan ke queue, kembalikan 200."