Transactional Outbox Pattern: Menjaga Konsistensi Database dan Event

Aplikasi modern sering perlu melakukan dua hal setelah sebuah tindakan terjadi: menyimpan perubahan ke database dan memberi tahu layanan lain melalui event. Contohnya, ketika pesanan dibuat, sistem menyimpan pesanan lalu mengirim event agar layanan stok, pembayaran, atau notifikasi dapat bekerja. Masalah muncul karena penyimpanan database dan pengiriman event biasanya merupakan dua operasi terpisah. Jika salah satunya berhasil sementara yang lain gagal, data antarlayanan bisa tidak sinkron.

Transactional outbox pattern membantu mengurangi risiko tersebut dengan menyimpan perubahan bisnis dan catatan event dalam satu transaksi database. Event kemudian dikirim oleh proses terpisah. Pola ini tidak membuat jaringan bebas gangguan, tetapi memberi sistem sumber kebenaran yang dapat dipulihkan ketika proses pengiriman gagal.

Mengapa Dua Operasi Terpisah Bisa Bermasalah?

Bayangkan layanan pesanan menyimpan pesanan baru, lalu memanggil broker pesan atau endpoint layanan lain. Jika database sudah melakukan commit tetapi koneksi terputus sebelum event terkirim, pesanan ada di sistem utama, sementara layanan lain tidak mengetahuinya. Sebaliknya, jika event dikirim lebih dahulu lalu transaksi database gagal, layanan penerima mungkin bertindak berdasarkan perubahan yang sebenarnya tidak pernah tersimpan.

Masalah ini sering disebut dual write: aplikasi menulis ke dua sistem yang tidak berbagi satu transaksi atomik. Menambahkan retry saja tidak selalu menyelesaikannya, karena aplikasi mungkin tidak tahu operasi mana yang sudah berhasil. Pengulangan tanpa rancangan idempotensi juga dapat memicu efek ganda.

Bagaimana Transactional Outbox Bekerja?

Pola ini menambahkan tabel outbox di database aplikasi. Dalam satu transaksi, aplikasi menyimpan perubahan bisnis sekaligus memasukkan event ke tabel tersebut. Karena keduanya berada dalam transaksi database yang sama, keduanya sama-sama commit atau sama-sama dibatalkan.

  1. Terima perintah bisnis. Misalnya, pengguna membuat pesanan.
  2. Simpan perubahan dan event. Aplikasi memasukkan pesanan ke tabel utama serta mencatat event seperti OrderCreated ke tabel outbox dalam satu transaksi.
  3. Commit transaksi. Jika penyimpanan gagal, catatan outbox ikut dibatalkan. Jika berhasil, event tetap tersimpan meskipun layanan pengirim sedang tidak tersedia.
  4. Kirim event secara terpisah. Proses relay membaca catatan yang belum terkirim, menerbitkannya ke broker atau layanan tujuan, lalu menandai catatan sesuai mekanisme yang digunakan.

Dengan demikian, aplikasi bisnis tidak harus bergantung pada keberhasilan jaringan saat transaksi utama berlangsung. Pengiriman dapat dilanjutkan setelah gangguan pulih, selama catatan outbox masih tersedia dan proses relay berjalan benar.

Contoh: Membuat Pesanan di Toko Online

Misalkan pelanggan memesan satu produk. Layanan pesanan menulis data pesanan dan event OrderCreated dalam satu transaksi. Setelah commit, relay menerbitkan event. Layanan inventaris menerima event untuk memperbarui stok, sedangkan layanan notifikasi mengirim konfirmasi kepada pelanggan.

Jika broker sedang tidak dapat diakses, pesanan tidak perlu dibatalkan hanya karena notifikasi gagal dikirim. Catatan event tetap berada di outbox dan dapat diproses ketika koneksi pulih. Namun, tim harus memantau usia catatan tertua yang belum terkirim agar keterlambatan tidak luput dari perhatian.

Pengiriman Ulang dan Duplikasi Tetap Harus Ditangani

Transactional outbox tidak otomatis menjamin setiap event diproses tepat satu kali. Contohnya, relay berhasil mengirim event, tetapi gagal menyimpan penanda bahwa pengiriman selesai. Saat berjalan kembali, relay mungkin mengirim event yang sama. Karena itu, desain yang realistis biasanya mengantisipasi pengiriman setidaknya satu kali dan membuat konsumen tahan terhadap duplikasi.

