পাঠ্যক্রম খুলুন
মধ্যবর্তী পর্যায়

Dead-Letter Queue: ব্যর্থ message যাচাই ও replay

Dead-Letter Queues and Safe Replay

এই পাঠের কুইজ ↓৫ মিনিট পড়াPHP 8.3+ · Laravel 12
আগে পড়ে নিনLaravel Queue: job, retry ও timeout ↗
এই পাঠের সূচিপত্র

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

  • Transient failure ও poison message আলাদা করুন
  • Bounded retry-এর পরে quarantine করুন
  • Inspection ও replay নিরাপদ করুন

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

এক malformed address-এর invoice email job প্রতি সেকেন্ডে fail হয়ে queue-তে ফিরে আসছে। Worker-এর সব সময় সেটিতেই যাচ্ছে। পরে developer failed সব job একসঙ্গে retry করলেন, পুরোনো already-sent receipt আবার গেল। Failure সংরক্ষণ ও recovery policy নেই।

সহজ করে বুঝি

Dead-letter queue বা failed-job store unsuccessful message আলাদা করে রাখে, যাতে primary flow এগোয় এবং কারণ inspect করা যায়। Poison message একই defect-এ বারবার fail হয়। Retry limit, backoff, failure reason ও retention দরকার। Laravel failed_jobs record আর RabbitMQ DLX routing একই mechanism নয়, যদিও quarantine-এর উদ্দেশ্য কাছাকাছি।

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

ডাকঘর ভুল ঠিকানার চিঠি মূল delivery bag-এ অনন্তকাল ঘুরায় না; exception desk-এ রাখে। ঠিকানা ঠিক করার পরে আবার পাঠানো যায়। কিন্তু প্রাপক আগেই চিঠি পেয়েছেন কি না না জেনে সব পুরোনো চিঠি একসঙ্গে পাঠালে duplicate হবে।

নকশাটি দেখুন

Diagram লোড হচ্ছে…

Transient failure ও poison message আলাদা করুন
Diagram-এর text flow দেখুন
flowchart LR
 Q[Primary Queue] --> W[Worker]
 W -->|Temporary error| R[Bounded Backoff]
 R --> Q
 W -->|Attempts exhausted| D[Failed Store or DLQ]
 D --> I[Inspect and Fix]
 I -->|Approved idempotent replay| Q

Temporary failure সীমিত retry পায়। Attempts শেষ বা invalid message হলে quarantine path চলে। Operator reason, payload version ও side effect state inspect করেন। Fix-এর পরে stable event identity দিয়ে controlled replay হয়। Replay primary traffic overwhelm করবে না এমন rate limit দরকার।

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

সম্পূর্ণ Laravel job class fragment দেখানো হলো; SendInvoiceService app-defined এবং idempotent provider contract ব্যবহার করবে। Database failed job driver ও table configured থাকতে হবে। $tries এবং backoff finite retry দেয়; permanent validation error আলাদা fail করা যায়।

php
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Queue\Queueable;

final class SendInvoice implements ShouldQueue
{
    use Queueable;
    public int $tries = 4;
    public int $timeout = 20;
    public function __construct(public string $invoiceId) {}
    public function backoff(): array
    {
        return [10, 60, 300];
    }
    public function handle(App\Services\SendInvoiceService $sender): void
    {
        $sender->send($this->invoiceId);
    }
    public function failed(?Throwable $exception): void
    {
        logger()->error('invoice.delivery_failed', [
            'invoice_id' => $this->invoiceId,
            'error_type' => $exception ? $exception::class : 'unknown',
        ]);
    }
}

এটি PHP 8.3+ ও Laravel 12-এর শিক্ষামূলক fragment; সম্পূর্ণ application নয়। সংশ্লিষ্ট route-এ authentication ও resource authorization প্রয়োগ করতে হবে। নিচের অনুশীলনে failure ইচ্ছা করে তৈরি করুন; শুধু সফল response দেখে correctness ধরে নেবেন না।

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

Quarantine healthy traffic বাঁচায় এবং investigation সম্ভব করে। আলাদা store unattended থাকলে সেটি স্থায়ী data loss-এর আড়াল হয়। Retention কম হলে evidence হারায়, বেশি হলে sensitive payload জমে। Age এবং failure category অনুযায়ী alert ও owner দিন।

সাধারণ ভুল

  • Immediate unlimited requeue দিয়ে poison loop করা।
  • কারণ না বুঝে retry all চালানো।
  • Failed store-এর sensitive payload public admin screen-এ দেখানো।

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

RabbitMQ dead-lettering reject, expiration বা configured queue limits-এর মতো কারণে route করতে পারে; deployment semantics documentation দিয়ে যাচাই করুন। Dead-letter cycle নিজেও loop করতে পারে। Replay-তে original event ID বজায় রেখে আলাদা replay-attempt identity audit করা ভালো।

Service temporary error দিক, attempts শেষে failed store-এ row আসা চাই। Fix করার পরে একটি job manual retry করুন, পুরো backlog নয়। প্রথম delivery-তে effect হয়ে ack হারানো scenario-তে replay duplicate effect না করুক। Queue age ও failed age দুটো মাপুন।

মনে রাখুন

  • Retry সীমিত, quarantine দৃশ্যমান।
  • DLQ owner ও repair workflow চাই।
  • Replay নতুন business intention নয়।

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

Failed payment notification-এর runbook লিখুন: inspect, redact, provider status verify, approve, rate-limited replay এবং result audit।

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

1. DLQ মানেই loss?

না। এটি recoverable quarantine হতে পারে, কিন্তু কেউ inspect না করলে কার্যত delivery অসম্পূর্ণ থেকে যায়।

2. সব failure retry?

না। Invalid schema বা permanent address failure input fix না করলে আবারও ব্যর্থ হবে।

3. Laravel failed_jobs broker DLQ?

একই implementation নয়। Framework database record এবং broker routing-এর boundary আলাদা।

4. Replay-তে নতুন event ID?

সাধারণত original business identity রাখুন, যাতে deduplication কাজ করে; replay attempt আলাদা audit করা যায়।

5. কী alert?

Oldest failed age, failure category ও affected business operations; শুধু count দিয়ে urgency বোঝা যায় না।

আরও পড়ুন

এই পাঠের কুইজ

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

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

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

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

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