Güvenilir Shopify webhook’ları: yeniden deneme, idempotency, sıra
Kısa yanıt
Shopify, bir webhook uç noktasına 2xx durum koduyla yanıt vermesi için beş saniye tanır; aksi hâlde sonraki 4 saat içinde 8 kez yeniden dener. Admin API üzerinden oluşturulan bir abonelik art arda 8 başarısızlıktan sonra silinir. Teslimat garanti değildir, tekrarlar olur ve sıra garanti edilmez. Bu yüzden HMAC’i doğrulayın, hızlı yanıt verin, işi kuyruğa alın, X-Shopify-Webhook-Id ile tekilleştirin, zaman damgasına göre sıralayın ve düzenli olarak mutabakat yapın.
- Shopify’ın bağlantı için bir saniyelik, webhook isteğinin tamamı için beş saniyelik zaman aşımı vardır.
- 3xx yönlendirmeler dahil, 2xx aralığı dışındaki her yanıt hata sayılır.
- Hata alındığında ya da yanıt gelmediğinde Shopify sonraki 4 saat içinde 8 kez yeniden dener.
- Art arda 8 başarısızlıktan sonra Admin API üzerinden ayarlanmış bir abonelik otomatik olarak silinir.
- Shopify ne aynı konu (topic) içinde ne de aynı kaynağa ait farklı konular arasında sırayı garanti eder.
- X-Shopify-Webhook-Id bir teslimatı tanımlar ve Shopify’ın tekilleştirme için kullanılmasını söylediği başlıktır.
Webhook’lar basit görünür: bir şey değiştiğinde Shopify sizin URL’nizi çağırır, siz de diğer sistemi güncellersiniz. Sorunlar basit olmayan kısımlardan çıkar. Yavaş bir işleyici zaman aşımına uğrar ve yeniden denenir; aynı olay iki kez gelir. Aynı ürüne ait iki güncelleme ters sırayla gelir; eskisi kazanır. Hatalı bir yayın bütün bir öğleden sonra düzeltilmez ve abonelik silinir. Bunların her biri belgelenmiş bir davranıştır ve her birinin bilinen bir çözümü vardır.
Teslimat kuralları
| Kural | Shopify’ın belgelediği |
|---|---|
| Zaman aşımı | Bağlanmak için bir saniye, isteğin tamamı için beş saniye |
| Başarı | 2xx yanıt. 3xx dahil diğer her şey hatadır |
| Yeniden deneme | Hata ya da yanıtsızlık sonrasında, sonraki 4 saatte 8 deneme |
| Silme | Art arda 8 başarısızlıktan sonra Admin API üzerinden ayarlanmış abonelik silinir; uyarı e-postaları uygulamanın acil durum geliştirici e-posta adresine gider |
| Garanti | Teslimat her zaman garanti değildir |
| Sıra | Ne bir konu içinde ne de aynı kaynağa ait konular arasında garanti edilir |
| Tekrarlar | En aza indirilir, ama aynı webhook birden fazla kez gelebilir |
Aşağıdaki her şey bu tablodan çıkar. Güvenilir bir işleyici bir teslimatı bazen iki kez alacağını, teslimatları bazen sırasız alacağını ve bazen hiç almayacağını varsayar.
1. Her şeyden önce doğrulayın
Her HTTPS teslimatı X-Shopify-Hmac-Sha256 başlığını taşır: ham istek gövdesinin, uygulamanızın client secret’ı ile anahtarlanmış, base64 kodlu HMAC-SHA256 değeri. Değeri kendiniz hesaplayın, karşılaştırın ve eşleşmiyorsa isteği reddedin. Shopify’ın rehberi birçok framework’ün takıldığı bir sıra konusuna dikkat çeker: imza ham, ayrıştırılmamış gövde üzerinden hesaplandığı için doğrulamayı gövdeyi ayrıştıran middleware’lerden önce yapın.
import {createHmac, timingSafeEqual} from 'node:crypto';
export function isFromShopify(rawBody: Buffer, header: string | null, secret: string) {
if (!header) return false;
const digest = createHmac('sha256', secret).update(rawBody).digest();
const received = Buffer.from(header, 'base64');
return received.length === digest.length && timingSafeEqual(received, digest);
}2. Hemen yanıt verin, işi sonra yapın
Ağ dahil bütün bütçe beş saniyedir. Yanıt vermeden önce bir ERP’yi çağıran, üç tabloya yazan ve e-posta gönderen bir işleyici bazen süreyi aşar. Zaman aşımı da başarısızlık sayılır; bu da yeniden deneme ve tekrar demektir. Shopify’ın kendi önerisi bir kuyruk kullanmaktır: yükü (payload) saklayın, 2xx ile yanıt verin ve işi bir worker’da yapın. Worker diğer sistem ne kadar süre gerektiriyorsa o kadar çalışabilir ve kendi takvimine göre yeniden deneyebilir.
Shopify’ın teslimat sistemi bağlantıları HTTP Keep-Alive ile yeniden kullanır; bu yüzden uç noktanızda etkin olduğundan emin olun. Yönlendirmeyle de yanıt vermeyin: 3xx hata sayılır.
3. İşlemeyi idempotent yapın
Shopify bunu açıkça söyler: webhook’ları idempotent işlemlerle işleyin; aynı webhook’u iki kez almak farklı bir sonuç doğurmasın. İki başlık yardımcı olur ve farklı anlamlar taşır:
X-Shopify-Webhook-Idher teslimat için benzersiz bir anahtardır. Shopify’ın doğrulama rehberi bunu kalıcı bir depoda kontrol etmenizi söyler: daha önce görüldüyse işi atlayın ve başarı dönün; görülmediyse işleyin ve kaydedin.X-Shopify-Event-Idmağaza sahibinin aynı işleminden doğan tüm teslimatlarda ortaktır. Bir işlemin neye yol açtığını gruplar; tekilleştirme anahtarı değildir.
Teslimat kimliğine göre tekilleştirme, birebir tekrarları engeller. Gerisini idempotent yazmalar karşılar: stok seviyesine fark eklemek yerine seviyeyi bir değere ayarlayın, kayıt eklemek yerine Shopify kaynak kimliğine göre upsert yapın, e-posta gibi yan etkileri tetiklemeden önce daha önce yapılıp yapılmadıklarını kontrol edin. Teslimat kimliğini, yol açtığı değişiklikle aynı transaction içinde kaydedin; böylece arada bir çökme olsa bile biri kaydedilip diğeri eksik kalmaz.
4. Geliş sırasına güvenmeyin
Sıra garanti olmadığı için saat 10:02’deki bir products/update, 10:05’teki bir güncellemeden sonra gelebilir. Shopify’ın önerisi olayları zaman damgasıyla sıralamaktır: başlıklarda X-Shopify-Triggered-At, yükte updated_at. Pratikte her kaynak için uyguladığınız son değişikliğin zaman damgasını saklayın ve bundan eski her olayı yok sayın.
Bazı işler için en basit çözüm webhook’u yalnızca bir sinyal olarak görmektir: bir ürün değiştiğinde ürünün güncel hâlini Admin API’den çekin ve onu uygulayın. Bildirimler hangi sırayla gelirse gelsin veri hep en günceli olur; bedeli de olay başına bir ek API çağrısıdır.
5. Mutabakat yapın, çünkü bazı teslimatlar hiç gelmez
Shopify bunu açıkça söyler: webhook teslimatı her zaman garanti değildir ve bir uygulama kendi hataları veya kesintileri yüzünden de olayları kaçırabilir. Önerisi, uygulamanın tutarlı kalması için Shopify’dan düzenli olarak veri çeken bir mutabakat işidir. Birçok GraphQL sorgusu updated_at filtresini kabul eder; böylece iş yalnızca son çalışmasından bu yana değişenleri okur.
Webhook hızlı yol olur, mutabakat işi de güvenlik ağı. İşin ne sıklıkla çalışacağı, işletmenin ne kadar sapmaya tahammül edebildiğine bağlıdır: stok ve fiyatlar genellikle müşteri etiketlerinden daha dar bir aralık ister. Stok özelinde Shopify stok senkronizasyonunu planlamak yazısına bakın.
6. Yalnızca kodu değil, aboneliği de izleyin
- Dev Dashboard’da ya da Shopify CLI ile oluşturulan uygulamalarda, Dev Dashboard’daki uygulamanın Overview sayfası teslimatları, başarısız teslimat oranını ve yanıt süresini gösterir; Logs sayfası da son 7 günün teslimatlarını tek tek listeler. Kayıtlar birkaç dakika gecikebilir.
- Uygulamanın acil durum geliştirici e-posta adresinin birine ulaştığından emin olun: Admin API aboneliği silinmeden önceki uyarılar bu adrese gelir.
- Bir kesintiden sonra nedeni düzeltin, silinen abonelikleri yeniden oluşturun ve aradaki boşluk için mutabakat işini çalıştırın.
- Kendi kuyruğunuz için alarm kurun: sürekli büyüyen bir birikim, Shopify yeniden denemeye başlamadan çok önce görülen erken işarettir.
Baştan sona işleyici, sırasıyla
Hepsi bir araya geldiğinde, Shopify’ın önerilerine uyan bir işleyici her teslimat için aynı birkaç adımı izler:
- Ham gövdeyi okuyun ve
X-Shopify-Hmac-Sha256değerini doğrulayın. Eşleşmezse isteği reddedin. X-Shopify-Webhook-Iddeğerini okuyun. İşlenmiş teslimatlar deponuzda zaten varsa başarı dönün ve durun.- Yükü,
X-Shopify-Topicbaşlığından konuyu,X-Shopify-Shop-Domainbaşlığından mağazayı veX-Shopify-Triggered-Atbaşlığından zaman damgasını bir kuyruğa yazın. - Beş saniyenin çok altında bir 2xx dönün.
- Worker’da olayın zaman damgasını o kaynağa uygulanan son değişiklikle karşılaştırın; daha eskiyse atlayın.
- Değişikliği idempotent bir yazmayla uygulayın ve teslimat kimliğini aynı transaction içinde kaydedin.
- Hiç gelmeyenleri mutabakat işi yakalasın.
Kaydetmeye değer bir başlık daha var: X-Shopify-API-Version, yükün serileştirilmesinde kullanılan API sürümünü belirtir. Bir yükseltmeden sonra bir alan eksik ya da adı değişmiş görünüyorsa ilk bakılacak yer burasıdır.
Lintel’in yeri
Webhook işleyicileri, kuyruklar ve mutabakat işleri, Lintel’in API entegrasyon işlerinin ve başka bir sistemi mağazayla uyumlu tutan özel Shopify uygulamalarının temelidir. Senkronu şimdiden kaymaya başlamış bir entegrasyonda ilk adım, işleyiciyi yukarıdaki altı maddeye göre gözden geçirmektir; bu genellikle hangisinin eksik olduğunu gösterir.
Sık sorulan sorular
- Shopify başarısız bir webhook’u kaç kez yeniden dener?
- Shopify yanıt alamazsa ya da hata alırsa sonraki 4 saat içinde 8 kez yeniden dener. Art arda 8 başarısızlıktan sonra Admin API üzerinden ayarlanmış abonelik otomatik olarak silinir ve uyarı e-postaları uygulamanın acil durum geliştirici e-posta adresine gider.
- Uç noktamın yanıt vermek için ne kadar süresi var?
- Shopify’ın bağlantı için bir saniyelik, isteğin tamamı için beş saniyelik zaman aşımı vardır. Hızla 2xx durum koduyla yanıt verin, yavaş işleri bir kuyrukta yapın.
- Shopify aynı webhook’u iki kez gönderebilir mi?
- Evet. Shopify tekrarları en aza indirir, ama aynı webhook birden fazla kez gelebilir; örneğin bir zaman aşımı ya da yeniden denemeden sonra. X-Shopify-Webhook-Id başlığıyla tekilleştirin ve işlemeyi idempotent yapın.
- Shopify webhook’ları sırayla mı teslim edilir?
- Hayır. Shopify ne bir konu içinde ne de aynı kaynağa ait konular arasında sırayı garanti eder. Hangi değişikliğin en yeni olduğuna karar vermek için X-Shopify-Triggered-At başlığını ya da yükteki updated_at alanını kullanın.
