MercanPay Blog

Webhook Yeniden Deneme ve İdempotent İşleme Rehberi

Webhook yeniden deneme takvimi, 10 saniye kuralı, tekrarlanan olayları eleme ve kaçan bildirimler için mutabakat. Kripto ödeme webhook'larını sağlam işleyin.

Yayınlanma: 11 Kasım 20265 dk okumaRead in English
Webhook Yeniden Deneme ve İdempotent İşleme Rehberi

Webhook yeniden deneme mekanizması, sunucunuz geçici olarak erişilemez olduğunda bile hiçbir ödeme bildiriminin kaybolmamasını sağlar. Ama bunun bir bedeli vardır: aynı olay size birden fazla kez ulaşabilir. Bu yazıda MercanPay'in webhook'ları ne zaman ve kaç kez yeniden denediğini, tekrarlanan olayları idempotent biçimde nasıl işleyeceğinizi ve bir bildirim kaçarsa mutabakatı nasıl yapacağınızı anlatıyoruz.

İmza doğrulamayı burada tekrar etmiyoruz. O konu için webhook imzası doğrulama rehberimize bakın. Olay türlerinin tam listesi de webhook olay türleri yazımızda.

Bir webhook ne zaman "teslim edildi" sayılır?

MercanPay, webhook URL'nize imzalı bir POST isteği gönderir. Teslimatın başarılı sayılması için sunucunuzun:

  • 10 saniye içinde yanıt vermesi,
  • 2xx bir HTTP kodu (örneğin 200) dönmesi

gerekir. Zaman aşımı, bağlantı hatası ya da 2xx dışındaki her yanıt (400, 401, 500, 502…) başarısız deneme sayılır.

Yeniden deneme takvimi

Başarısız bir denemeden sonra istek artan aralıklarla tekrarlanır:

Deneme Önceki denemeden sonra bekleme
2 30 saniye
3 2 dakika
4 10 dakika
5 30 dakika
6 1 saat
7 3 saat
8 6 saat
9 12 saat
10 24 saat

Son deneme de başarısız olursa teslimat başarısız olarak işaretlenir. Toplamda iki günü aşan bu pencere, sunucunuzdaki bakım ya da kısa kesintilerin bildirim kaybına dönüşmesini engeller.

Olay yalnızca durum gerçekten değiştiyse gönderilir

MercanPay webhook olaylarını, olaya neden olan durum değişikliğiyle aynı veritabanı işleminde kayda alır. Buna "transactional outbox" denir. Pratik sonucu şudur: size bir invoice.paid olayı geldiyse fatura gerçekten ödendi olarak kaydedilmiştir. Kaydedilmemiş bir değişiklik için olay gönderilmez.

Bu, sizin tarafınızda da aynı disiplini uygulamanız için iyi bir örnektir: siparişi "ödendi" yapma işlemini ve "bu olayı işledim" kaydını tek bir veritabanı işleminde yapın.

Aynı olay neden birden fazla gelir?

Yeniden deneme sistemi "en az bir kez" teslimat garanti eder, "tam olarak bir kez" değil. Tekrar şu durumlarda yaşanabilir:

  • Sunucunuz siparişi işledi, ama yanıtı 10 saniyeden geç verdi. MercanPay bunu başarısız sayar ve yeniden dener.
  • Yanıtınız ağda kayboldu.
  • Paneldeki teslimat geçmişinden bir olayı elle yeniden gönderdiniz.
  • Faturada callback_url verdiniz. Olay hem Ayarlar'daki Webhook URL'ye hem de callback_url'ye gider. İki adres aynı sisteme bakıyorsa aynı olayı iki kez görürsünüz.

Son maddede önemli bir ayrıntı var: her iki adrese giden istek aynı olay kimliğini (id) taşır. Bu yüzden olay kimliğiyle yapılan tekrar eleme, iki adres durumunda da doğru çalışır.

İdempotent işleme: adım adım

1. Olay kimliğini benzersiz olarak kaydedin

Her webhook gövdesinde bir id alanı vardır. Bunu UNIQUE kısıtlı bir tabloya yazın. Ekleme başarısızsa olay daha önce işlenmiştir.

CREATE TABLE processed_events (
  event_id   TEXT PRIMARY KEY,
  received_at TIMESTAMPTZ NOT NULL DEFAULT now()
);

2. Sipariş güncellemesini koşullu yapın

Olay kimliğine ek olarak siparişin durumunu da kontrol edin: "yalnızca henüz ödenmemişse ödendi yap". Bu ikinci kilit, farklı olay kimlikleri taşıyan ama aynı siparişi etkileyen olaylara karşı sizi korur. Örneğin önce invoice.partial, sonra invoice.paid gelmesi gibi.

3. Hızlı yanıt verin, ağır işi kuyruğa atın

E-posta göndermek, lisans üretmek ya da harici bir API'yi çağırmak 10 saniyeyi aşabilir. Webhook işleyicinizde yalnızca imzayı doğrulayın, olayı kaydedin, işi bir kuyruğa bırakın ve 200 dönün.

import json
import os

from flask import Flask, abort, request
from mercanpay import verify_webhook

app = Flask(__name__)
SECRET = os.environ["MERCANPAY_WEBHOOK_SECRET"]


@app.post("/mercanpay/webhook")
def webhook():
    body = request.get_data()
    if not verify_webhook(SECRET, body, request.headers.get("X-MercanPay-Signature", "")):
        abort(401)

    event = json.loads(body)
    with db.transaction() as tx:
        # event_id PRIMARY KEY: ikinci kez gelirse hiçbir şey eklenmez
        inserted = tx.execute(
            "INSERT INTO processed_events (event_id) VALUES (%s) ON CONFLICT DO NOTHING",
            (event["id"],),
        ).rowcount
        if inserted:
            tx.execute(
                "INSERT INTO jobs (kind, payload) VALUES (%s, %s)",
                (event["type"], json.dumps(event["data"])),
            )

    return "", 200  # ağır iş arka plandaki işçide

