ওজন বেশি টুল না নিয়ে কিভাবে সহজ ডাটাবেস‑কিউ আর ছোট worker ব্যবহার করে ইমেইল, রিপোর্ট ও ওয়েবহুক ডেলিভারি নিরাপদভাবে, রিট্রাই, ব্যাকঅফ ও ডেড‑লেটার সহ বাস্তবায়ন করবেন তা শিখুন।

{ "user_id": 42, "template": "welcome" }।\n\nবড় ব্লবগুলো রাখার এড়াবেন (পূর্ণ HTML ইমেইল, বড় রিপোর্ট ডেটা, বিশাল ওয়েবহুক বডি)। এগুলো আপনার ডাটাবেস দ্রুত বড় করে এবং ডিবাগিং কঠিন করে তোলে। যদি জব‑এ বড় ডকুমেন্ট লাগে, তাহলে রেফারেন্স রাখুন: report_id, export_id, বা একটি ফাইল কী। worker চালানোর সময় পূর্ণ ডেটা আনে।\n\n### যে ফিল্ডগুলো নিজেই মূল্য দেয়\n\nকমপক্ষে নিম্নলিখিতগুলোর জায়গা রাখুন:\n\n- job_type + payload: job_type handler নির্বাচন করে (send_email, generate_report, deliver_webhook)। payload ছোট ইনপুট ধরে যেমন IDs ও অপশন।\n- status: এটি স্পষ্ট রাখুন (উদাহরণ: queued, running, succeeded, failed, dead)।\n- attempt tracking: attempt_count এবং max_attempts যাতে আপনি Retry বন্ধ করতে পারেন যখন স্পষ্টভাবে কাজ হবে না।\n- time fields: created_at এবং next_run_at (কখন যোগ্য হবে)। started_at এবং finished_at যোগ করলে ধীর জবগুলোতে আরও দৃশ্যমানতা পাবেন।\n- idempotency + last error: একটি idempotency_key ডুপ জেনারেশন প্রতিরোধ করতে এবং last_error যাতে কেন ব্যর্থ হল তা লগ ছাড়া দেখার ব্যবস্থা থাকে।\n\nIdempotency শুনতে জটিল, কিন্তু ধারণা সহজ: একই জব যদি দুইবার চলে, দ্বিতীয়বারটি কোন বিপজ্জনক কাজ করবে না। উদাহরণ: একটি ওয়েবহুক ডেলিভারি জব webhook:order:123:event:paid মত idempotency কী ব্যবহার করতে পারে যাতে রিট্রাই overlap হলেও একই ইভেন্ট বারবার ডেলিভার না হয়।\n\nআরও কয়েকটি মৌলিক সংখ্যা প্রথম দিকে ধরুন। বড় ড্যাশবোর্ড দরকার নেই, শুধু এমন কুয়েরি যা বলে: কতগুলো জব কিউড আছে, কতগুলো ব্যর্থ হচ্ছে, এবং সবচেয়ে পুরানো কিউড জবটির বয়স কত।\n\n## ধাপে ধাপে: আজই আপনি যে ডাটাবেস কিউ বানাতে পারেন\n\nআপনার কাছে যদি ডাটাবেস থাকে, নতুন ইনফ্রা যোগ না করেই একটি ব্যাকগ্রাউন্ড কিউ শুরু করতে পারেন। জবগুলো সারি হবে, এবং একটি worker একটি প্রসেস যা নির্ধারিত সারি তুলে কাজ করবে।\n\n### ১) jobs টেবিল তৈরি করুন\n\nটেবিলটি ছোট ও সাদাসিধে রাখুন। আপনাকে যথেষ্ট ফিল্ড চাই যাতে পরে জব চালানো, রিট্রাই ও ডিবাগ করা যায়।\n\n```sqlCREATE TABLE jobs ( id bigserial PRIMARY KEY, job_type text NOT NULL, payload jsonb NOT NULL, status text NOT NULL DEFAULT 'queued', -- queued, running, done, failed attempts int NOT NULL DEFAULT 0, next_run_at timestamptz NOT NULL DEFAULT now(), locked_at timestamptz, locked_by text, last_error text, created_at timestamptz NOT NULL DEFAULT now(), updated_at timestamptz NOT NULL DEFAULT now() );
CREATE INDEX jobs_due_idx ON jobs (status, next_run_at);
\nযদি আপনি Postgres‑এর উপর নির্মাণ করেন (Go ব্যাকএন্ডের সাথে সাধারণ), `jsonb` জব ডেটা সংরক্ষণের একটি ব্যবহারিক উপায়, যেমন `{ "user_id":123,"template":"welcome" }`।\n\n### ২) নিরাপদভাবে enqueue করুন (বিশেষত ব্যবহারকারীর অ্যাকশনের জন্য)\n\nযখন কোনও ব্যবহারকারীর অ্যাকশন একটি জব ট্রিগার করবে (ইমেইল পাঠানো, ওয়েবহুক ফায়ার করা), সম্ভব হলে জব রোটি মূল পরিবর্তনের একই ডাটাবেস ট্রানজ্যাকশনে লিখুন। এতে যদি প্রধান লেখার পরে ক্র্যাশ ঘটে, "ব্যবহারকারী তৈরি কিন্তু জব নেই" সমস্যা রোধ হয়।\n\nউদাহরণ: একজন ব্যবহারকারী সাইন আপ করলে, এক ট্রানজ্যাকশনে user রো এবং একটি `send_welcome_email` জব ইন্সার্ট করুন।\n\n### ৩) একটি worker লুপ চালান যা স্কেল করতে পারে\n\nএকটি worker একই চক্র পুনরাবৃত্তি করে: একটি উপযুক্ত জব খুঁজে, এটিকে ক্লেইম করে যাতে কেউ আর না নিতে পারে, প্রসেস করে, তারপর সম্পন্ন বা রিট্রাই নির্ধারণ করে।\n\nঅর্থাৎ বাস্তবে:\n\n- `status='queued'` এবং `next_run_at <= now()` এমন একটি জব বাছুন।\n- এটিকে অ্যাটোমিকভাবে ক্লেইম করুন (Postgres‑এ `SELECT ... FOR UPDATE SKIP LOCKED` সাধারণ পদ্ধতি)।\n- সেট করুন `status='running'`, `locked_at=now()`, `locked_by='worker-1'`।\n- জব প্রসেস করুন।\n- সেট করুন সম্পন্ন (`done`/`succeeded`) অথবা `last_error` রেকর্ড করে পরবর্তী চেষ্টা নির্ধারণ করুন।\n\nএকাধিক worker একই সময়ে চালানো যাবে। ক্লেইম ধাপই দ্বৈত‑পিকিং রোধ করে।\n\n### ৪) শাটডাউন হ্যান্ডেল করুন যাতে জব ভাঙে না\n\nশাটডাউনে, নতুন জব নেয়া বন্ধ করুন, চলমানটি শেষ করে বেরিয়ে যান। যদি একটি প্রসেস মধ্যেই মরতে যায়, একটি সহজ নীতি ব্যবহার করুন: `running` অবস্থায় আটকে থাকা জবগুলোকে টাইমআউট পেরিয়ে গেলে একটি পর্যায়িক "reaper" টাস্ক পুনরায় কিউতে ফিরিয়ে দিক।\n\nআপনি যদি Koder.ai‑তে বানাচ্ছেন, ইমেইল, রিপোর্ট, ও ওয়েবহুকের জন্য এই ডাটাবেস-কিউ প্যাটার্ন একটি ভাল ডিফল্ট।\n\n## রিট্রাই ও ব্যাকঅফ যাতে বিশৃঙ্খলা না হয়\n\nরিট্রাই হল কিউকে শান্ত রাখার কৌশল যখন বাস্তব জীবন গড়মিল দেখায়। স্পষ্ট নিয়ম না হলে, রিট্রাইগুলো সোচাল্য গড়গড়িয়ে চলে যা ব্যবহারকারীকে স্প্যাম করে, API‑কে হামা করে, এবং আসল বাগ লুকিয়ে দেয়।\n\nপ্রথমে ঠিক করুন কোনটি রিট্রাই হবে এবং কোনটিতে দ্রুত ব্যর্থ হওয়া উচিত।\n\nঅস্থায়ী সমস্যাগুলো পুনরায় চেষ্টা করুন: নেটওয়ার্ক টাইমআউট, 502/503 ত্রুটি, রেট লিমিট, বা সামান্য ডাটাবেস কানেকশন ব্লিপ।\n\nযেগুলো কাজ করবে না সেগুলো দ্রুত ব্যর্থ করুন: মিসিং ইমেইল ঠিকানা, একটি ভ্যালিডেশন-ভুলের কারণে ওয়েবহুক 400, বা ডিলিট হওয়া অ্যাকাউন্টের জন্য রিপোর্ট অনুরোধ।\n\nব্যাকঅফ হল চেষ্টা-গুলোর মাঝের বিরতি। লিনিয়ার ব্যাকঅফ (5s, 10s, 15s) সহজ, কিন্তু তা ট্র্যাফিকের ওয়েভ তৈরি করতে পারে। এক্সপোনেনশিয়াল ব্যাকঅফ (5s, 10s, 20s, 40s) লোড ভালভাবে ছড়ায় এবং ওয়েবহুক ও তৃতীয়‑পক্ষ প্রদানকারীর জন্য সাধারণত নিরাপদ। জিটার (একটি ছোট র্যান্ডম বিলম্ব) যোগ করুন যাতে হাজারো জব একই সেকেন্ডে একসাথে রিট্রাই না করে।\n\nউৎপাদনে ভাল আচরণ করা কিছু নিয়ম:\n\n- স্পষ্টভাবে অস্থায়ী ত্রুটিতে রিট্রাই করুন (টাইমআউট, 429, 5xx)।\n- এক্সপোনেনশিয়াল ব্যাকঅফ ও জিটার ব্যবহার করুন।\n- চেষ্টা সীমা নির্ধারণ করুন, তারপর থামিয়ে জবকে failed হিসাবে মার্ক করুন।\n- প্রতি চেষ্টা‑এর জন্য একটি টাইমআউট নির্ধারণ করুন যাতে worker আটকে না থাকে।\n- প্রতিটি জবকে idempotent রাখুন যাতে রিট্রাই ডুপ্লিকেট সৃষ্টি না করে।\n\nMax attempts ক্ষতির সীমা। বহু দলের জন্য 5 থেকে 8 চেষ্টা যথেষ্ট। তার পরে রিট্রাই বন্ধ করে জবটি রিভিউ‑এর জন্য পার্ক করুন (ডেড-লেটার ফ্লো) যেন অনন্ত লুপ না হয়।\n\nটাইমআউটগুলো "জম্বি" জব রোধ করে। ইমেইলের জন্য প্রতি চেষ্টা 10–20 সেকেন্ড হতে পারে। ওয়েবহুকের জন্য প্রায় 5–10 সেকেন্ড ছোট টাইমআউট মানানসই, কারণ রিসিভার ডাউন থাকতে পারে এবং আপনাকে দ্রুত এগোতে হবে। রিপোর্ট জেনারেশন কয়েক মিনিট নিতে পারে, কিন্তু তবুও একটি হার্ড কাটঅফ থাকা উচিত।\n\nKoder.ai‑তে এটা বানালে `should_retry`, `next_run_at`, এবং idempotency কী‑কে প্রথম শ্রেণির ফিল্ড হিসেবে বিবেচনা করুন। এই ছোট বিবরণগুলো সিস্টেমকে শান্ত রাখে যখন কিছু ভুল হয়।\n\n## ডেড-লেটার হ্যান্ডলিং ও সরল অপারেশন\n\nডেড-লেটার অবস্থা হল যেখানে জবগুলো যায় যখন রিট্রাই করা নিরাপদ বা উপকারী নয়। এটি নীরব ব্যর্থতাকে এমন কিছুতে পরিণত করে যা আপনি দেখতে, সার্চ করতে এবং অ্যাক্ট করতে পারেন।\n\n### ডেড-লেটার জবে কি সংরক্ষণ করবেন\n\nকি হয়েছে বুঝতে এবং জবটি পুনরায় চালাতে পর্যাপ্ত কনটেক্সট রাখুন, তবে সিক্রেট নিয়ে সতর্ক থাকুন।\n\nরাখুন:\n\n- জব ইনপুট (payload) ঠিক যেমনটি ব্যবহার হয়েছিল, সঙ্গে job type ও version\n- শেষ ত্রুটি বার্তা এবং ছোট স্ট্যাক ট্রেস (বা যদি স্ট্যাক না থাকে তাহলে একটি ত্রুটি কোড)\n- চেষ্টা গণনা, প্রথম রান টাইম, শেষ রান টাইম, এবং পরবর্তী রান টাইম (যদি শিডিউল করা থাকে)
- worker identity (সার্ভিস নাম, হোস্ট) এবং লগের জন্য একটি correlation ID
- একটি ডেড-লেটার কারণ (টাইমআউট, ভ্যালিডেশন ত্রুটি, vendor‑এর 4xx ইত্যাদি)\n\nপে-লোডে টোকেন বা ব্যক্তিগত ডেটা থাকলে, সেগুলো redact বা এনক্রিপ্ট করে রাখুন।\n\n### একটি সরল ট্রায়াজ ওয়ার্কফ্লো\n\nকোন জব ডেড-লেটে গেলে দ্রুত সিদ্ধান্ত নিন: পুনরায় চেষ্টা, ঠিক করা, বা উপেক্ষা করা।\n\n- পুনরায় চেষ্টা: বাহ্যিক আউটেজ ও টাইমআউটের জন্য।\n- ঠিক করা: খারাপ ডেটা (মিসিং ইমেইল, ভুল ওয়েবহুক URL) বা আপনার কোডে বাগ হলে।\n- উপেক্ষা: বিরল হওয়া উচিত, কিন্তু তখনকার জন্য জবটি আর প্রাসঙ্গিক না হলে (যেমন কাস্টমার অ্যাকাউন্ট মুছে ফেলা হয়েছে) এটি বৈধ। উপেক্ষা করলে একটি কারণ রেকর্ড করুন যেন জব ভাপসায়নি বলে মনে না হয়।\n\nম্যানুয়াল রিকিউটি নিরাপদ: এটি একটি নতুন জব তৈরি করে এবং পুরনোটি অপরিবর্তিত রাখে। ডেড-লেটার জবকে মার্ক করুন কারা রিকিউ করেছে, কখন এবং কেন, তারপর নতুন একটি কপি নতুন ID‑এ enqueue করুন।\n\nঅ্যালার্টিংয়ের জন্য এমন সিগন্যাল দেখুন যা বাস্তব ব্যর্থতার ইঙ্গিত দেয়: ডেড-লেটার কাউন্ট দ্রুত বৃদ্ধি, একই ত্রুটি অনেক জবে পুনরাবৃত্তি, এবং পুরনো কিউড জব যা ক্লেইম হচ্ছে না।\n\nKoder.ai ব্যবহার করলে স্ন্যাপশট ও রোলব্যাক সাহায্য করে যখন ব্যাড রিলিজ হঠাৎ ফেইলিওর বাড়ায়—আপনি দ্রুত ব্যাক আউট করে তদন্ত করতে পারেন।\n\nশেষে, ভেন্ডর আউটেজের জন্য সেফটি ভ্যালভ যোগ করুন। প্রতি প্রদানকারীতে পাঠ সীমা (rate‑limit) দিন, এবং সার্কিট ব্রেকার ব্যবহার করুন: যদি কোনো ওয়েবহুক endpoint কঠোরভাবে ব্যর্থ হয়, নতুন চেষ্টা সাময়িকভাবে থামান যাতে আপনি ও তারা উভয়কেই অতিরিক্ত লোড না দেন।\n\n## ইমেইল, রিপোর্ট, ও ওয়েবহুকের প্যাটার্নসমূহ\n\nপ্রতিটি job টাইপের জন্য স্পষ্ট নিয়ম হলে কিউ সবচেয়ে ভালভাবে কাজ করে: কীকে সাফল্য বলা হবে, কী রিট্রাই হবে, এবং কী কখনই দুইবার ঘটতে পারবে না।\n\n**ইমেইল।** বেশিরভাগ ইমেইল ব্যর্থতা অস্থায়ী: প্রদানকারী টাইমআউট, রেট লিমিট, বা ছোট আউটেজ। এগুলোকে রিট্রাই করা উচিত, ব্যাকঅফ সহ। ডুপ্লিকেট পাঠ হওয়াটাই বড় ঝুঁকি, তাই ইমেইল জবগুলো idempotent রাখুন। একটি স্থিতিশীল dedupe কী সংরক্ষণ করুন, যেমন `user_id + template + event_id` এবং যদি সেই কী আগে পাঠানো হয়ে থাকে তো পাঠ বন্ধ করুন।\n\nটেমপ্লেট নাম ও ভার্সন (বা রেন্ডার করা সাবজেক্ট/বডি‑এর হ্যাশ) রাখা দরকার—যদি কখনও জব পুনরায় চালাতে হয়, আপনি ঠিক একই কনটেন্ট পুনরায় পাঠাবেন নাকি সর্বশেষ টেমপ্লেট থেকে পুনরায় জেনারেট করবেন তা বেছে নিতে পারবেন। যদি প্রদানকারী একটি message ID দেয়, সেটা সেভ করুন যাতে সাপোর্ট ট্রেস করতে পারে।\n\n**রিপোর্ট।** রিপোর্ট ভিন্নভাবে ব্যর্থ হয়। সেগুলো মিনিট ধরে চলতে পারে, pagination সীমা লাগতে পারে, বা সবকিছু একসঙ্গে করলে মেমরি শেষ হতে পারে। কাজকে ছোট টুকরোতে ভাগ করুন। সাধারণ প্যাটার্ন: একটি "report request" জব বহু "page" বা "chunk" জব তৈরি করে, প্রতিটি ডেটার স্লাইস প্রোসেস করে।\n\nরিজাল্টগুলো পরে ডাউনলোডের জন্য সেভ করুন যাতে ব্যবহারকারী অপেক্ষা না করে। এটি হতে পারে একটি ডাটাবেস টেবিল `report_run_id` দ্বারা কী করা, অথবা একটি ফাইল রেফারেন্স + মেটাডেটা (status, row count, created_at)। UI‑তে "processing" বনাম "ready" দেখানোর জন্য progress ফিল্ড যোগ করুন।\n\n**ওয়েবহুক।** ওয়েবহুকগুলোর মূল বিষয় হল ডেলিভারি নির্ভরযোগ্যতা, স্পীড নয়। প্রতিটি রিকোয়েস্ট সাইন করুন (উদাহরণ: HMAC একটি শেয়ার্ড সিক্রেট দিয়ে) এবং রেপ্লে প্রতিরোধে একটি টাইমস্ট্যাম্প দিন। তখনি রিট্রাই করুন যখন রিসিভার পরে সফল হতে পারে।\n\nসহজ নিয়ম সেট:\n\n- টাইমআউট ও 5xx উত্তরগুলোর উপর রিট্রাই করুন, ব্যাকঅফ এবং ম্যাক্স অ্যাটেম্পট কৃতভাবে ব্যবহার করুন।\n- বেশিরভাগ 4xx রেসপন্সকে স্থায়ী ত্রুটি মনে করুন এবং রিট্রাই বন্ধ করুন।\n- ডিবাগের জন্য শেষ স্ট্যাটাস কোড ও ছোট রেসপন্স বডি রেকর্ড করুন।\n- রিসিভার যাতে ডুপ্লিকেট উপেক্ষা করতে পারে সে জন্য idempotency কী ব্যবহার করুন।\n- পে-লোড সাইজ ক্যাপ করুন এবং আপনি আসলে যা পাঠিয়েছেন তা লগ করুন।\n\n**অর্ডারিং এবং অগ্রাধিকার।** বেশিরভাগ জবে কঠোর অর্ডারিং দরকার হয় না। যখন গুরুত্বপূর্ণ হয়, তা সাধারণত per-key (প্রতি ব্যবহারকারী, প্রতি ইনভয়েস, প্রতি ওয়েবহুক এন্ডপয়েন্ট) হয়। `group_key` যোগ করুন এবং শুধুমাত্র একই key‑এর জন্য একটিই ইন‑ফ্লাইট জব রাখুন।\n\nঅগ্রাধিকারের জন্য, জরুরি কাজ আলাদা করুন ধীর কাজ থেকে। একটি বড় রিপোর্ট ব্যাকলগ পাসওয়ার্ড রিসেট ইমেইল বিলম্ব করুক না।\n\nউদাহরণ: কোনো পারচেসের পরে আপনি (1) অর্ডার কনফার্মেশন ইমেইল, (2) একটি পার্টনার ওয়েবহুক, এবং (3) একটি রিপোর্ট আপডেট জব enqueue করেন। ইমেইল দ্রুত রিট্রাই করতে পারে, ওয়েবহুক দীর্ঘ ব্যাকঅফের সাথে রিট্রাই করে, এবং রিপোর্ট পরে লো‑প্রায়োরিটি তে চলে।\n\n## একটি বাস্তবসম্মত উদাহরণ: সাইনআপ ফ্লো + ওয়েবহুক + নাইটলি রিপোর্ট\n\nএকজন ব্যবহারকারী আপনার অ্যাপে সাইন আপ করে। তিনটি জিনিস ঘটবে, কিন্তু এদের কোনোটিই সাইনআপ পেজ ধীর করুক না: welcome ইমেইল পাঠানো, আপনার CRM‑কে ওয়েবহুক নোটিফাই করা, এবং ব্যবহারকারীকে nightly activity রিপোর্টে অন্তর্ভুক্ত করা।\n\n### সাইনআপে কি কিউড হবে\n\nuser রেকর্ড তৈরি করার ঠিক পরে, তিনটি job রো আপনার ডাটাবেস কিউতে লিখুন। প্রতিটি রোতে থাকে টাইপ, পে-লোড (যেমন `user_id`), স্ট্যাটাস, একটি চেষ্টা গণনা, এবং `next_run_at` টাইমস্ট্যাম্প।\n\nএকটি সাধারণ লাইফসাইকেল এরকম:\n\n- `queued`: তৈরি হয়েছে এবং worker-এর জন্য অপেক্ষা করছে\n- `running`: একটি worker এটিকে ক্লেইম করেছে\n- `succeeded`: শেষ, আর কোনো কাজ নেই\n- `failed`: ব্যর্থ, পরে শিডিউল করা বা রিট্রাই শেষ হয়েছে\n- `dead`: খুব বেশি বার ব্যর্থ হয়েছে এবং মানুষের নজর দরকার\n\nwelcome ইমেইল জবে একটি idempotency কী থাকে, যেমন `welcome_email:user:123`। পাঠানোর আগে worker একটি টেবিলে সম্পন্ন idempotency কী চেক করে (বা unique constraint প্রয়োগ করে)। যদি জব দুটি বার চলে কারণ ক্র্যাশ হয়েছে, দ্বিতীয়বার কী দেখে ও পাঠ বন্ধ করে দেয়—কোনো ডাবল welcome ইমেইল হয় না।\n\n### একটি ব্যর্থতা এবং কিভাবে তা পুনরুদ্ধার করে\n\nধরা যাক CRM‑এর ওয়েবহুক এন্ডপয়েন্ট ডাউন। ওয়েবহুক জব টাইমআউট দিয়ে ব্যর্থ হয়। আপনার worker ব্যাকঅফ ব্যবহার করে রিট্রাই শিডিউল করে (উদাহরণ: 1 মিনিট, 5 মিনিট, 30 মিনিট, 2 ঘণ্টা) এবং একটু জিটার যোগ করে যাতে বহু জব একই সেকেন্ডে রিট্রাই না করে।\n\nMax attempts পার হওয়ার পরে জব `dead` হয়। ব্যবহারকারী তখনও সাইন আপ করেছে, welcome ইমেইল পেয়েছে, এবং নাইটলি রিপোর্ট জব স্বাভাবিকভাবেই চলবে। শুধু CRM নোটিফিকেশন আটকে আছে এবং তা দৃশ্যমান।\n\nপরের সকালে, সাপোর্ট বা অন‑কলে থাকা ব্যক্তি এটি সহজে সামলাতে পারে:\n\n- ডেড জবগুলো টাইপ অনুযায়ী ফিল্টার করুন (যেমন `webhook.crm`)\n- শেষ ত্রুটি বার্তা পড়ুন এবং পে-লোড ঠিক আছে কিনা নিশ্চিত করুন\n- CRM ফিরে এসেছে কিনা নিশ্চিত করুন\n- জব রিকিউ করুন (dead → queued, attempts রিসেট) বা ঐ ডেস্টিনেশন সাময়িকভাবে ডিসেবল করুন\n\nআপনি যদি Koder.ai‑তে অ্যাপ বানান, একই প্যাটার্ন প্রযোজ্য: ব্যবহারকারীর ফ্লো দ্রুত রাখুন, সাইড‑ইফেক্ট জবগুলোতে ঠেলে দিন, এবং ব্যর্থতাগুলো ইন্সপেক্ট ও পুনরায় চালানোর উপায় সহজ রাখুন।\n\n## কিউকে অনির্ভরযোগ্য করে তোলা সাধারণ ভুলগুলো\n\nকিউ ভাঙানোর দ্রুততম উপায় হল এটাকে ঐচ্ছিক মানা। দলগুলো প্রায়ই শুরু করে "এই একবারের জন্য অনুরোধে ইমেইল পাঠাই" বলে, কারণ তা সহজ মনে হয়। তারপর তা ছড়িয়ে পড়ে: পাসওয়ার্ড রিসেট, রিসীট, ওয়েবহুক, রিপোর্ট এক্সপোর্ট—অল্পতেই অ্যাপ ধীর লাগে, টাইমআউট বাড়ে, এবং কোনো তৃতীয়‑পক্ষ ঢিলেঢালা হলে তা আপনার আউটেজে পরিণত হয়।\n\nআরেকটা সাধারণ ফাঁদ হল idempotency এড়িয়ে যাওয়া। যদি একটি জব দুইবার চালানো যেতে পারে, এটি দুটি ফলাফল তৈরি করা থেকে বিরত থাকতে হবে। idempotency না থাকলে রিট্রাই ডুপ্লিকেট ইমেইল, পুনরাবৃত্ত ওয়েবহুক ইভেন্ট, বা এর চেয়েও খারাপ ফলাতে পারে।\n\nতৃতীয়টি হল দৃশ্যমানতার অভাব। যদি আপনি কেবল সাপোর্ট টিকিট থেকে ব্যর্থতা জানেন, কিউ তখনই ব্যবহারকারীকে ক্ষতিগ্রস্ত করছে। এমনকি একটি বেসিক অভ্যন্তরীণ ভিউ যা স্ট্যাটাস অনুযায়ী জব কাউন্ট ও searchable `last_error` দেখায়, অনেক সময় বাঁচায়।\n\n### নির্ভরযোগ্যতা নাশক যে কিছু বিষয় নজরে রাখবেন\n\nকিছু সমস্যা দ্রুত দেখা দেয়, এমনকি সহজ কিউতেও:\n\n- ব্যর্থ হওয়ার সাথে সাথেই তৎক্ষণাৎ রিট্রাই করা। যদি একটি প্রদানকারী ডাউন, দ্রুত রিট্রাই আপনার নিজেরই ট্রাফিক স্পাইক তৈরি করে।\n- ধীর জবগুলোকে জরুরি জবগুলোর সাথে মিশানো। 10‑মিনিট রিপোর্ট "ইমেইল ভেরিফাই করুন" মেসেজ ব্লক করতে পারে।\n- ত্রুটিকে সর্বদা অস্থায়ী মনে করা। কখনও সফল হবে না এমন জব লাগাতার ঘোরাফেরা করে প্রকৃত সমস্যাগুলো লুকায়।\n- পে-লোড ভার্সনের মালিকানা না রাখা। যদি আপনি জবের আকৃতি বদলে ফেলেন, পুরনো জবগুলো ব্যর্থ হতে পারে।\n- রেট লিমিট উপেক্ষা করা। কিউ আপনাকে এমন প্রদানকারীদের প্ল্যাডে ফ্লাড করতে পারে যারা আপনাকে থ্রটল করে।\n\nব্যাকঅফ স্ব-সৃষ্ট আউটেজ রোধ করে। এমনই একটি বেসিক শিডিউলও কাজ করে: 1 মিনিট, 5 মিনিট, 30 মিনিট, 2 ঘণ্টা। এছাড়া একটি ম্যাক্স অ্যাটেম্পট লিমিট দিন যাতে ভাঙা জব থামে ও দৃশ্যমান হয়।\n\nআপনি যদি Koder.ai তে তৈরি করেন, এই বেসিকগুলো ফিচারের সঙ্গে একসাথে পাঠান—সপ্তাহ পর শুদ্ধিকরণ প্রকল্প হিসেবে নয়।\n\n## দ্রুত চেকলিস্ট ও পরবর্তী ধাপগুলো\n\nআরও টুল যোগ করার আগে বেসিকগুলো দৃঢ় করে নিন। একটি ডাটাবেস-ব্যাকড কিউ ভালভাবে কাজ করে যখন প্রতিটি জব ক্লেইম করা সহজ, রিট্রাই করা সহজ, এবং ইন্সপেক্ট করা সহজ।\n\nএকটি দ্রুত নির্ভরযোগ্যতা চেকলিস্ট:\n\n- প্রতিটি জবে আছে: id, type, payload, status, attempts, max_attempts, run_at/next_run_at, এবং last_error।\n- Workers নিরাপদে জব ক্লেইম করে (এক worker একজব) এবং ক্র্যাশের পরে পুনরুদ্ধার করে (lock timeout + reaper)।\n- প্রতিটি জবের একটি স্পষ্ট টাইমআউট আছে যাতে আটকে থাকা কাজ রিট্রাইযোগ্য হয়ে ওঠে।\n- রিট্রাই সীমাবদ্ধ এবং ডিলে বাড়ে (backoff) যাতে থান্ডারিং হার্ডস না আসে।\n- একটি ডেড-লেটার অবস্থা (বা টেবিল) আছে এবং জব রি-রান বা বাদ দেয়ার একটি স্পষ্ট পদ্ধতি আছে।\n\nপরবর্তী, আপনার প্রথম তিনটি job টাইপ নির্ধারণ করুন এবং তাদের নিয়মগুলো লিখে নিন। উদাহরণ: password reset email (দ্রুত রিট্রাই, ছোট max), nightly report (কম রিট্রাই, বড় টাইমআউট), webhook delivery (অধিক রিট্রাই, দীর্ঘ ব্যাকঅফ, স্থায়ী 4xx‑এ বন্ধ)।\n\nডাটাবেস কিউ কখন পর্যাপ্ত নয় তা সন্দেহ হলে এই সিগন্যালগুলো দেখুন: বহু worker‑এর কারণে row‑level contention, অনেক job টাইপে কড়া অর্ডারিং প্রয়োজন, বৃহৎ fan‑out (এক ইভেন্ট হাজারো জব ট্রিগার করে), বা ক্রস‑সার্ভিস কনজাম্পশন যেখানে ভিন্ন দলগুলো আলাদা worker চালায়।\n\nদ্রুত প্রোটোটাইপ চান? Koder.ai‑তে প্ল্যানিং মোডে ফ্লো স্কেচ করুন, jobs টেবিল ও worker লুপ জেনারেট করুন, এবং স্ন্যাপশট ও রোলব্যাক দিয়ে ডিপ্লয়ের আগে ইটারেট করুন।
If a task can take more than a second or two, or depends on a network call (email provider, webhook endpoint, slow query), move it to a background job.
Keep the user request focused on validating input, writing the main data change, enqueueing a job, and returning a fast response.
Start with a database-backed queue when:
Add a broker/streaming tool later when you need very high throughput, many independent consumers, or cross-service event replay.
Track the basics that answer: what to do, when to try next, and what happened last time.
A practical minimum:
job_type, payloadstatus (queued, running, succeeded, failed, dead)attempts, max_attemptsnext_run_at, plus created_atlocked_at, locked_bylast_erroridempotency_key (or another dedupe mechanism)Store inputs, not big outputs.
Good payloads:
user_id, template, report_id)Avoid:
If the job needs big data, store a reference (like report_run_id or a file key) and fetch the real content when the worker runs.
The key is an atomic “claim” step so two workers can’t take the same job.
Common approach in Postgres:
FOR UPDATE SKIP LOCKED)running and set locked_at/locked_byThen your workers can scale horizontally without double-processing the same row.
Assume jobs will run twice sometimes (crashes, timeouts, retries). Make the side effect safe.
Simple patterns:
idempotency_key like welcome_email:user:123This is especially important for emails and webhooks to prevent duplicates.
Use a clear default policy and keep it boring:
Fail fast on permanent errors (like missing email address, invalid payload, most 4xx webhook responses).
Dead-letter means “stop retrying and make it visible.” Use it when:
max_attemptsStore enough context to act:
last_error and last status code (for webhooks)When you replay, prefer creating a new job and keeping the dead one immutable.
Handle “stuck running” jobs with two rules:
running jobs older than a threshold and re-queues them (or marks them failed)This lets the system recover from worker crashes without manual cleanup.
Use separation so slow work can’t block urgent work:
If ordering matters, it’s usually “per key” (per user, per webhook endpoint). Add a group_key and ensure only one in-flight job per key to preserve local ordering without forcing global ordering.