ওয়েবহুক নির্ভরযোগ্যতা চেকলিস্ট: রিট্রাই, আইডেমপোটেন্সি, রিপ্লে
প্রায়োগিক ওয়েবহুক নির্ভরযোগ্যতা চেকলিস্ট: রিট্রাই, আইডেমপোটেন্সি, রিপ্লে লগ ও মনিটরিং ইনবাউন্ড ও আউটবাউন্ড উভয়ের জন্য যখন পার্টনার ব্যর্থ হয়।

কেন বাস্তব প্রকল্পে ওয়েবহুক অনির্ভরযোগ্য মনে হয়
ওয়েবহুক সহজ একটি চুক্তি: কোনো কিছু ঘটলে একটি সিস্টেম আরেকটিকে HTTP অনুরোধ পাঠায়। "অর্ডার শিপড", "টিকিট আপডেটেড", "ডিভাইস অফলাইন"। এটি অ্যাপগুলোর মাঝে একটি পুশ নোটিফিকেশনের মতো, ওয়েবের ওপর ডেলিভারি করা।
ডেমোতে এগুলো বিমানভ্রমণের মতো স্থির লাগে কারণ হ্যাপি-পাথ দ্রুত ও পরিষ্কার। বাস্তবে, ওয়েবহুকগুলো এমন সিস্টেমগুলোর মাঝে থাকে যেগুলো আপনি নিয়ন্ত্রণ করেন না: CRMs, শিপিং প্রোভাইডার, হেল্পডেস্ক, মার্কেটিং টুল, IoT প্ল্যাটফর্ম, এমনকি আপনার নিজের টিমের অন্য অ্যাপ। পেমেন্ট ছাড়া ঠিকঠাক ডেলিভারি গ্যারান্টি, স্থির ইভেন্ট স্কিমা বা ধারাবাহিক রিট্রি আচরণ অনেক সময় থাকে না।
প্রথম লক্ষণগুলো সাধারণত বিভ্রান্তিকর:
- ডুপ্লিকেট ইভেন্ট (একই আপডেট দুইবার আসে)
- মিসিং ইভেন্ট (কিছু বদলেছে কিন্তু আপনি কখনও খবর পাননি)
- বিলম্ব (আপডেট মিনিট বা ঘন্টার পর আসে)
- অ-ক্রমিক ইভেন্ট ("closed" আগে এসে "opened" এর আগে আসে)
ফ্লাকি তৃতীয় পক্ষের সিস্টেমগুলো এটিকে র্যান্ডম মনে করায় কারণ ব্যর্থতাগুলো সবসময় জোরালো হয় না। একটি প্রোভাইডার টাইমআউট হতে পারে কিন্তু আপনার অনুরোধটি তারা প্রক্রিয়াও করে ফেলেছে। একটি লোড ব্যালান্সার কানেকশন ড্রপ করতে পারে পরে সেই একই সিস্টেম আবার রিট্রি করে। অথবা তাদের সিস্টেম সাময়িকভাবে ডাউন হয়ে যায়, পরে পুরোনো ইভেন্টগুলোর একটি বাল্বাস্ত পাঠায়।
ধরুন একটি শিপিং পার্টনার "delivered" ওয়েবহুক পাঠায়। একদিন আপনার রিসিভার স্লো হয়ে 3 সেকেন্ডের জন্য রেসপন্ড করলে তারা রিট্রি করে। আপনি দুইবার ডেলিভারি পান, কাস্টমারকে দুটি ইমেইল যায়, সাপোর্ট বিভ্রান্ত হয়। পরের দিন তাদের আউটেজ হয় এবং তারা রিট্রি করে না, তাই "delivered" কখনো আসেনি এবং আপনার ড্যাশবোর্ড আটকে থাকে।
ওয়েবহুক নির্ভরযোগ্যতা এক পারফেক্ট অনুরোধের চেয়ে বেশী—এটি মেসি বাস্তবতার জন্য ডিজাইন করা: রিট্রিস, আইডেমপোটেন্সি, এবং পরে কী ঘটেছিল তা রি-প্লে ও যাচাই করার ক্ষমতা।
তিনটি ভিত্তি: রিট্রাই, আইডেমপোটেন্সি, রিপ্লে
ওয়েবহুক দুই দিকে আসে। ইনবাউন্ড ওয়েবহুক হলো আপনাকে কেউ পাঠায় (পেমেন্ট প্রোভাইডার, CRM, শিপিং টুল)। আউটবাউন্ড ওয়েবহুক হলো যখন আপনি আপনার কাস্টমার বা পার্টনারকে কিছু পরিবর্তন হলে পাঠান। দুটোই এমন কারণে 실패 করতে পারে যেগুলো আপনার কোডের সাথে সম্পর্কিত নয়।
রিট্রাই হলো ব্যর্থতার পরে যা ঘটে। একটি সেন্ডার রিট্রি করতে পারে টাইমআউট, 500 এরর, ড্রপড কানেকশন, বা কোনো রেসপন্স না পাওয়া কারণে। ভাল রিট্রাই ঘটনা, না কোনো বিরল এজ-কেস—লক্ষ্য হলো ইভেন্টটি পৌঁছে দেওয়া ছাড়া রিসিভারকে ওভারফ্লো করা বা ডুপ্লিকেট সাইড-ইফেক্ট তৈরি করা নয়।
আইডেমপোটেন্সি হলো ডুপ্লিকেটকে নিরাপদ কিভাবে করা যায়। মানে "একবার করো, এমনকি এটি দুইবার এলেও"। একই ওয়েবহুক আবার এলে আপনি তা শনাক্ত করে সফল রেসপন্স দেবেন কিন্তু ব্যবসায়িক অ্যাকশন আবার চালাবেন না (যেমন, দ্বিতীয় ইনভয়েস তৈরি করবেন না)।
রিপ্লে হলো আপনার রিকভারি বাটন। এটি নিয়ন্ত্রিতভাবে পূর্বের ইভেন্টগুলো পুনরায় প্রক্রিয়া করার ক্ষমতা, সাধারণত বাগ ফিক্স করার পরে বা পার্টনার আউটেজ-পর। রিট্রাই স্বয়ংক্রিয় ও তাৎক্ষণিক—রিপ্লে ইচ্ছাকৃত এবং প্রায়ই ঘণ্টা বা দিন পরে হয়।
যদি আপনি ওয়েবহুক নির্ভরযোগ্যতা চান, কয়েকটি সহজ লক্ষ্য ঠিক করুন এবং সেগুলোকে ঘিরে ডিজাইন করুন:
- কোনও ইভেন্ট হারিয়ে যাবে না (আপনি সবসময় যা এসেছে বা যা পাঠানোর চেষ্টা করা হয়েছে তা খুঁজে পাবেন)
- ডুপ্লিকেট নিরাপদ (রিট্রাই ও রিপ্লে ডাবল-চার্জ, ডাবল-ক্রিয়েট বা ডাবল-ইমেইল করবে না)
- স্পষ্ট অডিট ট্রেইল (আপনি দ্রুত “কি ঘটেছিল?” উত্তর দিতে পারবেন)
একটি প্র্যাকটিক্যাল উপায় হলো প্রতিটি ওয়েবহুক চেষ্টা স্ট্যাটাস ও ইউনিক আইডেমপোটেন্সি কি সহ সংরক্ষণ করা। অনেক টিম এটিকে একটি ছোট "webhook inbox/outbox" টেবিল হিসেবে বানায়।
ইনবাউন্ড ওয়েবহুক: একটি রিসিভার ফ্লো যেটা আপনি পুনঃব্যবহার করতে পারবেন
বেশিরভাগ ওয়েবহুক সমস্যা ঘটে কারণ সেন্ডার ও রিসিভার আলাদা ক্লক চালায়। রিসিভার হিসেবে আপনার কাজ হলো প্রত্যাশাযোগ্য হয়ে ওঠা: দ্রুত অ্যাকনলেজ করুন, যা এসেছিল তা রেকর্ড করুন, এবং নিরাপদে প্রসেস করুন।
"অ্যাকসেপ্ট" আলাদা করুন ও "কাজ করা" থেকে
রিকোয়েস্টটিকে দ্রুত রাখুন এবং আসল কাজ অন্যত্র সরিয়ে দিন। এতে টাইমআউট কমে এবং রিট্রির ব্যথা অনেক কমে।
- দ্রুত স্বীকার করুন। রিকোয়েস্ট গ্রহণযোগ্য হলে যত দ্রুত সম্ভব 2xx দিন।
- বেসিক চেক করুন। কনটেন্ট টাইপ, প্রয়োজনীয় ফিল্ড ও পার্সিং ভ্যালিডেট করুন। যদি ওয়েবহুক সাইন করা হয়, সিগনেচার এখানে যাচাই করুন।
- র’ ইভেন্ট সংরক্ষণ করুন। বডি এবং পরে দরকারি হেডারগুলো (সিগনেচার, ইভেন্ট ID) স্টোর করুন, সাথে রিসিভ টাইমস্ট্যাম্প ও একটি স্ট্যাটাস যেমন "received"।
- কাজ কে কিউ করুন। ব্যাকগ্রাউন্ড প্রসেসিংয়ের জন্য একটি জব তৈরি করুন, তারপর 2xx রিটার্ন করুন।
- স্পষ্ট আউটকাম দিয়ে প্রসেস করুন। সাইড-ইফেক্ট সফল হলে ইভেন্টকে "processed" চিহ্নিত করুন। ব্যর্থ হলে কেন ব্যর্থ জানিয়ে রেকর্ড করুন এবং এটি কি রিট্রি করা উচিত তা লগ করুন।
"দ্রুত রেসপন্ড করা" কেমন হওয়া উচিত
বাস্তবসম্মত লক্ষ্য হলো এক সেকেন্ডের মধ্যে রেসপন্ড করা। যদি সেন্ডার নির্দিষ্ট কোড আশা করে, তা ব্যবহার করুন (অনেকে 200 গ্রহণ করে, কেউ কেউ 202 পছন্দ করে)। 4xx তখনই দিন যখন সেন্ডার আর রিট্রি করা উচিত নয় (যেমন, ইনভ্যালিড সিগনেচার)।
উদাহরণ: একটি customer.created ওয়েবহুক আসে যখন আপনার ডাটাবেস লোডে আছে। এই ফ্লো থাকলে আপনি র’ ইভেন্ট স্টোর করে এনকিউ করবেন এবং 2xx দেবেন—আপনার কর্মী পরে রিট্রাই করতে পারবে সেন্ডারের রিট্রাইয়ের ওপর নির্ভর না করে।
ইনবাউন্ড সেফটি চেক যা ডেলিভারিকে ভেঙে ফেলে না
সিকিউরিটি চেক করার মূল্য আছে, কিন্তু লক্ষ্য সহজ: খারাপ ট্রাফিক ব্লক করুন কিন্তু সত্যিকারের ইভেন্ট ব্লক করবেন না। অনেক ডেলিভারি সমস্যা ঘটে রিসিভারগুলো খুব কড়া হওয়ার কারণে বা ভুল রেসপন্স দেওয়ার কারণে।
সেন্ডার প্রমাণ করার চেষ্টা করুন। সাইন করা রিকোয়েস্ট (HMAC সিগনেচার হেডার) বা হেডারে শেয়ার্ড সিক্রেট টোকেন পছন্দ করুন। ভারিফাই করুন ভারী কাজ করার আগে, আর নেই হলে দ্রুত ব্যর্থ করুন।
স্ট্যাটাস কোডে সাবধান থাকুন কারণ এগুলো রিট্রিকে নিয়ন্ত্রণ করে:
- অথেন্টিকেশন ব্যর্থতার জন্য 401/403 রিটার্ন করুন যাতে সেন্ডার অনবরত রিট্রি না করে।
- ম্যালফর্মড JSON বা প্রয়োজনীয় ফিল্ড মিসিং হলে 400 দিন।
- 5xx কেবল তখনই দিন যখন আপনার সার্ভিস সাময়িকভাবে গ্রহণ বা প্রসেস করতে অক্ষম।
IP allowlist সাহায্য করতে পারে, কিন্তু কেবল তখনই যখন প্রোভাইডারের IP রেঞ্জ স্থির ও ডকুমেন্টেড। তাদের IP বারবার পরিবর্তিত হলে বা তারা বড় ক্লাউড পুল ব্যবহার করলে allowlist সত্যিকারের ওয়েবহুক গোপনভাবে ড্রপ করতে পারে এবং আপনি পরে বুঝতে পারবেন।
প্রোভাইডার যদি টাইমস্ট্যাম্প ও ইউনিক ইভেন্ট ID দেয়, আপনি রিপ্লে সুরক্ষা যোগ করতে পারেন: খুব পুরনো মেসেজ প্রত্যাখ্যান করুন এবং সাম্প্রতিক ID ট্র্যাক করে ডুপ্লিকেট দেখুন। টাইম উইন্ডো ছোট রাখুন, কিন্তু ছোট গ্রেস পিরিয়ড রাখুন যেন ক্লক ড্রিফট বৈধ অনুরোধ ভেঙে না দেয়।
রিসিভার-অনুকুল সিকিউরিটি চেকলিস্ট:
- বড় পে-লোড পার্স করার আগে সিগনেচার বা শেয়ার্ড সিক্রেট যাচাই করুন।
- একটি সর্বোচ্চ বডি সাইজ ও ছোট রিকোয়েস্ট টাইমআউট প্রয়োগ করুন।
- অথ কম্পকালে 401/403 দিন, ম্যালফর্মড ইনপুটে 400 দিন, এবং গৃহীত ইভেন্টে 2xx দিন।
- যদি টাইমস্ট্যাম্প চেক করেন, কয়েক মিনিটের গ্রেস উইন্ডো রাখুন।
লগিংয়ের জন্য, অডিট ট্রেইল রাখুন কিন্তু সংবেদনশীল ডেটা চিরকাল রাখবেন না। ইভেন্ট ID, সেন্ডার নাম, রিসিভ সময়, ভেরিফিকেশন ফলাফল এবং র’ বডির হ্যাশ স্টোর করুন। যদি পে-লোড সংরক্ষণ করা বাধ্যতামূলক হয়, রিটেনশন সীমা রাখুন এবং ইমেইল, টোকেন বা পেমেন্ট ডিটেইলসের মত ফিল্ড মাস্ক করুন।
রিট্রাই যা সাহায্য করে, নয় যা ক্ষতি করে
রিট্রাইগুলো ভাল যখন সংক্ষিপ্ত সমস্যাকে সফল ডেলিভারিতে পরিণত করে। ক্ষতিকর যখন তারা ট্রাফিক বহুগুণ বাড়ায়, বাস্তব বাগ লুকায়, বা ডুপ্লিকেট তৈরি করে। পার্থক্য হলো কি রিট্রাই করা হবে, কীভাবে স্পেস করা হবে, এবং কখন বন্ধ করা হবে—এর স্পষ্ট নিয়ম থাকা।
একটি বেসলাইন—শুধু তখনই পুনরায় চেষ্টা করুন যখন রিসিভার পরে সফল হওয়ার সম্ভাবনা থাকে। মানসিক মডেল: "সময়াচলিত" ব্যর্থতার উপর রিট্রাই করুন, "তুমি ভুল কিছু পাঠিয়েছ" এ ধরনের ত্রুটিতে রিট্রাই করবেন না।
প্র্যাকটিক্যাল HTTP ফলাফল:
- রিট্রাই করুন: নেটওয়ার্ক টাইমআউট, কানেকশন এরর, এবং HTTP 408, 429, 500, 502, 503, 504
- রিট্রাই করবেন না: HTTP 400, 401, 403, 404, 422
- নির্ভর করে: HTTP 409 (কখনও কখনও "ডুপ্লিকেট", কখনও বাস্তব কনফ্লিক্ট)
স্পেসিং গুরুত্বপূর্ণ। এক্সপোনেনশিয়াল ব্যাকঅফ ও জিটার ব্যবহার করুন যাতে অনেক ইভেন্ট একসাথে ব্যর্থ হলে রিট্রাই স্টর্ম তৈরি না হয়। উদাহরণ: 5s, 15s, 45s, 2m, 5m অপেক্ষা করুন এবং প্রতিবার সামান্য র্যান্ডম অফসেট যোগ করুন।
এছাড়া একটি সর্বোচ্চ রিট্রাই উইন্ডো এবং স্পষ্ট কাটা সীমা সেট করুন। সাধারণ পছন্দ: "২৪ ঘণ্টার মধ্যে চেষ্টা চালিয়ে যাও" অথবা "সর্বোচ্চ ১০ বার চেষ্টা"। তার পরে এটি রিকভারির সমস্যা হিসেবে দেখুন, ডেলিভারি সমস্যা হিসেবে নয়।
এই কাজটি দৈনন্দিনভাবে চালাতে ইভেন্ট রেকর্ডে এসব তথ্য থাকা উচিত:
- চেষ্টা গণনা
- শেষ ত্রুটি
- পরের চেষ্টা সময়
- চূড়ান্ত স্থিতি (ডেড-লেটার স্টেটসহ যখন আপনি রিট্রি বন্ধ করেন)
ডেড-লেটার আইটেমগুলো ইন্সপেক্ট করা সহজ হওয়া উচিত এবং ভিত্তিগত সমস্যা ঠিক করে পরে নিরাপদে রিপ্লে করা যাবে।
বাস্তবে কাজ করা আইডেমপোটেন্সি প্যাটার্ন
আইডেমপোটেন্সি মানে একই ওয়েবহুক একাধিকবার প্রক্রিয়া করে অতিরিক্ত সাইড-ইফেক্ট না ঘটানো। এটি নির্ভরযোগ্যতা দ্রুত বাড়ায় কারণ রিট্রাই ও টাইমআউট ঘটেই যায়, এমনকি কেউ কিছু না করলেও।
একটি স্থিতিশীল কি নির্বাচন করুন
প্রোভাইডার যদি ইভেন্ট ID দেয়, সেটাই ব্যবহার করুন—এটি সবচেয়ে পরিষ্কার।
প্রোভাইডার ID না থাকলে, আপনার কাছে থাকা স্থিতিশীল ফিল্ড থেকে কী তৈরি করুন, যেমন:
- provider name + event type + resource ID + timestamp এর হ্যাশ, অথবা
- provider name + message ID
কি এবং কিছু মেটাডাটা (রিসিভ টাইম, প্রোভাইডার, ইভেন্ট টাইপ, এবং ফলাফল) স্টোর করুন।
সাধারণ নিয়ম:
- কিকে বাধ্যতামূলক হিসেবে বিবেচনা করুন। যদি বানাতে না পারেন, ইভেন্ট কোয়রান্টাইনে রাখুন।
- কির জন্য TTL রাখুন (উদাহরণ: 7–30 দিন) যাতে টেবিল অনবরত বাড়ে না।
- প্রসেসিং ফলাফলও সংরক্ষণ করুন (success, failed, ignored) যাতে ডুপ্লিকেটে ধারাবাহিক রেসপন্স দেয়া যায়।
- কী-তে ইউনিক কনস্ট্রেইন্ট রাখুন যাতে প্যারালেল অনুরোধ দুইবার একই কাজ চালায় না।
ব্যবসায়িক অ্যাকশনটাকেও আইডেমপোটেন্ট করুন
ভাল কি টেবিল থাকলেও আপনার বাস্তব অপারেশনগুলো নিরাপদ হতে হবে। উদাহরণ: একটি "create order" ওয়েবহুক দ্বিতীয়বার চালালে দ্বিতীয় অর্ডার তৈরি করা যাবে না—ব্যবহার করুন বাইরের পরিচিতি (external_order_id, external_user_id) এবং আপসার্ট প্যাটার্ন।
আউট-অফ-অর্ডার ইভেন্ট সাধারণ। যদি আপনি পেয়ে থাকেন "user_updated" আগে এবং পরে "user_created", এমন একটি নিয়ম নিন যেমন "শুধুমাত্র তখনই পরিবর্তন প্রয়োগ করুন যখন event_version নতুন" অথবা "শুধুমাত্র update_if updated_at আমাদের রেকর্ডের চেয়ে নতুন"।
পে-লোড ভিন্ন কিন্তু কী মিলে গেলে সেটাই সবচেয়ে কঠিন। সিদ্ধান্ত আগে থেকেই নিন:
- যদি কী মেলে কিন্তু পে-লোড ভিন্ন, প্রোভাইডারের বাগ মনে করে এলার্ট করুন।
- যদি কী মেলে এবং পার্থক্য কেবল অনির্বচনীয় ফিল্ডে, তাকে উপেক্ষা করুন।
- যদি আপনি প্রোভাইডারে বিশ্বাস না করেন, ফুল পে-লোড হ্যাশ থেকে ডেরাইভ করা কী ব্যবহার করুন এবং কনফ্লিক্টকে নতুন ইভেন্ট হিসেবে ট্রিট করুন।
লক্ষ্য সহজ: এক বাস্তব-জগতের পরিবর্তন এক বাস্তব-জগতের আউটকাম তৈরি করবে, এমনকি আপনি মেসেজ তিনবার দেখেন।
রিকভারির জন্য রিপ্লে টুল ও অডিট লগ
যখন পার্টনার সিস্টেম ফ্লাকি হয়, নির্ভরযোগ্যতা নিখুঁত ডেলিভারির চেয়ে দ্রুত রিকভারি নিয়ে বেশি সম্পর্কিত। একটি রিপ্লে টুল "আমরা কিছু ইভেন্ট হারিয়েছি"—কে রুটিন ফিক্সে পরিণত করে।
প্রতিটি ওয়েবহুকের লাইফসাইকেল ট্র্যাক করে এমন একটি ইভেন্ট লগ দিয়ে শুরু করুন: received, processed, failed, অথবা ignored। তা সময়, ইভেন্ট টাইপ, এবং একটি কোরিলেশন ID-এ অনুসন্ধানযোগ্য রাখুন যাতে সাপোর্ট দ্রুত জানতে পারে, "order 18432-কে কী হয়েছিল?"
প্রতিটি ইভেন্টে পুনরায় চালানোর জন্য পর্যাপ্ত কনটেক্সট রাখুন:
- র’ পে-লোড ও কী হেডার (সিগনেচার, ইভেন্ট ID, টাইমস্ট্যাম্প)
- আপনি বের করা স্বাভাবিকীকৃত ফিল্ডগুলো
- প্রসেসিং ফলাফল ও ত্রুটির মেসেজ (যদি থাকে)
- কাজ বা ম্যাপিং ভার্সন যা তখন ব্যবহার করা হয়েছিল
- রিসিভ, শুরু, শেষ টাইমস্ট্যাম্প
এরপর একটি "Replay" অ্যাকশন যোগ করুন ব্যর্থ ইভেন্টগুলোর জন্য। বাটনটি কম গুরুত্বপূর্ণ, গার্ডরেইলস বেশি গুরুত্বপূর্ণ। একটি ভাল রিপ্লে ফ্লো পূর্বের ত্রুটি দেখায়, রিপ্লেতে কী হবে তা জানায়, এবং ইভেন্টটি পুনরায় চালানো নিরাপদ কি না তা বলে।
অ্যাকসিলেশন গার্ডরেইলস:
- রিপ্লে করার আগে একটি রিজন নোট বাধ্যতামূলক করুন
- রিপ্লে অনুমতি সীমিত একটি ভূমিকা পর্যন্ত রাখুন
- প্রথমবারের মতো একই আইডেমপোটেন্সি চেকগুলো পুনরায় চালান
- রেট-লিমিট রিপ্লে যাতে ইনসিডেন্টে নতুন স্পাইক না তৈরি হয়
- ঐচ্ছিক ড্রাই-রান মোড যা ভ্যালিডেট করে কিন্তু চেঞ্জ লেখে না
ইনসিডেন্টগুলোতে সাধারণত একাধিক ইভেন্ট জড়িত থাকে, তাই সময়-রেঞ্জ অনুযায়ী রিপ্লে (উদাহরণ: "10:05 থেকে 10:40 পর্যন্ত সব ব্যর্থ ইভেন্ট রিপ্লে করুন") সমর্থন করুন। লগ করুন কে, কখন ও কেন রিপ্লে করেছে।
আউটবাউন্ড ওয়েবহুক: একটি সেন্ডার ফ্লো যা আপনি অডিট করতে পারবেন
আউটবাউন্ড ওয়েবহুক এক ধরণের সাধারণ কারণে ব্যর্থ হয়: স্লো রিসিভার, সাময়িক আউটেজ, DNS সমস্যা, বা প্রক্সি যা লম্বা রিকোয়েস্ট ড্রপ করে। নির্ভরযোগ্যতা আসে যখন প্রতিটি পাঠানো জব হিসেবে ট্র্যাক করা হয়, এক-অফ HTTP কল হিসেবে নয়।
একটি সেন্ডার ফ্লো যা প্রত্যাশাযোগ্য থাকে
প্রতিটি ইভেন্টকে একটি স্থিতিশীল, ইউনিক ইভেন্ট ID দিন। এই ID রিট্রাই, রিপ্লে এবং সার্ভিস রিস্টার্ট জুড়ে অপরিবর্তিত থাকা উচিত। যদি আপনি প্রতিটি অ্যাটেম্পটে নতুন ID তৈরি করেন, তাহলে ডেডুপ্লিকেশন কঠিন হবে রিসিভারের জন্য এবং অডিটিং কঠিন হবে আপনার জন্য।
প্রতিটি রিকোয়েস্টে সাইন করুন এবং একটি টাইমস্ট্যাম্প Include করুন। টাইমস্ট্যাম্প রিসিভারকে খুব পুরোনো রিকোয়েস্ট প্রত্যাখ্যান করতে সাহায্য করে এবং সাইনিং নিশ্চিত করে পে-লোড ট্রান্সিটে বদল হয়নি। সিগনেচার নিয়ম সাদাসিধে ও ধারাবাহিক রাখুন যেন পার্টনার সহজে ইমপ্লিমেন্ট করতে পারে।
ডেলিভারিসমূহ এন্ডপয়েন্ট অনুসারে ট্র্যাক করুন, শুধুমাত্র ইভেন্টের জন্য নয়। যদি একই ইভেন্ট তিনজন গ্রাহককে পাঠান, প্রতিটি গন্তব্যের আলাদা অ্যাটেম্পট ইতিহাস ও চূড়ান্ত স্থিতি থাকা দরকার।
একটি কার্যকর ফ্লো:
- ইভেন্ট রেকর্ড তৈরি করুন (event ID, endpoint ID, payload hash, initial status)
- একটি সিগনেচার, টাইমস্ট্যাম্প এবং একটি idempotency key হেডার সহ HTTP রিকোয়েস্ট পাঠান
- প্রতিটি চেষ্টা রেকর্ড করুন (start time, end time, HTTP status, সংক্ষিপ্ত ত্রুটি মেসেজ)
- টাইমআউট ও 5xx রেসপন্সে মাত্র রিট্রাই করুন, এক্সপোনেনশিয়াল ব্যাকঅফ ও জিটার ব্যবহার করে
- একটি স্পষ্ট সীমা পার হলে (ম্যাক্স অ্যাটেম্পট / ম্যাক্স এজ) থামিয়ে তা রিভিউর জন্য মার্ক করুন
এই idempotency key হেডারটি তখনও গুরুত্বপূর্ণ যখন আপনি সেন্ডার হন। এটি রিসিভারকে প্রথম রিকোয়েস্ট প্রক্রিয়াকৃত হলেও আপনার ক্লায়েন্ট 200 পায়নি এমন পরিস্থিতিতে সহজ ডুপ্লিকেট প্রতিরোধ দেখায়।
শেষে, ব্যর্থতাগুলো দৃশ্যমান করুন। "Failed" মানে "হারা গেছে" নয়—এটি মানে "পজ্ করা হয়েছে পর্যাপ্ত কনটেক্সট নিয়ে যাতে নিরাপদে রিপ্লে করা যায়"।
উদাহরণ: একটি ফ্লাকি পার্টনার সিস্টেম এবং পরিষ্কার রিকভারি
আপনার সাপোর্ট অ্যাপ পার্টনার সিস্টেমকে টিকিট আপডেট পাঠায় যেন তাদের এজেন্টরা একই স্ট্যাটাস দেখে। প্রতিবার টিকিট পরিবর্তন হলে (অ্যাসাইন, প্রায়োরিটি আপডেট, ক্লোজ) আপনি একটি ticket.updated ইভেন্ট পোস্ট করেন।
এক বিকালে পার্টনারের এন্ডপয়েন্ট টাইমআউট করতে শুরু করে। আপনার প্রথম ডেলিভারি অ্যাটেম্পট অপেক্ষা করে, আপনার টাইমআউট লিমিট ছুঁয়েছে, এবং আপনি এটিকে "অজানা" হিসেবে ট্রিট করেন (হতে পারে তারা পেয়েছে, না পেয়েও থাকতে পারে)। একটি ভাল রিট্রি কৌশল ব্যাকঅফ নিয়ে রিট্রি করে, প্রতি সেকেন্ডে রিপিট না করে। ইভেন্টটি একটি কিউতে থাকে একই ইভেন্ট ID নিয়ে এবং প্রতিটি চেষ্টা রেকর্ড হয়।
এখন দুঃখজনক অংশ: যদি আপনি আইডেমপোটেন্সি না ব্যবহার করেন, পার্টনার ডুপ্লিকেট প্রক্রিয়া করতে পারে। অ্যাটেম্পট #1 তাদের কাছে পৌঁছতে পারে কিন্তু তাদের রেসপন্স আপনার কাছে ফিরেনি। অ্যাটেম্পট #2 পরে আসলে দ্বিতীয় "Ticket closed" অ্যাকশন তৈরি করে, দুটি ইমেইল পাঠায় বা দুটি টাইমলাইন এন্ট্রি তৈরি করে।
আইডেমপোটেন্সি থাকলে প্রতিটি ডেলিভারিতে ইভেন্ট থেকে নেয়া একটি আইডেমপোটেন্সি কি থাকে (প্রায়শই কেবল ইভেন্ট ID)। পার্টনার সেই কিকে একটি সময় ধরে রাখে এবং রিপিট হলে "already processed" জানায়। আপনি আর আন্দাজ করবেন না।
যখন পার্টনার ফিরে আসে, রিপ্লে দিয়ে আপনি মিস হওয়া এক আপডেট ঠিক করবেন (যেমন আউটেজের সময়ের একটি প্রায়োরিটি চেঞ্জ)। অডিট লগ থেকে ইভেন্ট তুলে নিয়ে একই পে-লোড ও আইডেমপোটেন্সি কি সহ একবার রিপ্লে করুন—এটি নিরাপদ হবে, এমনকি তারা আগেও পেয়েও থাকতে পারে।
ইনসিডেন্ট চলাকালীন আপনার লগগুলো গল্পটি স্পষ্ট করা উচিত:
- ইভেন্ট ID, টিকিট ID, ইভেন্ট টাইপ, পে-লোড ভার্সন
- অ্যাটেম্পট নম্বর, টাইমস্ট্যাম্প, এবং পরের রিট্রাই টাইম
- টাইমআউট বনাম নন-2xx রেসপন্স বনাম সফলতা
- পাঠানো আইডেমপোটেন্সি কি এবং পার্টনার কি "duplicate" রিপোর্ট করেছে
- রিপ্লে রেকর্ড—কে রিপ্লে করেছে এবং চূড়ান্ত ফলাফল কী
সাধারণ ভুল এবং ফাঁদ যা এড়াতে হবে
বেশিরভাগ ওয়েবহুক ইনসিডেন্ট বড় একটি বাগ থেকে হয় না। এগুলো ছোট ছোট সিদ্ধান্ত থেকে আসে যা ট্রাফিক স্পাইক বা তৃতীয় পক্ষের ফ্লাকির সময় নির্ভরযোগ্যতা ভেঙে দেয়।
পোস্টমর্টেমে যেসব ফাঁদ দেখা যায়:
- রিকোয়েস্ট হ্যান্ডলারের ভিতরে ধীর কাজ করা (ডাটাবেস লেখালেখি, API কল, ফাইল আপলোড) যতক্ষণ না সেন্টার টাইমআউট করে এবং রিট্রি করে
- ধরে নেওয়া যে প্রোভাইডার কখনই ডুপ্লিকেট পাঠাবে—তার ফলাফল অতো চার্জ, দ্বিগুণ অর্ডার, বা দুটি ইমেইল
- ভুল স্ট্যাটাস কোড পাঠানো (200 যখন আপনি ইভেন্ট গ্রহণ করেনি, বা 500 যখন ডাটা খুঁত যা কখনো রিট্রাই দিয়ে সফল হবে না)
- কোরিলেশন ID, ইভেন্ট ID, বা রিকোয়েস্ট ID ছাড়া চালু করা এবং পরে লগ মিলাতে ঘণ্টা খরচ করা
- অনন্তকাল রিট্রি করা, যা ব্যাকলগ তৈরি করে এবং একটি পার্টনার আউটेजকে আপনার নিজের আউটেজে পরিণত করে
একটি সহজ নিয়ম শক্তভাবে কাজ করে: দ্রুত অ্যাকনলেজ করুন, তারপর নিরাপদে প্রসেস করুন। গ্রহণের সিদ্ধান্তের জন্য শুধু যা প্রয়োজন তা ভ্যালিডেট করুন, স্টোর করুন, এবং বাকিটা অ্যাসিঙ্ক করে করুন।
স্ট্যাটাস কোডের গুরুত্ব মানুষ যতটা ভাবে তার চেয়ে বেশি:
- 2xx ব্যবহার করুন কেবল তখনই যখন আপনি ইভেন্ট স্টোর (বা কিউ) করেছেন এবং নিশ্চিত যে এটি হ্যান্ডল হবে।
- 4xx ব্যবহার করুন ইনপুট ইনভ্যালিড বা অথ ব্যর্থ হলে যাতে সেন্ডার রিট্রি বন্ধ করে।
- 5xx কেবলমাত্র আপনার সাইডে সাময়িক সমস্যার জন্য ব্যবহার করুন।
রিট্রাই সিলিং সেট করুন। একটি নির্দিষ্ট উইন্ডো (যেমন 24 ঘন্টা) বা নির্দিষ্ট অ্যাটেম্পট সংখ্যার পরে থামান এবং ইভেন্টকে "needs review" হিসেবে মার্ক করুন যাতে একজন মানুষ সিদ্ধান্ত নিতে পারে কি রিপ্লে করা হবে।
দ্রুত চেকলিস্ট এবং পরবর্তী ধাপ
ওয়েবহুক নির্ভরযোগ্যতা বেশিরভাগই পুনরাবৃত্ত অভ্যাস: দ্রুত গ্রহণ করুন, কঠোরভাবে ডেডুপ করুন, যত্ন নিয়ে রিট্রি করুন, এবং একটি রিপ্লে পথ রাখুন।
ইনবাউন্ড (রিসিভার) দ্রুত চেকস
- অনুরোধ নিরাপদে স্টোর করা হলে দ্রুত 2xx রিটার্ন করুন (ধীর কাজ অ্যাসিঙ্ক করুন)।
- ডিবাগের জন্য পর্যাপ্ত ইভেন্ট সংরক্ষণ করুন।
- একটি আইডেমপোটেন্সি কি বাধ্যতামূলক করুন (অথবা provider+event ID থেকে ডেরাইভ করুন) এবং ডাটাবেসে তা এনফোর্স করুন।
- ভুল সিগনেচার বা ইনভ্যালিড স্কিমার জন্য 4xx, এবং কেবল প্রকৃত সার্ভার সমস্যার জন্য 5xx ব্যবহার করুন।
- প্রসেসিং স্ট্যাটাস ট্র্যাক করুন (received, processed, failed) এবং শেষ ত্রুটি মেসেজও রাখুন।
আউটবাউন্ড (সেন্ডার) দ্রুত চেকস
- প্রতিটি ইভেন্টের জন্য একটি ইউনিক ইভেন্ট ID নির্ধারণ করুন এবং তা অ্যাটেম্পট জুড়ে অপরিবর্তিত রাখুন।
- প্রতিটি রিকোয়েস্টে সাইন করুন এবং টাইমস্ট্যাম্প Include করুন।
- একটি রিট্রি পলিসি সংজ্ঞায়িত করুন (ব্যাকঅফ, ম্যাক্স অ্যাটেম্পট, কখন থামবে) এবং সেটার ওপর স্থির থাকুন।
- প্রতিটি এন্ডপয়েন্টের জন্য স্টেট ট্র্যাক করুন: লাস্ট সাকসেস, লাস্ট ফেলিউর, ধারাবাহিক ফেলিউর, পরের রিট্রাই টাইম।
- সার্পোট ও অডিটের জন্য প্রতিটি চেষ্টা লগ করুন পর্যাপ্ত বিশদ সহ।
অপসের জন্য, আগে থেকেই সিদ্ধান্ত নিন আপনি কি রিপ্লে করবেন (একক ইভেন্ট, সময়-রেঞ্জ/স্ট্যাটাস অনুযায়ী ব্যাচ, অথবা উভয়), কে করতে পারবে, এবং ডেড-লেটার রিভিউ রুটিন কেমন হবে।
যদি আপনি সব কিছুকে হ্যান্ড-কোড না করে এই অংশগুলো গড়তে চান, একটি নো-কোড প্ল্যাটফর্ম যেমন AppMaster (appmaster.io) প্রায়োগিক হতে পারে: আপনি PostgreSQL-এ webhook inbox/outbox টেবিল মডেল করতে পারবেন, ভিজ্যুয়াল Business Process Editor-এ রিট্রাই ও রিপ্লে ফ্লো ইমপ্লিমেন্ট করতে পারবেন, এবং একটি অভ্যন্তরীণ অ্যাডমিন প্যানেল দ্রুত শিপ করতে পারবেন যা পার্টনার ফ্লাকির সময় ব্যর্থ ইভেন্টগুলো সার্চ ও পুনরায় চালাতে সাহায্য করবে।
প্রশ্নোত্তর
ওয়েবহুকগুলো এমন সিস্টেমগুলোর মাঝামাঝি থাকে যা আপনি নিয়ন্ত্রণ করেন না, তাই তাদের টাইমআউট, আউটেজ, পুনরায় প্রচেষ্টা এবং স্কিমা পরিবর্তনগুলোর প্রভাব আপনি ভোগ করেন। আপনার কোড সঠিক থাকলেও ডুপ্লিকেট ইভেন্ট, মিসিং ইভেন্ট, বিলম্ব বা অ-ক্রমিক ডেলিভারি দেখা দিতে পারে।
শুরু থেকেই পুনরায় চেষ্টা এবং ডুপ্লিকেটের জন্য ডিজাইন করুন। প্রতিটি ইনকামিং ইভেন্ট সংরক্ষণ করুন, সেভ করা হলে দ্রুত 2xx রেসপন্স দিন, এবং অ্যাসিঙ্ক্রোনাসভাবে একটি আইডেমপোটেন্সি কি ব্যবহার করে প্রসেসিং করুন যাতে পুনরায় ডেলিভারি সাইড-ইফেক্ট না বাড়ায়।
মৌলিক ভ্যালিডেশন ও সংরক্ষণ করার পরে সাধারণত এক সেকেন্ডের মধ্যে দ্রুত ack দেওয়া উচিত। লম্বা কাজ রিকোয়েস্ট হ্যান্ডলারের ভিতরে করলে সेंडার টাইমআউট করে পুনরায় চেষ্টা করবে, যা ডুপ্লিকেট বাড়ায় এবং ঘটনার বিচার কঠিন করে।
আইডেমপোটেন্সি মানে সহজ ভাষায়—একই বার্তা একাধিকবার এলে ব্যবসায়িক কাজ একবারই করা হবে। সাধারণত প্রোভাইডারের ইভেন্ট ID ব্যবহার করে কি সেট করবেন, তা সংরক্ষণ করবেন, এবং ডুপ্লিকেট এলে সফল রেসপন্স দেবেন কিন্তু কাজ পুনরায় চালাবেন না।
প্রথম পছন্দ প্রোভাইডারের ইভেন্ট ID। যদি না থাকে, তাহলে স্থিতিশীল ফিল্ড থেকে একটি কি বানান—উদাহরণ: provider + event type + resource ID + timestamp এর হ্যাশ। স্থিতিশীল না পারলে ঘটনাটি কুয়ারান্টাইনে রাখুন, অনুমান করে বদলি করার চেষ্টা না করুন।
যেসব সমস্যা পাঠকটি নিজে ঠিক করতে পারবে না, সেগুলির জন্য 4xx রিটার্ন করুন (উদাহরণ: auth ব্যর্থতা বা ম্যালফর্মড পে-লোড)। আপনার পাশে সাময়িক সমস্যা হলে 5xx ব্যবহার করুন। স্ট্যাটাস কোডের প্রতিসাধারণে সেন্টার অনেক সময় পুনরায় প্রচেষ্টা কন্ট্রোল করে, তাই ধারাবাহিকতা রাখুন।
টাইমআউট, কানেকশন এরর এবং সাময়িক সার্ভার রেসপন্স (যেমন 408, 429, 5xx) হলে পুনরায় চেষ্টা করুন। এক্সপোনেনশিয়াল ব্যাকঅফ ও জিটার ব্যবহার করুন এবং একটি পরিষ্কার কাটা সীমা রেখে দিন (ম্যাক্স অ্যাটেম্পট বা একটি সময়সীমা), তারপর ইভেন্টটিকে “needs review” বা ডেড-লেটারে রাখুন।
রিপ্লে হলো পূর্বের ইভেন্টগুলো ইচ্ছাকৃতভাবে পুনরায় প্রক্রিয়াকরণ করা—সাধারণত বাগ ফিক্স-এর পরে বা আউটেজের পরে। পুনরায়চেষ্টা স্বয়ংক্রিয় ও তাৎক্ষণিক; রিপ্লে সচেতন ও নিয়ন্ত্রিত। ভাল রিপ্লে থাকতে হবে ইভেন্ট লগ, আইডেমপোটেন্সি চেক এবং গার্ডরেইলস যাতে দুর্ঘটনায় ডুপ্লিকেট কাজ না ঘটে।
অর্ডারড-আউট-অফ-অপসনের জন্য সাধারণ নিয়ম হলো: আপনাকে এমন নিয়ম প্রয়োগ করতে হবে যা আপনার ডোমেইনের সাথে মেলে। সাধারণত ইভেন্ট ভার্সন বা টাইমস্ট্যাম্প দেখে শুধুমাত্র নতুন আপডেটগুলো প্রয়োগ করুন, যাতে পুরানো বাড়তি আপডেটগুলি বর্তমান স্টেট ওভাররাইট না করে।
একটি সিম্পল webhook inbox/outbox টেবিল তৈরি করুন এবং একটি ছোট অ্যাডমিন ভিউ যাতে ব্যর্থ ইভেন্টগুলো সার্চ, পরীক্ষা ও রিপ্লে করা যায়। AppMaster-এ (appmaster.io) আপনি PostgreSQL-এ টেবিল মডেল করতে পারেন, dedupe/রিপ্লে/রিট্রি ফ্লো Business Process Editor-এ বানিয়ে সাপোর্টের জন্য একটি ইন্টারনাল প্যানেল দ্রুত শিপ করতে পারবেন।


