Webhook یعنی وقتی رویدادی در سرویس خارجی رخ میدهد (پرداخت تأیید شد، سفارش آماده شد)، آن سرویس یک درخواست HTTP — معمولاً POST — به URL شما میفرستد. Polling برعکس است: شما هر چند ثانیه یا دقیقه API میزنید و میپرسید «آیا چیزی عوض شده؟». در اتوماسیون داده، webhook برای رویدادهای لحظهای و polling برای sync دورهای bulk منطقیتر است. مبنای API در راهنمای دریافت داده از API.
- Webhook = push رویداد؛ polling = pull دورهای.
- endpoint شما باید سریع ۲xx بدهد؛ پردازش سنگین async.
- امضا (HMAC) و idempotency برای تحویل تکراری.
تفاوت عملی
| معیار | Webhook | Polling |
|---|---|---|
| تأخیر | ثانیهها پس از رویداد | تا یک interval کامل (مثلاً ۵ دقیقه) |
| بار روی شما | فقط وقتی رویداد هست | مداوم حتی اگر تغییری نباشد |
| بار روی ارائهدهنده | push کنترلشده | هر مشتری هر N ثانیه میزند |
| پیچیدگی | endpoint عمومی، TLS، امضا | cron + client سادهتر |
| با scrape | مکمل (اعلان سفارش) | همراستا با job شبانه scrape |
مثال: پرداخت → سفارش در Django
ارائهدهنده پرداخت بعد از موفقیت، JSON شامل order_id و event_id میفرستد. view شما امضا را با secret مشترک چک میکند، رویداد را idempotent پردازش میکند (اگر event_id قبلاً دیده شده → ۲۰۰ بدون کار دوباره)، وضعیت سفارش را به «پرداختشده» بهروز میکند.
امنیت و امضا
secret در env نگه دارید؛ header امضا (مثلاً X-Signature) را با HMAC payload محاسبه و مقایسه کنید. timestamp در payload برای جلوگیری از replay قدیمی. IP allowlist در صورت مستند بودن.
Retry و تحویل تکراری
اگر endpoint شما ۵xx یا timeout بدهد، ارائهدهنده معمولاً همان رویداد را دوباره میفرستد. بنابراین handler باید idempotent باشد: کلید یکتا event_id در DB؛ duplicate → ۲۰۰ OK.
HTTP response و timeout
ارائهدهنده انتظار پاسخ سریع دارد (اغلب چند ثانیه). کار سنگین (ایمیل، scrape follow-up) را در queue بگذارید و بلافاصله ۲۰۰ برگردانید. اگر sync پردازش کنید و ۳۰ ثانیه طول بکشد، retryهای پشتسرهم و duplicate زیاد میشود.
# ایدهٔ idempotency — شبهکد
def payment_webhook(request):
verify_hmac(request.body, request.headers["X-Signature"])
payload = json.loads(request.body)
if WebhookEvent.objects.filter(event_id=payload["event_id"]).exists():
return HttpResponse(status=200)
WebhookEvent.objects.create(event_id=payload["event_id"], raw=payload)
enqueue_process_payment(payload["order_id"])
return HttpResponse(status=200)
Webhook در برابر زمانبندی scrape
Webhook برای «الان یک سفارش جدید آمد» عالی است. برای «هر شب همه قیمتهای ۵۰ هزار محصول» هنوز cron یا Celery لازم است. بعضی پروژهها hybrid دارند: webhook برای trigger فوری + job شبانه برای تکمیل dataset.
در محیط توسعه از tunnel (مثلاً ngrok) برای تست webhook استفاده کنید؛ URL ثابت production را در پنل ارائهدهنده ثبت کنید.
در عمل چه انتخابی کنیم؟
رویداد لحظهای با قرارداد push از سرویس → webhook با امضا و idempotency. فقط sync دورهای bulk بدون push رسمی → polling یا scrape زمانبندیشده. پیادهسازی endpoint: توسعه API. خطا و retry سمت ingest: مدیریت خطا.