Message Contract #
Dalam sistem berbasis RabbitMQ, message sering dianggap hanya sebagai payload JSON biasa.
Padahal secara arsitektural, message adalah:
- Kontrak antar service
- API asynchronous
- Representasi fakta bisnis
Kesalahan dalam mendesain message contract dapat menyebabkan:
- Breaking change antar service
- DLQ meningkat tiba-tiba
- Retry storm
- Ketergantungan implisit yang tidak terdokumentasi
Karena itu, message contract harus diperlakukan dengan disiplin yang sama seperti API HTTP publik.
“Event yang dikirim hari ini bisa menjadi fondasi sistem bertahun-tahun ke depan — atau menjadi sumber kerusakan yang tidak pernah selesai.”
Apa Itu Message Contract? #
Message contract adalah definisi formal mengenai:
- Nama event
- Routing key
- Struktur payload
- Field wajib dan opsional
- Tipe data
- Versi
- Ownership
Ia menjawab pertanyaan:
“Apa yang boleh dan tidak boleh ada dalam message ini?”
Tanpa kontrak yang jelas, integrasi antar service menjadi rapuh.
Mengapa Message Contract Sangat Penting di RabbitMQ? #
Berbeda dengan REST API:
- Tidak ada schema validation otomatis
- Tidak ada HTTP status code
- Tidak ada OpenAPI default
Jika producer mengubah struktur payload tanpa koordinasi:
- Consumer bisa crash
- Message masuk DLQ
- Sistem terhenti sebagian
Dalam sistem asynchronous, kesalahan sering terlihat terlambat.
Elemen Penting dalam Message Contract #
1️⃣ Naming Convention Event #
Gunakan pola konsisten, misalnya:
- order.created
- payment.completed
- user.registered
Hindari nama ambigu seperti:
- process
- update
- event1
Nama event adalah identitas domain.
2️⃣ Struktur Payload yang Jelas #
Tentukan:
- Field wajib
- Field opsional
- Tipe data
- Format tanggal (ISO 8601)
- Enum yang diperbolehkan
Contoh:
{
"event_id": "uuid",
"event_version": 1,
"occurred_at": "2026-02-20T10:00:00Z",
"order_id": "string",
"status": "CREATED"
}
Struktur harus terdokumentasi.
3️⃣ Versioning Strategy #
Schema akan berubah.
Pertanyaannya bukan apakah berubah, tetapi kapan.
Strategi umum:
- Tambahkan field baru (backward compatible)
- Hindari menghapus field lama
- Gunakan
event_version - Gunakan routing key versioned jika perlu
Contoh:
- order.created.v1
- order.created.v2
Backward compatibility adalah kunci stabilitas.
4️⃣ Ownership Jelas #
Setiap event harus memiliki:
- Producer owner
- Domain owner
Jika tidak jelas siapa pemilik kontrak, perubahan menjadi tidak terkontrol.
5️⃣ Idempotency Awareness #
Karena RabbitMQ default adalah at-least-once delivery:
- Duplicate message bisa terjadi
Message contract harus mengandung identifier unik seperti:
- event_id
- order_id
- correlation_id
Consumer harus mampu mendeteksi duplicate.
Anti-Pattern dalam Message Contract #
Beberapa kesalahan umum:
- Mengirim seluruh entity database apa adanya
- Mengubah struktur payload tanpa versioning
- Menghapus field lama secara tiba-tiba
- Tidak mendokumentasikan event
- Menggunakan field ambigu
Message contract yang tidak disiplin adalah sumber integrasi yang rapuh.
Message Contract dan DLQ #
Banyak message masuk DLQ karena:
- Field hilang
- Tipe berubah
- Enum tidak dikenali
DLQ sering kali adalah indikator bahwa kontrak tidak dikelola dengan baik.
Monitoring DLQ dapat menjadi alarm perubahan kontrak yang tidak kompatibel.
Dokumentasi dan Validasi #
Beberapa pendekatan yang bisa digunakan:
- JSON Schema
- Avro
- Protobuf
- Internal contract registry
Validasi bisa dilakukan:
- Di sisi producer sebelum publish
- Di sisi consumer sebelum proses
Schema validation mengurangi kesalahan runtime.
Perbandingan: Tanpa vs Dengan Contract Discipline #
| Tanpa Kontrak Jelas | Dengan Kontrak Jelas |
|---|---|
| Breaking change sering | Stabil jangka panjang |
| DLQ meningkat tiba-tiba | Error terkontrol |
| Integrasi sulit | Integrasi predictable |
| Coupling implisit | Boundary jelas |
Kontrak adalah boundary antar service.
Prinsip Message Contract yang Sehat #
- Treat event as public API
- Hindari breaking change
- Version dengan disiplin
- Dokumentasikan payload
- Gunakan identifier unik
- Monitor DLQ sebagai indikator kontrak rusak
Messaging tanpa kontrak adalah integrasi tanpa pagar.
Ringkasan #
Message contract menentukan:
- Stabilitas antar service
- Kejelasan domain
- Ketahanan terhadap perubahan
- Kemudahan scaling tim
Ia bukan detail kecil. Ia adalah fondasi arsitektur asynchronous.
Penutup #
RabbitMQ memindahkan pesan.
Tetapi pesan itu sendiri membawa makna bisnis.
Jika makna tersebut tidak didefinisikan dengan jelas, sistem akan rapuh terhadap perubahan.
Message contract adalah janji antar service.
Janji itu harus dijaga dengan disiplin, versioning yang matang, dan dokumentasi yang jelas.
Karena dalam sistem terdistribusi, kegagalan sering kali bukan karena jaringan putus.
Tetapi karena kontrak yang dilanggar tanpa disadari.