Reliability

At-Least-Once Delivery dan Risiko Data Duplikat

Memahami mengapa pesan dapat dikirim lebih dari sekali, titik ambigu pada jaringan, dan strategi menjaga efek integrasi tetap aman.

Dalam integrasi terdistribusi, pengirim dapat kehilangan respons meskipun tujuan sudah memproses request. Agar pesan tidak hilang, sistem mengirim ulang. Konsekuensinya, tujuan mungkin menerima request yang sama lebih dari satu kali. Inilah trade-off utama at-least-once delivery.

Inti pembahasan At-least-once menjaga peluang pesan diproses, tetapi efek ganda harus dicegah melalui identitas stabil dan operasi idempoten.

Apa arti at-least-once?

At-least-once berarti sistem berusaha agar setiap pesan diproses sedikitnya satu kali. Bila status penyelesaian belum pasti, pesan dapat dicoba kembali. Model ini tidak menjamin hanya satu eksekusi. “Exactly once” pada seluruh jalur biasanya memerlukan koordinasi antara pengirim, transport, dan tujuan yang tidak selalu tersedia, terutama untuk API pihak ketiga dan email.

Pada NitroNet, delivery HTTP dan email menggunakan mekanisme retry. Penulisan database yang berada dalam satu transaksi lokal mempunyai boundary yang lebih kuat, tetapi request ulang pada eksekusi berbeda tetap membutuhkan identitas bisnis. Label sukses pada satu attempt tidak boleh disamakan dengan jaminan global bahwa efek hanya pernah terjadi sekali.

Di mana duplikasi dapat bermula?

  1. Pengirim mengirim request.

    Pesan mencapai tujuan dengan correlation ID tertentu.

  2. Tujuan menjalankan efek.

    Record dibuat, pembayaran diproses, atau email diterima server.

  3. Respons hilang.

    Koneksi terputus sebelum acknowledgment sampai ke pengirim.

  4. Pengirim melakukan retry.

    Tanpa idempotency key, tujuan melihatnya sebagai request baru.

Timeout tidak menjelaskan apakah efek terjadi. Menganggap timeout sebagai “pasti gagal” adalah sumber duplikasi yang umum. Menganggapnya “pasti sukses” juga berisiko kehilangan proses bila request sebenarnya tidak pernah sampai.

Duplikasi memiliki dampak yang berbeda

EfekRisiko duplikasiKontrol utama
Insert customerDua profilExternal ID unik
InvoiceTagihan gandaNomor/idempotency key
PembayaranDebit gandaProvider idempotency + rekonsiliasi
EmailNotifikasi berulangNotification ledger
Update statusMungkin amanSet nilai absolut, bukan increment

Operasi set status=paid dapat idempoten bila hasilnya sama setiap kali. Operasi balance=balance+amount tidak idempoten karena setiap retry menambah nilai lagi. Risiko harus dinilai dari efek tujuan, bukan hanya method HTTP.

Bangun perlindungan berlapis

  • Buat idempotency key dari identitas kejadian, bukan UUID baru pada setiap attempt.
  • Simpan key dan hasil pertama pada tujuan agar request ulang mengembalikan hasil yang sama.
  • Gunakan unique constraint sebagai pagar terakhir untuk insert database.
  • Terapkan deduplikasi pada ingress untuk mengurangi pemrosesan pesan yang sama.
  • Catat correlation ID, attempt, status, dan referensi tujuan untuk rekonsiliasi.

Deduplikasi pada workflow dan idempotensi pada tujuan saling melengkapi. Deduplikasi dapat memiliki TTL dan state yang hilang setelah retensi; idempotensi berbasis identitas bisnis di tujuan memberikan perlindungan pada boundary efek yang sebenarnya.

Contoh pengiriman pembayaran

Workflow menerima payment_request_id dari sistem pemilik. Nilai itu dipakai sebagai idempotency key saat memanggil provider, bukan dibuat ulang ketika retry. Bila provider timeout, workflow memeriksa kontrak provider: apakah request aman diulang dengan key yang sama atau status harus ditanyakan melalui endpoint inquiry.

Hasil provider disimpan bersama key dan correlation ID. Respons duplicate yang menunjuk transaksi pertama bukan selalu error; workflow dapat mengembalikan hasil sebelumnya setelah memverifikasi identitas dan nominal. Keputusan finansial tetap mengikuti kontrak provider dan rekonsiliasi yang dikelola pihak berwenang.

Skema penyimpanan idempotensi memerlukan keputusan: berapa lama key disimpan, status apa yang direkam ketika attempt masih berjalan, dan bagaimana request paralel ditahan. Pola yang aman biasanya membuat reservasi atomik untuk key, menyimpan fingerprint request, lalu menyimpan hasil final. Jika key yang sama datang dengan payload berbeda, tujuan sebaiknya menolak konflik alih-alih mengembalikan hasil yang tidak sesuai.

Rekonsiliasi tetap dibutuhkan untuk efek bernilai tinggi. Bandingkan ledger sumber, log delivery, dan referensi tujuan secara periodik. Jangan memakai timestamp sebagai satu-satunya identitas karena clock serta precision dapat berbeda. Simpan correlation ID yang tidak mengandung PII dan referensi bisnis yang dapat dicari oleh petugas berwenang. Dengan demikian, kasus ambigu dapat diselesaikan berdasarkan bukti, bukan dengan mencoba request berulang kali.

Uji dua request paralel dengan key sama, bukan hanya retry berurutan. Tujuan harus memastikan hanya satu eksekusi memperoleh hak memproses sementara yang lain menunggu atau menerima hasil konsisten. Catat apakah respons duplicate berisi referensi aman ke hasil pertama. Tanpa test concurrency, implementasi idempotensi dapat tetap memiliki race condition meskipun terlihat benar pada pengujian manual.

Batasan yang perlu dikomunikasikan

NitroNet tidak mengubah API eksternal menjadi exactly-once.

Retry eksternal bersifat at-least-once. Gunakan idempotency key bila didukung, desain inquiry/reconciliation, dan jangan menganggap timeout sebagai bukti sukses atau gagal.

Mekanisme penyangga dan antrean dapat menjaga pesan selama periode retensi, tetapi pesan yang melewati batas tetap perlu memiliki status gagal atau dihentikan yang terlihat. Pelajari kapan retry layak dilakukan dan risiko tiap operasi database untuk menyusun alur yang aman.

Bawa konsep ke kasus nyata

Sedang merancang integrasi lintas-sistem?

Petakan satu alur nyata bersama tim NitroNet untuk melihat posisi agent, Core, workflow, dan batas transaksinya.

Bahas arsitektur AndaKembali ke blog
Chat WhatsApp