Debugging18 April 20267 mnt baca

Men-debug Webhook yang Gagal di Production tanpa Kehilangan Akhir Pekan

Men-debug pengiriman webhook: apa yang perlu diperiksa di header, kode status, waktu, dan payload saat integrasi Anda berhenti berfungsi.

YANG DICATAT DASHBOARD PROVIDERproviderlog pengiriman2xxtiba, lalu hilang setelah respons dikirim4xxAnda menolaknya: tanda tangan, WAF, URL salah5xxhandler Anda error tepat pada stempel waktu itutimeouthandler terlalu lambat; jadikan pekerjaannya asinkron
Mulai dari log pengiriman milik provider. Status yang dicatatnya memberi tahu lapisan mana yang perlu Anda buka berikutnya, dan menghemat sekitar tiga puluh menit menebak-nebak.

Seorang pelanggan mengirim email: “webhook Stripe saya rusak.” Anda memeriksa dashboard Stripe, dan event-nya terpicu. Anda memeriksa log server, dan tidak ada apa-apa. Sentry, juga tidak ada. Event itu pergi ke suatu tempat, hanya saja bukan ke tempat yang Anda harapkan.

Artikel ini adalah kerangka langkah demi langkah untuk men-debug masalah pengiriman webhook di production, berdasarkan mode kegagalan yang paling sering muncul.

TL;DR

  • Mulai dari dashboard provider: apakah event-nya terpicu, dan status apa yang diterimanya kembali?
  • 4xx berarti Anda menolaknya: tanda tangan (signature), middleware, atau URL yang salah
  • 5xx berarti handler Anda crash. Periksa error monitoring pada stempel waktu (timestamp) yang persis itu
  • Timeout berarti handler Anda terlalu lambat. Pindahkan pekerjaan berat ke proses async dan kembalikan 200 dengan cepat
  • Solusi untuk “butuh 2 jam untuk men-debug” adalah satu tempat yang menampilkan permintaan masuk, permintaan keluar, percobaan ulang (retry), dan putar ulang (replay) sekaligus, yang biasanya berarti relay webhook

Pohon keputusan

Mulai dari sini. Ini akan menghemat 30 menit menebak-nebak.

Q1: Apakah provider benar-benar mengirim event-nya?

Periksa dashboard provider (Stripe: Developers → Events; GitHub: Settings → Webhooks → Recent Deliveries; Shopify: Dev Dashboard → Apps → aplikasi Anda → Logs).

Jika event-nya tidak ada di sana, pemicunya tidak berjalan, jadi telusuri state upstream yang seharusnya menghasilkan event itu. Jika ada, lanjut ke Q2.

Q2: Apakah provider menerima 2xx sebagai balasan?

Di dashboard yang sama, lihat status respons dari endpoint Anda.

  • 2xx: provider menganggapnya berhasil. Jika aplikasi Anda tidak pernah melihatnya, event itu tiba lalu terbuang setelah respons. Periksa antrean async, penulisan DB, dan logika handler Anda.
  • 4xx: Anda menolaknya. Paling sering karena verifikasi tanda tangan gagal, header yang hilang, atau middleware (WAF, rate limiter, lapisan auth) yang memblokir permintaan.
  • 5xx: endpoint Anda crash. Periksa error monitoring, dan bukan hanya “satu jam terakhir”, melainkan stempel waktu persis dari pengiriman ini.
  • Timeout: endpoint Anda terlalu lambat. Lihat Q4.
  • Connection refused atau DNS: endpoint Anda tidak bisa dijangkau, dan itu masalah lain yang letaknya di jaringan, DNS, atau firewall.

Q3: Jika 4xx, yang mana?

  • 400, bad request. Biasanya header tidak cocok, atau pemeriksaan tanda tangan Anda melempar error sebelum sempat mengembalikan pesan error yang jelas. Periksa apa yang dikembalikan handler Anda saat body-nya rusak atau tanda tangannya tidak ada.
  • 401 / 403, Anda menolak permintaan itu sebagai tidak terotorisasi. Verifikasi tanda tangan gagal? Middleware memeriksa sesi pengguna di endpoint yang seharusnya tidak membutuhkannya?
  • 404, URL-nya salah. Apakah Anda men-deploy perubahan route yang memindahkan endpoint webhook?
  • 413, payload terlalu besar. Naikkan batas body-parser Anda.
  • 429, rate limiter terpicu. Apa pun yang membatasi laju route webhook Anda seharusnya tidak melakukannya. Sebagian besar provider webhook mengirim dari kumpulan IP yang terbatas, dan limiter Anda mungkin memperlakukan semuanya sebagai satu penyerang.

Q4: Jika timeout, apa yang lambat?

GitHub memberi Anda 10 detik. Shopify memberi 5. Slack dan Discord memberi 3. Stripe tidak pernah memublikasikan angkanya; dokumentasinya hanya meminta Anda mengembalikan 2xx sebelum logika yang lambat. Tabel lengkapnya, dengan sumber untuk setiap baris, ada di referensi provider webhook.

waitUntil · 200 ITU JANJI YANG TIDAK BISA ANDA TEPATIverifikasikembalikan 200waitUntil(work)hanya di memorididaur ulang → hilang, tidak pernah dikirim ulangSIMPAN DULU · 200 ITU BENARverifikasitulis persistenkembalikan 200prosesbisa dicoba ulang
Bentuk yang menjaga Anda tetap di dalam batas timeout setiap provider, selambat apa pun pekerjaan yang sebenarnya.

