Webhook datang dua kali: cegah agent AI menggandakan pekerjaan pembayaran
Sebuah toko menerima pemberitahuan pembayaran berhasil. Sistem menandai pesanan lunas, lalu agent AI menyiapkan pesan untuk pelanggan dan tugas pengemasan. Beberapa saat kemudian, pemberitahuan yang sama datang lagi. Jika setiap kedatangan dianggap pekerjaan baru, pelanggan bisa menerima pesan berulang dan staf mendapat dua tugas untuk satu pesanan.
Contoh ini hipotetis, tetapi perilaku pengirimannya terdokumentasi. Stripe menyebut bahwa webhook dapat diterima lebih dari sekali dan urutan kedatangannya tidak dijamin. Integrasi harus mengantisipasi keduanya. Model yang memahami bahasa pelanggan dengan baik tetap bisa menggandakan pekerjaan bila aplikasi memperlakukannya sebagai satu-satunya pengendali proses.
Bagi UMKM, pembahasannya bisa dimulai dari pertanyaan sederhana saat meninjau otomasi: ketika pemberitahuan yang sama masuk lagi, bagian mana yang mencegah pekerjaan bisnis terulang?
Pemberitahuan bukan pekerjaan bisnis baru
Webhook adalah cara layanan mengirim kabar ke aplikasi ketika suatu peristiwa terjadi. Penerima tidak perlu terus-menerus bertanya apakah pembayaran sudah selesai. Namun, menerima kabar tentang pembayaran tidak sama dengan menerima izin untuk membuat semua tindakan turunannya sekali lagi.
Pisahkan identitas pemberitahuan dari identitas pekerjaan bisnis. Identitas event membantu aplikasi mengenali pengiriman ulang pemberitahuan yang sama. Identitas pekerjaan membantu mencegah satu pesanan menghasilkan dua tugas pengemasan, meskipun pemicunya berasal dari pemberitahuan berbeda.
Dokumentasi Stripe menyarankan pencatatan identitas event yang sudah diproses. Dokumentasi itu juga menjelaskan bahwa dua objek event terpisah dapat berkaitan dengan duplikasi; identitas objek terkait dan jenis event membantu mengenalinya. Jangan mengubah saran tersebut menjadi aturan bahwa setiap event untuk satu objek selamanya harus diabaikan. Objek yang sama memang dapat mengalami perubahan sah berikutnya.
Aturan aplikasi perlu memahami tindakan yang hendak dilakukan. “Buat tugas pengemasan pertama untuk pesanan ini” berbeda dari “catat perubahan status pembayaran terbaru”.
Terima dengan cepat, simpan pekerjaan dengan jelas
Stripe menganjurkan penerima webhook segera mengembalikan respons sukses sebelum menjalankan logika rumit yang berisiko melewati batas waktu. Dokumentasinya juga menyarankan pemrosesan asinkron menggunakan antrean. Memanggil model, membaca riwayat pelanggan, lalu menulis pesan panjang di dalam proses penerimaan webhook akan menambah ketergantungan pada waktu respons model.
Sebagai rancangan aplikasi, penerima dapat memverifikasi keaslian pemberitahuan, mencatatnya secara tahan gangguan, lalu menyerahkan pekerjaan ke pemroses terpisah. Respons sukses menunjukkan bahwa aplikasi menerima pemberitahuan sesuai kontrak integrasinya. Respons itu tidak membuktikan bahwa pesan pelanggan sudah terkirim atau paket sudah siap.
Ada detail yang mudah terlewat: jangan mengirim tanda terima sukses lalu hanya menyimpan pekerjaan di memori sementara. Jika proses berhenti, pengirim mungkin sudah menganggap pemberitahuan diterima sementara pekerjaan hilang. Cara penyimpanan dan pemulihannya harus ditentukan pengembang, bukan diserahkan kepada keputusan model.
Antrean pun dapat mengirim pekerjaan lagi setelah gangguan. Karena itu, memindahkan proses ke antrean belum menyelesaikan duplikasi. Pemeriksaan tetap diperlukan ketika tindakan bisnis dijalankan.
Beri agent ruang untuk menyusun, bukan menggandakan
Agent AI cocok membantu merangkum informasi pesanan, menyusun pesan dengan bahasa yang wajar, atau menjelaskan pengecualian kepada staf. Aplikasi sebaiknya menentukan apakah pekerjaan tersebut sudah selesai, masih berjalan, atau memang boleh diulang.
Dalam contoh toko tadi, backend memeriksa status pembayaran dan kelayakan pesanan, lalu membuat satu catatan pekerjaan pengemasan. Agent menerima konteks dari catatan itu untuk menyiapkan ringkasan. Bila webhook yang sama datang lagi, backend dapat merujuk pekerjaan yang sudah ada tanpa meminta model menciptakan tugas baru.
Pemisahan tersebut sejalan dengan gagasan dalam artikel Agentic Web Application: aturan dan otorisasi tindakan berada di backend. Pada kasus webhook, tambahkan aturan tentang identitas pekerjaan dan status penyelesaiannya.
Untuk pesan pelanggan, tentukan pula kapan pengiriman ulang sah. Staf mungkin meminta kirim ulang karena alamat kontak telah diperbaiki. Itu keputusan baru yang perlu dicatat, bukan alasan menghapus semua perlindungan terhadap pesan ganda.
Jangan membiarkan dua pemroses sama-sama lolos
Pemeriksaan “pekerjaan belum ada” yang terpisah dari penyimpanan dapat bermasalah ketika dua pemroses berjalan bersamaan. Keduanya membaca keadaan kosong, lalu masing-masing membuat pekerjaan. Pemeriksaan di kode terlihat benar, tetapi waktunya saling bertabrakan.
Rekomendasi desainnya adalah menggunakan jaminan penyimpanan yang sesuai, misalnya batasan unik pada identitas pekerjaan bisnis dan transaksi untuk perubahan yang perlu berlangsung bersama. Pemroses yang kalah dalam perebutan pekerjaan membaca hasil yang sudah tercatat, bukan menganggap konflik sebagai alasan membuat identitas baru.
Perlindungan tersebut mempunyai batas. Transaksi database lokal tidak otomatis mencakup layanan pengiriman pesan atau pembayaran di luar aplikasi. Jika layanan luar sudah menjalankan tindakan tetapi responsnya hilang, aplikasi membutuhkan cara memeriksa hasil sebelum mengulang. Catat status yang belum pasti secara jujur agar staf tidak membaca “gagal” sebagai bukti bahwa tidak ada tindakan terjadi.
Bedakan webhook masuk dan permintaan API keluar
Deduplikasi webhook menangani pemberitahuan yang diterima. Kunci idempotensi pada API menangani percobaan ulang permintaan yang dikirim. Keduanya berkaitan, tetapi bukan pengganti satu sama lain.
Sebagai contoh spesifik, dokumentasi Stripe API v1 menjelaskan bahwa permintaan dengan kunci idempotensi yang sama mengembalikan hasil pertama yang disimpan setelah eksekusi dimulai, termasuk respons kesalahan tertentu. Parameter juga dibandingkan untuk mencegah penggunaan kunci yang sama bagi permintaan berbeda. Dokumentasi tersebut membedakan perilaku API v1 dan v2, sehingga aturan satu versi tidak boleh dianggap berlaku identik pada semuanya.
Untuk rancangan aplikasi, kaitkan kunci dengan operasi bisnis yang sama saat mengulang permintaan. Jangan menghasilkan kunci baru setiap kali jaringan bermasalah, karena layanan dapat menganggapnya operasi baru. Perhatikan juga masa penyimpanan kunci pada penyedia. Perlindungan penyedia tidak menghapus kebutuhan akan riwayat pekerjaan di aplikasi sendiri.
Idempotensi bukan janji bahwa seluruh alur pasti terjadi tepat sekali. Satu alur bisa melibatkan beberapa layanan dengan jaminan berbeda. Jelaskan cakupan perlindungannya, lalu siapkan rekonsiliasi untuk hasil yang meragukan.
Uji pengiriman ulang sebelum pelanggan mengalaminya
Pengujian tidak cukup dengan satu pembayaran yang berjalan mulus. Kirim event yang sama dua kali, termasuk secara bersamaan. Hasil yang diharapkan adalah satu pekerjaan bisnis, dengan riwayat yang tetap menjelaskan bahwa beberapa pengiriman telah diterima.
Uji pula pemberitahuan yang datang tidak berurutan. Dokumentasi Stripe menyarankan integrasi tidak bergantung pada urutan kedatangan dan menjelaskan penggunaan API untuk mengambil objek yang dibutuhkan. Rancangan aplikasi perlu menetapkan sumber status yang dipercaya, bukan menyimpulkan keadaan hanya dari urutan pesan masuk.
Simulasikan proses berhenti setelah tindakan luar berhasil tetapi sebelum hasilnya tersimpan. Periksa apakah pemulihan menemukan tindakan lama atau malah membuat yang baru. Tambahkan pengujian untuk pemberitahuan tidak sah: dokumentasi Stripe mensyaratkan verifikasi tanda tangan dan penggunaan badan permintaan asli untuk pemeriksaan tersebut. Jangan menyerahkan penilaian keaslian kepada model.
Mulailah dari satu alur kecil, misalnya pembayaran terkonfirmasi sampai tugas pengemasan tercatat. Ukur pekerjaan ganda yang berhasil dicegah, pekerjaan yang tertahan, dan kasus yang perlu diperiksa staf. Setelah jalur pemulihannya jelas, barulah pertimbangkan menambah tanggung jawab agent. Pelanggan tidak perlu mengetahui berapa kali pemberitahuan datang; mereka perlu menerima layanan yang konsisten untuk pesanan yang sama.
Sumber
- Stripe: Webhooks, khususnya pengiriman ganda, urutan event, verifikasi tanda tangan, dan pemrosesan asinkron.
- Stripe: Idempotent requests, dengan pembedaan perilaku API v1 dan v2.
- Agus Ramdan: Agentic Web Application, sebagai bacaan terkait tentang pemisahan agent dan aturan backend.
Contoh toko dan rekomendasi arsitektur di atas bersifat ilustratif, bukan klaim implementasi atau hasil pengukuran produksi.