Burada db ve jobs kendi uygulamanıza ait örnek yapılardır. Önemli olan desendir: doğrula, kaydet, kuyruğa bırak, hızlı yanıtla.

4. İş mantığında tutarı ve coini kontrol edin

Arka plandaki işçi, siparişi onaylamadan önce data.invoice.order_id, token ve paid_amount değerlerinin sizin kaydınızla eşleştiğini doğrulamalıdır. Sipariş numarası eşleştirmesini order_id ile fatura sipariş eşleştirme yazımızda anlattık.

Kaçan bildirimler için mutabakat

Sunucunuz iki günden uzun süre erişilemez kaldıysa ya da bir hata yüzünden olayları yanlış işlediyseniz, API ile durumu kendiniz kontrol edebilirsiniz. Bu yaklaşım, periyodik bir mutabakat görevi olarak da çalıştırılabilir.

from mercanpay import MercanPay

zp = MercanPay("https://mercanpay.com", os.environ["MERCANPAY_API_KEY"])

before = None
while True:
    page = zp.list_invoices(status="paid", limit=100, before=before)
    for inv in page["data"]:
        ensure_order_paid(inv["order_id"], inv["token"], inv["paid_amount"])  # idempotent
    before = page.get("next_before")
    if not before:
        break

ensure_order_paid fonksiyonu webhook işleyicinizle aynı koşullu güncellemeyi kullanmalıdır. Böylece mutabakat ile webhook aynı siparişi iki kez işlemez. Fazla ödenmiş faturalar için aynı döngüyü status="overpaid" ile de çalıştırın.

Mutabakatı ne sıklıkla çalıştırmalısınız?

Bu, hacminize ve siparişlerin ne kadar zamana duyarlı olduğuna bağlıdır. Genel bir yaklaşım:

  • Anında teslim edilen dijital ürünlerde webhook birincil kanaldır. Mutabakatı günde bir kez, gözden kaçan bir şey olmadığını doğrulamak için çalıştırmak çoğu zaman yeterlidir.
  • Bir kesinti yaşadığınızda sunucunuz tekrar ayağa kalkar kalkmaz, kesinti süresini kapsayacak şekilde bir kez elle çalıştırın. Yeniden denemeler zaten gelecektir, ama beklemek zorunda kalmazsınız.
  • Yeni bir entegrasyonu canlıya aldığınız ilk günlerde mutabakat sonuçlarını webhook kayıtlarınızla karşılaştırmak, işleyicinizdeki hataları erkenden ortaya çıkarır.

Mutabakat görevi herhangi bir sipariş için "ödendi ama bizde ödenmemiş görünüyor" durumu bulduysa bunu sessizce düzeltmekle yetinmeyin; bir günlük kaydı bırakın. Böyle bir fark, webhook işleyicinizde incelenmesi gereken bir sorun olduğuna işaret eder.

Panelde teslimat geçmişi

Panelde Webhooklar sayfasında gönderilen her olayı görebilirsiniz:

  • Olay türü ve hedef URL
  • Deneme sayısı ve durum (iletildi, bekliyor, başarısız)
  • HTTP yanıt kodu, yanıt süresi ve varsa hata

Bir olayı buradan yeniden gönderebilir, "Test gönder" ile bir test.ping olayı yollayabilirsiniz. Teslimat geçmişini CSV, Excel ya da PDF olarak da dışa aktarabilirsiniz. Bkz. kripto ödeme raporları.

Sık yapılan hatalar

  • Önce iş, sonra yanıt: E-posta gönderimini beklerken 10 saniyeyi aşmak, gereksiz tekrarlara yol açar.
  • Hata durumunda 200 dönmek: İşleyemediğiniz bir olaya 200 dönerseniz yeniden deneme olmaz. Gerçekten işleyemediyseniz 5xx dönün.
  • Tekrarları order_id ile değil hiçbir şeyle elememek: Aynı lisansın iki kez gönderilmesi en yaygın sonuçtur.
  • Yönlendirme yapan bir URL kullanmak: HTTP'den HTTPS'e ya da başka bir yola yönlendiren adresler 2xx sayılmaz. Webhook URL'si doğrudan işleyiciye işaret etmelidir.

Sık sorulan sorular

Başarısız olarak işaretlenmiş bir olayı yeniden alabilir miyim?

Evet. Panelde Webhooklar sayfasındaki teslimat geçmişinden olayı yeniden gönderebilirsiniz. Ayrıca API ile faturaların güncel durumunu her zaman sorgulayabilirsiniz.

Olaylar sırayla mı gelir?

Sıraya güvenmeyin. Yeniden denemeler nedeniyle olaylar farklı sırada ulaşabilir. İş mantığınızı fatura durumuna göre kurun.

Olay kimliği mi, order_id mi ile tekrar elemeliyim?

İkisini birlikte kullanın. Olay kimliği aynı olayın tekrarını, sipariş durumu kontrolü ise aynı siparişi etkileyen farklı olayları yakalar.

MercanPay ile başlayın

Kaybolmayan, imzalı ve yeniden denenen webhook'larla kripto ödeme almak için satıcı başvurunuzu yapın. Tüm ayrıntılar dokümantasyonda.

#Webhook#API#Entegrasyon#İdempotency

İlgili yazılar

Kripto ödemeleri dakikalar içinde almaya başlayın

USDT ve TRX (TRC20) ile ödeme alın. %0,4'ten başlayan komisyon, hazır ödeme sayfası, API ve webhook.