Webhook'lar sana hiçbir şey garanti etmiyor. Yazılı olarak.

Webhook entegrasyonu yazmak kolay görünüyor: bir uç nokta aç, gelen olayı oku, veritabanını güncelle, 200 dön.

Bu üç satırın içine gömülü üç varsayım var ve üçü de yanlış. Olaylar sırayla gelmiyor, bir kez gelmiyor, ve sen hazır olduğunda gelmiyor. Sağlayıcının dokümantasyonu bunu genellikle açıkça söylüyor — ama entegrasyonu yazan kişi çoğu zaman o satırı okuduğunda henüz neden önemli olduğunu bilmiyor.

Önce imza, sonra her şey

Sıra ve tekillikten önce daha temel bir şey var: gelen isteğin gerçekten sağlayıcıdan geldiğini doğrulamak.

Webhook uç noktası internete açık bir POST adresi. İmzayı doğrulamıyorsan, herhangi biri sana "ödeme başarılı" olayı gönderebiliyor. Bu, para akışının en ucuz saldırı yüzeyi.

İmza doğrulaması ham gövde üzerinden yapılıyor. Framework'ün gövdeyi JSON'a çevirmesine izin verip sonra tekrar diziye dökerek doğrulamaya kalkarsan, en küçük biçim farkı imzayı bozuyor — ve o noktada çoğu kişi doğrulamayı kapatıyor. Doğru yol, ham gövdeyi imza doğrulanana kadar hiç ellememek.

Sıra bir garanti değil

İkinci mesele sıralama. "Ödeme başarılı" olayı bazen "ödeme oluşturuldu"dan önce düşüyor.

Naif uygulama bunu geçersiz bir geçiş sayıp reddediyor ve tutarlılığı kaybediyor. Doğru davranış erken gelen olayı reddetmek değil — bekletmek. Öncülü geldiğinde ikisini birden işlemek.

Yani sıra dışı olay bir hata değil, tasarlaman gereken bir durum. Ve bu, escrow yazısında anlattığım şeye bağlanıyor: durumu bir alan olarak değil bir defter olarak tuttuğunda, geç gelen olayı defterin doğru yerine yazmak mümkün oluyor.

Bir olay akışını doğru işlemek, olayları sıraya sokmak değil. Sıranın olmadığını kabul edip yine de doğru sonuca varmak.

Aynı olay birden fazla gelir

Üçüncüsü tekillik. Sağlayıcı bir olayı, sen 200 dönene kadar tekrar tekrar gönderiyor. Ve bazen 200 döndükten sonra da gönderiyor.

Bu, idempotency yazısında anlattığım şeyin webhook tarafı: her olayın sağlayıcı tarafından verilmiş bir kimliği var, o kimliği benzersiz kısıtla tabloya yazıyorsun, ve yazma ile işin kendisi aynı transaction içinde oluyor. İkinci gelişte kısıta çarpıyor ve hiçbir şey iki kez olmuyor.

200 dönmek "işledim" demek değil

En sinsi hata bu. Olayı alıyorsun, işliyorsun, sonra 200 dönüyorsun. İşleme yarısında bir şey patlarsa, sağlayıcı zaman aşımı görüyor ve tekrar gönderiyor — bu iyi.

Ama işleme uzun sürüyorsa sağlayıcının zaman aşımına yakalanıyorsun. O zaman sağlayıcı başarısız sanıp tekrar gönderiyor, sen de aynı işi ikinci kez başlatıyorsun. İki uzun iş paralel çalışıyor.

Doğru yapı: olayı al, imzayı doğrula, kalıcı bir kuyruğa yaz, hemen 200 dön. Asıl işi kuyruktan tüketen ayrı bir işçi yapıyor. Böylece kabul etmek hızlı, işlemek yeniden denenebilir, ve ikisi birbirini bekletmiyor.

Sonunda kim haklı

Ne kadar dikkatli yazarsan yaz, bir olayı bir gün kaçırıyorsun. Sağlayıcı kesinti yaşıyor, sen dağıtım yapıyorsun, kuyruk doluyor.

Bu yüzden webhook tek başına yeterli bir mekanizma değil. Yanında periyodik bir mutabakat gerekiyor: kendi defterinde yazan ile sağlayıcının kayıtlarında yazanı düzenli karşılaştırmak ve fark varsa alarm üretmek.

Webhook hızlı yoldur. Mutabakat doğru yoldur. İkisine birden ihtiyacın var — çünkü bir fark çıktığında onu sabah kullanıcıdan öğrenmek ile gece sistemden öğrenmek arasındaki mesafe, ürüne duyulan güvenin tamamı.