পাঠ্যক্রম খুলুন
প্রাথমিক পর্যায়

Webhooks: signature, duplicate ও নির্ভরযোগ্য delivery

Reliable Webhooks

এই পাঠের কুইজ ↓৫ মিনিট পড়াPHP 8.3+ · Laravel 12
এই পাঠের সূচিপত্র

এই পাঠে যা শিখবেন

  • Signed webhook গ্রহণ ও durable acknowledgement
  • Duplicate event ও retry সামলানো
  • Laravel transaction ও unique event ID

সমস্যা দিয়ে শুরু

Payment provider বলে payment সফল, কিন্তু customer-এর order pending। Callback-এর সময় আপনার server বন্ধ ছিল। পরে provider একই event তিনবার পাঠাল। Webhook হলো অন্য system থেকে asynchronous HTTP notification; reliable receiver বানাতে response code-এর পাশাপাশি storage, authentication এবং duplicate handling ভাবতে হয়।

সহজ করে বুঝি

Provider event তৈরি করে configured endpoint-এ POST করে। Receiver signature যাচাই করে, durable inbox-এ event রাখে, তারপর দ্রুত success response দেয়। Business processing worker পরে করতে পারে। একই event আবার এলে একই receipt ফিরিয়ে দেওয়া নিরাপদ। Event arrival order business order-এর নিশ্চয়তা নয়; payment failed-এর পরে পুরোনো pending event আসতে পারে। Event ID deduplication আর order state transition validation আলাদা দায়িত্ব।

পরিচিত একটি উপমা

ডাকপিয়ন registered parcel দিলে reception খাতায় tracking number লিখে গ্রহণ করে। একই নম্বর আবার এলে নতুন parcel বলে হিসাব করে না। কিন্তু parcel-এর নির্দেশ অনুযায়ী কাজ হয়েছে কি না warehouse আলাদা খাতায় রাখে। Reception receipt আর কাজ শেষ হওয়া এক জিনিস নয়।

নকশাটি দেখুন

Diagram লোড হচ্ছে…

প্রথম arrow untrusted input boundary।
Diagram-এর text flow দেখুন
flowchart TD
 P[Payment Provider] --> V[Verify raw body signature]
 V --> I[(Unique event inbox)]
 I --> A[Return 2xx]
 I --> W[Scheduled inbox worker]
 W --> O[(Validated order transition)]

প্রথম arrow untrusted input boundary। Verification পাস করলে unique event ID-সহ inbox commit হয়। Commit-এর আগে 2xx দিলে crash-এ event হারাতে পারেন। Scheduled worker pending inbox পড়ে; direct dispatch বাদ গেলেও inbox থেকে recover করা সম্ভব। Order update-এ amount, currency ও provider transaction identity যাচাই প্রয়োজন।

PHP ও Laravel-এ প্রয়োগ

নিচে controller-method fragment। এটি demo provider-এর HMAC protocol: X-Signature হলো raw body-এর hex SHA-256 HMAC। বাস্তব provider-এর SDK/protocol মেনে timestamp ও replay window যাচাই করুন। webhook_events.provider_event_id unique এবং payload text column থাকতে হবে; API route-এ browser session CSRF প্রযোজ্য নয়।

php
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;

public function receive(Request $request)
{
    $secret = config('services.demo_webhook.secret');
    abort_unless(is_string($secret) && $secret !== '', 503);
    $expected = hash_hmac('sha256', $request->getContent(), $secret);
    abort_unless(hash_equals($expected, (string) $request->header('X-Signature')), 401);
    $data = $request->validate(['id' => ['required', 'string', 'max:128']]);
    DB::table('webhook_events')->upsert([[
        'provider_event_id' => $data['id'],
        'payload' => $request->getContent(),
        'status' => 'pending',
    ]], ['provider_event_id'], ['provider_event_id']);
    return response()->json(['received' => true]);
}

সুবিধা, সীমাবদ্ধতা ও trade-off

Webhook polling কমায় এবং event দ্রুত জানায়; receiver downtime, provider retries ও operational recovery যোগ হয়। Inbox storage ব্যবহার করলে acknowledgement ও processing আলাদা হয়, কিন্তু pending backlog monitor করতে হয়। উপরের upsert duplicate-এ payload/status overwrite করে না; অন্য engine-এর unique index behavior যাচাই করতে হবে। একই ID-তে ভিন্ন payload সন্দেহজনক হলে আলাদা audit alert রাখুন।

সাধারণ ভুল

  • Parsed JSON serialize করে raw-body signature যাচাই করা।
  • User-supplied order status সরাসরি trust করা।
  • Signature secret source control বা request log-এ রাখা।

আরও একটু গভীরে

Durable inbox-এর worker claim atomic হওয়া দরকার। Processing exception-এ attempt count ও next_attempt_at লিখুন; terminal failures operator দেখতে পাবেন। Provider retry বন্ধ করে দিলে reconciliation job payment API থেকে final status আনতে পারে। HMAC message origin যাচাই করে, কিন্তু পুরোনো valid message replay আটকায় না; timestamp validation ও deduplication দুটোই দরকার।

মনে রাখুন

আগে verify, তারপর durable receive, শেষে acknowledge। Provider delivery আর business effect আলাদা state machine। Duplicate, reorder এবং missed event-কে স্বাভাবিক failure case ধরুন।

নিজে চেষ্টা করুন

একই valid webhook দুইবার পাঠিয়ে inbox-এ একটি row আছে পরীক্ষা করুন। Invalid signature, একই ID-তে অন্য body এবং database unavailable case-এর expected response লিখুন। Pending inbox recovery কীভাবে হবে সেটিও ব্যাখ্যা করুন।

নিজের বোঝা যাচাই করুন

1. কখন 2xx দেব?

Authentic event durable ভাবে গ্রহণ করার পরে। Memory-তে রেখে success দিলে process crash-এ provider আর retry নাও করতে পারে।

2. Unique ID-ই যথেষ্ট?

Duplicate delivery কমায়, কিন্তু business transition, amount ও currency validation করে না। Payment capture-এ আলাদা invariant থাকে।

3. Raw body কেন?

Whitespace বা key order বদলালে serialized JSON-এর bytes বদলায়। Provider যেই exact bytes sign করেছে সেগুলোই যাচাই করতে হয়।

4. Event order বিশ্বাস করব?

না। Delayed retry পুরোনো event আনতে পারে। Provider sequence/version বা authoritative state ব্যবহার করে invalid transition আটকান।

5. afterCommit dispatch করলেই inbox worker লাগবে না?

Dispatch crash gap থাকতে পারে। Inbox poller বা outbox dispatcher pending row recover করে; কেবল callback-এর ওপর নির্ভর করবেন না।

আরও পড়ুন

এই পাঠের কুইজ

এই পাঠ থেকে ২টি প্রশ্ন। উত্তর দিয়ে ব্যাখ্যা দেখুন; অধ্যায়ের কুইজ আলাদাভাবে দিতে হবে।

এই পাঠের ২টি প্রশ্নের উত্তর দিন। পাস করতে দুটিই সঠিক হতে হবে।

জমা দেওয়ার পর সঠিক উত্তর ও ব্যাখ্যা দেখবেন। ফলাফল এই ব্রাউজারে সংরক্ষিত থাকবে। অনুশীলনের ফল অধ্যায় সম্পন্নের হিসাবে যোগ হয় না।

সব বিষয় মিলিয়ে অনুশীলন করুন →

অগ্রগতি এই ব্রাউজারে সংরক্ষিত থাকে। শুধু পাঠ খুললে সম্পন্ন হয় না।