At-least-once #
Dalam sistem messaging, salah satu keputusan arsitektural paling penting adalah memilih delivery guarantee.
RabbitMQ secara default dirancang untuk mendukung pola:
At-Least-Once Delivery
Artinya:
- Setiap message dijamin akan dikirim minimal satu kali
- Tetapi mungkin dikirim lebih dari satu kali
Artikel ini membahas secara mendalam bagaimana at-least-once bekerja di RabbitMQ, bagaimana ia dicapai, risiko duplicate, dan bagaimana mendesain sistem yang aman terhadapnya.
“Lebih baik menerima dua kali daripada tidak pernah menerima sama sekali — tetapi konsekuensinya harus disiapkan.”
Apa Itu At-Least-Once Delivery? #
At-least-once berarti:
- Message tidak akan hilang selama sistem dikonfigurasi dengan benar
- Jika terjadi kegagalan sebelum ack diterima broker
- Message akan dikirim ulang
Dengan kata lain:
Tidak ada silent data loss.
Namun ada kemungkinan duplicate.
Bagaimana RabbitMQ Mencapai At-Least-Once? #
Ada dua komponen penting:
- Manual acknowledgment (manual ack)
- Persistent message + durable queue (opsional untuk durability lebih tinggi)
Alur dasar:
1️⃣ Producer publish message
2️⃣ Broker menyimpan message
3️⃣ Broker mengirim ke consumer
4️⃣ Consumer memproses
5️⃣ Consumer mengirim basic.ack
6️⃣ Broker menghapus message
Jika sebelum langkah 5 terjadi crash:
- Message dianggap belum selesai
- Akan dikirim ulang
Skenario Duplicate Terjadi #
Duplicate dapat terjadi jika:
1️⃣ Consumer Crash Setelah Proses, Sebelum Ack #
- Message sudah diproses
- Tetapi ack belum terkirim
- Broker menganggap belum selesai
- Message dikirim ulang
2️⃣ Network Partition #
- Ack terkirim tetapi tidak diterima broker
- Broker mengirim ulang
3️⃣ Channel Ditutup Mendadak #
- Unacked message dikembalikan ke queue
Semua ini adalah konsekuensi desain at-least-once.
Kenapa At-Least-Once Dipilih Sebagai Default? #
Karena dalam sistem terdistribusi:
- Kehilangan message biasanya lebih berbahaya daripada duplicate
Contoh:
- Payment event hilang → fatal
- Payment event diproses dua kali → bisa dicegah dengan idempotency
At-least-once memprioritaskan reliability dibanding kemurnian single execution.
Konsekuensi: Consumer Harus Idempotent #
Karena duplicate mungkin terjadi:
Consumer harus dirancang agar:
- Aman dipanggil lebih dari sekali
- Tidak menghasilkan efek samping ganda
Strategi umum:
1️⃣ Gunakan Unique Event ID #
Setiap message memiliki:
- event_id (UUID)
Simpan event_id yang sudah diproses.
Jika event_id sama muncul lagi → abaikan.
2️⃣ Gunakan Constraint Database #
Contoh:
- Unique constraint pada transaction_id
- Insert dengan upsert
Duplicate akan ditolak oleh database.
3️⃣ Gunakan Idempotent Business Logic #
Contoh:
- Update status berdasarkan state machine
- Hindari increment tanpa check
Idempotency adalah pasangan alami at-least-once.
Peran Publisher Confirm #
Untuk memastikan message benar-benar diterima broker:
Gunakan publisher confirm.
Alur:
1️⃣ Producer publish 2️⃣ Broker menyimpan message 3️⃣ Broker mengirim confirm
Jika tidak ada confirm:
- Producer bisa retry
Ini memperkuat at-least-once dari sisi producer.
At-Least-Once + Quorum Queue #
Jika menggunakan quorum queue:
- Message direplikasi ke mayoritas node
- Ack hanya dikirim setelah commit mayoritas
Ini meningkatkan jaminan durability.
Namun duplicate tetap mungkin terjadi.
Quorum meningkatkan ketahanan fisik, bukan menghilangkan duplicate.
Perbandingan Delivery Guarantee #
| Guarantee | Bisa Hilang? | Bisa Duplicate? |
|---|---|---|
| At-Most-Once | Ya | Tidak |
| At-Least-Once | Tidak (dengan konfigurasi benar) | Ya |
| Exactly-Once | Tidak | Tidak (secara teoretis, sulit di praktik) |
RabbitMQ secara natural berada pada spektrum at-least-once.
Kesalahan Umum #
Beberapa kesalahan ketika menggunakan at-least-once:
- Tidak menggunakan manual ack
- Tidak membuat consumer idempotent
- Tidak menyimpan event_id
- Mengasumsikan tidak akan ada duplicate
Duplicate bukan bug.
Ia adalah konsekuensi desain.
Kapan At-Least-Once Cocok? #
Hampir semua workload bisnis:
- Order
- Payment
- Inventory
- Notification
Lebih aman kehilangan idempotency daripada kehilangan data.
Ringkasan #
At-least-once dalam RabbitMQ berarti:
- Message dijamin sampai
- Tetapi mungkin lebih dari sekali
- Consumer harus idempotent
- Publisher confirm memperkuat jaminan
- Quorum meningkatkan durability
At-least-once adalah keseimbangan antara reliability dan kompleksitas.
Penutup #
Dalam sistem terdistribusi, tidak ada jaminan tanpa tradeoff.
At-least-once memilih untuk tidak kehilangan pesan.
Sebagai gantinya, ia menuntut kita untuk siap menghadapi duplicate.
Arsitektur yang matang tidak mencoba menghindari tradeoff.
Ia memahami tradeoff tersebut dan mendesain sistem yang tahan terhadapnya.
Karena dalam dunia messaging, kepastian bahwa pesan sampai sering kali jauh lebih penting daripada kepastian bahwa ia hanya sampai sekali.