Berikan setiap event ID unik, simpan ID yang sudah diproses pada konsumen bila sesuai, dan pastikan efek bisnis tidak dijalankan berulang untuk event yang sama. Prinsip ini berkaitan dengan idempotensi pada API, meskipun penerapannya pada konsumen event perlu disesuaikan dengan model data dan transaksi yang digunakan.

Jika event gagal diproses setelah sejumlah percobaan, kebijakan retry dan jalur pemulihan harus jelas. Dead Letter Queue dapat membantu mengisolasi pesan bermasalah, tetapi bukan pengganti pencatatan error dan prosedur pemulihan yang aman.

Memilih Cara Mengirim Event: Polling atau CDC

Polling relay secara berkala mencari catatan outbox yang belum diproses. Cara ini relatif mudah dipahami dan dapat dimulai dengan query database sederhana. Kekurangannya, polling terlalu sering menambah beban, sedangkan interval terlalu panjang meningkatkan latensi. Gunakan indeks pada status dan waktu pembuatan, serta batasi jumlah baris yang diambil setiap siklus.

Change Data Capture (CDC) membaca perubahan database melalui log perubahan atau mekanisme yang didukung platform. Pendekatan ini dapat mengurangi kebutuhan polling, tetapi menambah komponen dan persyaratan operasional. Tim perlu memahami dukungan database, urutan event, retensi log, pemulihan posisi baca, serta cara menangani perubahan skema. Tidak ada pilihan yang selalu terbaik; pilih berdasarkan volume, target latensi, dan kemampuan tim mengelolanya.

Hal yang Perlu Dirancang Sejak Awal

  • Struktur event: sertakan ID unik, jenis event, waktu, versi skema, dan referensi entitas. Hindari memasukkan data pribadi berlebihan.
  • Status pengiriman: tentukan cara mencatat percobaan, waktu retry berikutnya, dan waktu berhasil tanpa menghapus bukti kegagalan terlalu cepat.
  • Urutan: jika urutan perubahan penting, tentukan kunci pengurutan dan perilaku konsumen ketika event datang terlambat.
  • Retensi: bersihkan catatan yang sudah selesai sesuai kebijakan, tetapi pertahankan data yang dibutuhkan untuk audit dan pemulihan.
  • Observabilitas: pantau jumlah backlog, usia event tertua, tingkat kegagalan, durasi pengiriman, dan jumlah retry.
  • Keamanan: batasi akses tabel outbox, lindungi kredensial relay, dan gunakan autentikasi serta enkripsi pada jalur pengiriman. Jika event dikirim melalui webhook, terapkan validasi penerima seperti dijelaskan dalam panduan keamanan webhook.

Kapan Pola Ini Layak Digunakan?

Outbox berguna ketika perubahan database harus memicu pekerjaan di layanan lain dan kehilangan event tidak dapat diterima, misalnya pada pesanan, pembayaran, inventaris, atau sinkronisasi antarlayanan. Pola ini menambah tabel, relay, pemantauan, dan prosedur pemulihan, sehingga mungkin berlebihan untuk aplikasi sederhana yang tidak membutuhkan pemrosesan asinkron.

Sebelum menerapkannya, tentukan apa yang terjadi jika relay berhenti berjam-jam, bagaimana event yang gagal dipulihkan, dan bagaimana konsumen mencegah efek ganda. Uji juga skenario crash setelah commit, setelah publish, dan sebelum status pengiriman diperbarui.

Kesimpulan

Transactional outbox menyatukan perubahan bisnis dan catatan event dalam satu transaksi database, lalu memisahkan pengiriman event ke proses relay. Pola ini mengurangi risiko ketidaksinkronan akibat dual write, tetapi tetap membutuhkan retry yang terukur, konsumen idempoten, pemantauan backlog, serta prosedur pemulihan. Rancang berdasarkan kebutuhan konsistensi dan kemampuan operasional, bukan sekadar menambah komponen arsitektur.

PENGALAMAN BARU Coba tampilan baru Penasaran dengan pengalaman membaca Nazuaf versi modern? Coba tampilan baru yang dirancang agar nyaman dibaca dari ponsel dan pc. Buka versi modern dan lanjutkan membaca artikel ini. Jelajahi tampilan baru Nazuaf versi modern · Ketuk kartu untuk mencoba

Bagikan artikel ini

Tinggalkan komentar

Server Load: 26% · CMH · ⚡ --ms