Menangani webhook terlambat berarti memastikan layanan internal tetap konsisten walaupun pihak ketiga mengirim payload lama, tidak tertangani, atau gagal berulang. Dalam artikel ini, langsung akan dibahas cara mendesain kontrak webhook yang kuat, mengatur retry dengan batas waktu acknowledgments, serta menjaga idempotensi payload melalui deteksi duplikasi dan observability.
1. Mendesain Kontrak Webhook Tahan Kegagalan
Kontrak webhook adalah janji bersama antara layanan pengirim dan penerima. Kontrak yang tidak eksplisit menyebabkan ambiguity saat webhook telat atau gagal.
1.1 Payload dan Schema Versioning
Pastikan payload dideskripsikan dalam dokumen resmi (misalnya OpenAPI). Sertakan metadata berikut:
- event_type: string tetap untuk mengidentifikasi aksi.
- event_id: UUID unik untuk setiap event.
- timestamp: waktu pembuatan event di pengirim.
- schema_version: versi schema untuk evolusi payload.
Versi schema membolehkan perubahan struktural tanpa mematahkan konsumen. Konsumen harus mendukung fallback atau menolak payload dengan schema_version yang tidak dikenali, lalu mengirim respons 422 untuk memicu observability.
1.2 Otentikasi Signature
Tambahkan header seperti X-Hub-Signature yang dihitung menggunakan secret yang dibagi kedua pihak. Penerima menghitung ulang HMAC terhadap body untuk memastikan integritas payload.
Implementasi sample:
HMAC_SHA256(secret, body) == request.headers['X-Hub-Signature']
Hindari menyimpan secret dalam kode: gunakan vault atau secrets manager. Pastikan timestamp tidak kedaluwarsa lebih dari batas (misal 5 menit) untuk memitigasi replay attack.
2. Strategi Retry dan Acknowledgment
Mendefinisikan batas timeout untuk acknowledgement (ACK) membantu pengirim mengetahui kapan harus retry.
2.1 Timeout dan Acknowledgment
Penerima harus membalas dalam waktu yang wajar (misalnya 10 detik). Bila pemrosesan memakan waktu lebih lama, kirimkan 202 Accepted dengan header Retry-After agar pengirim tahu tidak perlu retry saat ini.
2.2 Retry dengan Backoff
Pengirim menerapkan retry berjenjang:
- Initial delay: 5 detik.
- Backoff: eksponensial (2x) hingga batas maksimum (misal 5 menit).
- Max attempts: tentukan sebelum memberikan status GREY/FAILED.
Backoff mencegah ping pong antara sistem ketika downstream terganggu. Bila status masih belum ACK setelah batas, kirim alert atau simpan state untuk manual recovery.
2.3 Tabel Status Retry
| Status | Deskripsi | Tindakan |
|---|---|---|
| NEW | Event diterima, belum diproses | Trigger worker async |
| PROCESSING | Worker sedang menjalankan bisnis logika | Locking untuk idempotensi |
| ACKED | Response sukses, tidak perlu retry | Hapus atau arsip state |
| RETRYING | Failure transient, akan dicoba ulang | Catat jumlah, backoff |
| FAILED | Batas retry tercapai | Alert, manual review |
3. Idempotensi dan Deteksi Duplikasi
Untuk webhook terlambat, idempotensi memastikan operasi tidak dijalankan dua kali walau payload sama diproses lebih dari sekali.
3.1 Idempotensi Key dan Penyimpanan State
Gunakan event_id sebagai idempotensi key. Saat menerima webhook, lakukan:
- Cek cache/DB (misal Redis) apakah
event_idsudah berhasil diproses. - Jika belum, lock (optimistic locking) lalu proses.
- Set status sukses dengan TTL (sesuaikan retensi) sehingga event lama bisa diabaikan bila datang lagi.
Contoh pseudo HTTP request/response:
POST /webhooks/events HTTP/1.1
Host: api.terima.id
Content-Type: application/json
X-Hub-Signature: sha256=abcdef123456
{ "event_id": "c10b5678", "event_type": "order.paid", ... }
HTTP/1.1 200 OK
Content-Type: application/json
{ "status": "ack", "processed_at": "2024-01-15T10:05:00Z" }
Jika event diterima duplikat sebelum timeout:
HTTP/1.1 409 Conflict
Content-Type: application/json
{ "status": "duplicate", "event_id": "c10b5678", "first_processed_at": "2024-01-15T10:05:00Z" }
Respons 409 memberi sinyal ke pengirim bahwa mereka tidak perlu retry lagi.
3.2 Logging dan Observability
Catat metadata event: event_id, status, latency, retry_count, response_code. Gunakan observability stack (misal Prometheus + Grafana) untuk:
- Memantau rate retry tinggi yang bisa mengindikasikan downstream bermasalah.
- Menampilkan distribusi latency ACK.
- Menginformasikan hubungan antara failure rate dan jumlah webhook terlambat.
Integrasikan tracing untuk melihat path request yang memicu webhook agar debugging delay lebih mudah.
4. Pengujian dan Simulasi Keterlambatan
Uji sistem dengan simulasi delay atau pemadaman downstream guna memverifikasi kontrak dan retry.
4.1 Simulasi Delay dan Pemadaman
Gunakan HTTP mocking/server proxy yang bisa menunda respons (misal WireMock atau httpbin) lalu ukur reaksi pengirim:
- Set timeout client lebih pendek untuk memicu retry.
- Simulasikan kode 5xx dan 429 untuk memastikan backoff berjalan.
- Periksa apakah status RETRYING maupun FAILED tercatat dengan benar.
4.2 Checklist Validasi Kontrak
- Apakah payload divalidasi terhadap schema dan versi didokumentasikan?
- Apakah signature HMAC diverifikasi dan waktu valid?
- Sudahkah status ACK/RETRY/FAIL distandarkan dan dipantau?
- Apakah idempotensi key disimpan dengan TTL untuk menghindari duplikasi?
- Sudahkah logging/metric mencakup retry_count dan latency?
- Apakah ada tes integrasi untuk kondisi timeout dan pemadaman?
5. Rangkuman dan Praktik Terbaik
Kontrak webhook yang jelas (schema versioning, signature), retry dengan backoff yang bijak, serta idempotensi kuat akan mengurangi kegagalan saat webhook terlambat. Pastikan observability dan pengujian mencakup simulasi delay agar tidak terkejut saat downtime nyata terjadi.
Dengan pendekatan ini, sistem dapat menerima webhook terlambat tanpa risiko duplikasi atau kehilangan data, sehingga reliability layanan tetap terjaga walau pihak ketiga dalam keadaan tidak stabil.
Komentar
0 komentar
Masuk ke akun kamu untuk ikut berkomentar.
Belum ada komentar
Jadilah yang pertama ikut berdiskusi!