Sebagian besar timeout berasal dari terlalu banyak pekerjaan di dalam handler. Pelaku yang biasa adalah penulisan database sinkron ke pool yang sudah jenuh, panggilan ke layanan lain (Stripe, Salesforce, Notion, API Anda sendiri) dari dalam handler, pengiriman email atau pesan Slack secara sinkron, dan pencatatan seluruh body ke stdout pada log ingester yang sedang mengalami backpressure.

Pola solusinya: verifikasi tanda tangan, masukkan event ke antrean, kembalikan 200. Semua logika bisnis terjadi di downstream, secara asinkron.

Apa yang biasanya benar-benar rusak

Setelah beberapa tahun mengamati hal ini, inilah pola 80/20:

  1. Verifikasi tanda tangan melakukan serialisasi ulang pada body. Lihat panduan verifikasi tanda tangan
  2. Proxy atau WAF menelan webhook sebelum sampai ke handler Anda. Periksa log permintaan di Cloudflare, Vercel, atau apa pun yang dipakai platform Anda
  3. Rate limiting terpicu. Bot Management dari Cloudflare bisa menghasilkan false positive pada webhook yang sah
  4. URL endpoint berubah saat deploy dan tidak ada yang memperbaruinya di provider
  5. Sebuah env var tidak ada di production (signing secret, URL DB) dan handler diam-diam mengembalikan 500
  6. Job latar belakang crash setelah webhook mengembalikan 200. Provider menganggap semuanya baik-baik saja, tetapi tidak ada yang diproses

Nomor 6 mewabah di serverless, karena di sana pekerjaan yang dijadwalkan setelah respons sama sekali tidak punya jaminan persistensi: Menerima Webhook di Vercel tanpa Ada yang Hilang. Dan jika gejalanya duplikat, bukan event yang terlewat, biasanya itu memang sesuai rancangan: Anda Menerima Webhook yang Sama Dua Kali.

Tool yang benar-benar membantu

Dashboard provider bagus untuk melihat satu event dalam satu waktu dan buruk untuk melihat pola. Jika Anda ingin “semua event yang gagal dalam 24 jam terakhir”, Anda harus menggulir secara manual.

ngrok dan webhook.site untuk pengembangan lokal. Keduanya tidak membantu Anda di production.

Log Anda sendiri membantu jika Anda mencatat hal yang tepat. Jika Anda mencatat “webhook received for event evt_xxx” sebelum pemeriksaan tanda tangan, setidaknya Anda tahu event itu tiba. Kebanyakan orang mencatatnya setelah pemeriksaan, sehingga event yang gagal verifikasi tanda tangan tidak terlihat.

Relay webhook seperti AnyHook berada di depan handler Anda dan mencatat header, body, waktu, status respons, dan jumlah upaya. Siklus debugging-nya menjadi: lihat aliran event, klik yang gagal, periksa payload mentahnya, putar ulang.

Siklus debugging di AnyHook

Saat pengguna mengirim email ke support AnyHook dengan keluhan “webhook saya tidak berfungsi”, dashboard biasanya membuat penyebabnya jelas dalam waktu kurang dari satu menit:

  1. Buka aliran event, filter ke status=failed
  2. Klik event yang gagal
  3. Lihat header masuk (apakah tanda tangannya ada?), body masuk (apakah bentuknya sesuai harapan?), respons keluar (apa kata server Anda?), dan rincian waktu (edge → antrean → pengiriman)
  4. Jika itu kejadian sekali saja, deploy yang buruk atau jaringan yang tidak stabil, klik tombol Replay (putar ulang) dan lihat event itu berhasil
  5. Jika setiap event gagal, kini Anda tahu persis apa yang harus diperbaiki, dan event Anda tetap tersimpan dan dapat diputar ulang selama masa putar ulang paket Anda (3 hari di Free, 30 di Pro, 90 di Scale) selagi Anda memperbaikinya

Yang mengubah sesi debugging 2 jam menjadi 2 menit adalah memiliki permintaan yang benar-benar dikirim provider, respons yang benar-benar dikembalikan server Anda, dan stempel waktu di antara keduanya, semuanya di satu tempat. Tanpa itu, Anda harus merekonstruksinya dari tiga dashboard dan log Anda sendiri.

Untuk melihatnya sebelum mendaftar apa pun, satu perintah mengembalikan URL masuk (inbound URL) yang aktif, tanpa akun:

curl -X POST https://anyhook.net/api/v1/quickstart

Responsnya berisi inbound_url untuk Anda berikan ke provider, api_key untuk membaca log event lewat API, dan claim_url. Endpoint ini sementara: endpoint dan event-nya dihapus setelah 7 hari kecuali Anda membuka URL klaim itu lalu masuk, dan URL-nya tetap sama.

Kesimpulan

Jika ini lebih sering menjadi Minggu sore Anda daripada yang Anda inginkan, AnyHook mengubah sebagian besarnya menjadi satu klik di dashboard.

Semua artikel18 April 2026 · 7 mnt

Berhenti kehilangan webhook.

Ganti satu URL. Dapatkan percobaan ulang, log event, dan putar ulang sekali klik. Atau lihat dulu: daftar dan jalankan latihan gangguan 30 detik, lalu saksikan event tetap selamat saat server Anda mati. Tidak perlu server.