مهران علم‌بیگی - زمستان ۱۴۰۴

مفهوم Webhook یک مکانیزم ارتباطی event-driven است که به یک سیستم اجازه می‌دهد به‌محض رخ دادن یک رویداد، به‌صورت خودکار به سیستم دیگر اطلاع بدهد. برخلاف APIهای معمولی که کلاینت باید به‌طور مداوم سرور را صدا بزند تا ببیند تغییری اتفاق افتاده یا نه، در Webhook این سرور است که هنگام وقوع یک event، یک درخواست HTTP به آدرس از پیش تعیین‌شده‌ی کلاینت ارسال می‌کند. به همین دلیل Webhook معمولاً به‌عنوان «push-based communication» شناخته می‌شود.

در Webhook، کلاینت ابتدا یک URL در اختیار سرویس‌دهنده قرار می‌دهد که به آن endpoint یا callback URL گفته می‌شود. این URL جایی است که سرور باید رویدادها را به آن ارسال کند. هر زمان که رویداد مشخصی رخ دهد، مثلاً ثبت سفارش جدید، پرداخت موفق، تغییر وضعیت کاربر یا آپلود فایل، سرور یک HTTP request معمولاً از نوع POST به آن URL می‌فرستد و اطلاعات مربوط به رویداد را در بدنه‌ی درخواست قرار می‌دهد. این اطلاعات اغلب به‌صورت JSON ارسال می‌شوند و شامل جزئیات event هستند.

مزیت اصلی Webhook کاهش latency و مصرف منابع است. در مدل polling، کلاینت مجبور است هر چند ثانیه یا دقیقه یک بار API را صدا بزند تا ببیند داده‌ای تغییر کرده یا نه، که هم باعث مصرف بیهوده‌ی شبکه و CPU می‌شود و هم همیشه با تأخیر همراه است. در Webhook، اطلاع‌رسانی تقریباً لحظه‌ای انجام می‌شود، چون به محض وقوع event درخواست ارسال می‌شود و نیازی به چک کردن مداوم نیست.

از نظر فنی، Webhook معمولاً روی HTTP معمولی پیاده‌سازی می‌شود و stateless است. امنیت آن اغلب با استفاده از secret key، امضای دیجیتال یا token انجام می‌شود تا کلاینت مطمئن شود درخواست واقعاً از سمت سرویس معتبر آمده است. در بسیاری از سیستم‌ها، payload Webhook همراه با یک signature ارسال می‌شود که کلاینت با استفاده از secret مشترک آن را اعتبارسنجی می‌کند.

مفهوم Webhook بیشتر برای integration بین سیستم‌ها استفاده می‌شود، مثلاً اتصال درگاه پرداخت به بک‌اند، هماهنگ‌سازی سیستم سفارش با انبار، ارسال اعلان به سرویس دیگر بعد از تغییر وضعیت، یا تریگر کردن یک pipeline اتوماسیون. به‌طور خلاصه، Webhook یعنی «به‌جای اینکه مدام بپرسی چیزی تغییر کرده یا نه، خود سیستم بهت خبر می‌دهد».

معماری Event-driven چیه؟

مفهوم Event-driven یک الگوی معماری است که در آن جریان سیستم بر اساس «رویدادها» شکل می‌گیرد، نه بر اساس فراخوانی مستقیم و هم‌زمان سرویس‌ها. در این مدل، به‌جای اینکه یک کامپوننت مستقیماً سرویس دیگری را صدا بزند و منتظر پاسخ بماند، یک رویداد رخ می‌دهد و سیستم‌هایی که به آن رویداد علاقه‌مند هستند، به‌صورت مستقل به آن واکنش نشان می‌دهند.

رویداد یا Event نشان‌دهنده‌ی وقوع یک اتفاق در سیستم است، مثل ثبت شدن یک کاربر، انجام موفق پرداخت، تغییر وضعیت سفارش یا آپلود یک فایل. وقتی چنین اتفاقی رخ می‌دهد، تولیدکننده‌ی رویداد آن را منتشر می‌کند، بدون اینکه بداند چه سرویس‌هایی قرار است از آن استفاده کنند. سرویس‌های مصرف‌کننده یا Subscriber، قبلاً اعلام کرده‌اند که به این نوع رویداد علاقه‌مند هستند و با دریافت آن، منطق خودشان را اجرا می‌کنند.

ویژگی کلیدی معماری event-driven دیکاپل بودن است. تولیدکننده‌ی رویداد هیچ وابستگی مستقیمی به مصرف‌کننده‌ها ندارد؛ نه نام آن‌ها را می‌داند، نه تعدادشان را، و نه نحوه‌ی پیاده‌سازی‌شان را. این موضوع باعث می‌شود اضافه یا حذف کردن سرویس‌ها بدون تغییر در سرویس اصلی ممکن باشد. همچنین مقیاس‌پذیری به‌مراتب ساده‌تر می‌شود، چون هر مصرف‌کننده می‌تواند مستقل از بقیه scale شود.

ارتباط در این معماری معمولاً asynchronous است. یعنی بعد از انتشار رویداد، تولیدکننده منتظر پردازش آن توسط مصرف‌کننده‌ها نمی‌ماند و مسیر کاری خودش را ادامه می‌دهد. این ویژگی latency مؤثر سیستم را کاهش می‌دهد و از ایجاد bottleneck جلوگیری می‌کند. البته در عوض، سیستم از حالت کاملاً هم‌زمان خارج می‌شود و مدیریت consistency و error handling پیچیده‌تر می‌شود.

پیاده‌سازی event-driven می‌تواند به شکل‌های مختلفی انجام شود. ساده‌ترین شکل آن Webhook است که در آن یک سرویس هنگام وقوع event یک HTTP request به سرویس دیگر ارسال می‌کند. شکل‌های پیشرفته‌تر شامل استفاده از Message Brokerها یا Event Busها مثل Kafka، RabbitMQ یا Google Pub/Sub است که رویدادها را دریافت، ذخیره و بین مصرف‌کننده‌ها توزیع می‌کنند. در این حالت، تولیدکننده فقط رویداد را publish می‌کند و broker مسئول تحویل مطمئن آن به مصرف‌کننده‌هاست.

معماری event-driven معمولاً در کنار معماری microservices استفاده می‌شود، چون باعث کاهش coupling، افزایش resilience و بهبود scalability می‌شود. البته این معماری چالش‌هایی هم دارد؛ از جمله دشواری در trace کردن جریان سیستم، پیچیدگی دیباگ، و نیاز به طراحی دقیق برای idempotency و مدیریت خطا.

به‌طور خلاصه، event-driven یعنی سیستم به‌جای فراخوانی مستقیم و خطی، بر پایه‌ی انتشار و واکنش به رویدادها کار می‌کند؛ هر اتفاق یک event است و هر سرویس فقط در صورت نیاز به آن واکنش نشان می‌دهد.