ওয়েবহুক ইন্টিগ্রেশন ডিবাগ করুন: স্বাক্ষর, রিট্রাই, রিপ্লে, ইভেন্ট লগ
ওয়েবহুক ইন্টিগ্রেশন কীভাবে ডিবাগ করবেন শিখুন — স্বাক্ষর স্ট্যান্ডার্ড করা, রিট্রাই নিরাপদভাবে পরিচালনা করা, রিপ্লে সক্ষম করা এবং সহজে সার্চযোগ্য ইভেন্ট লগ রাখা।

কেন ওয়েবহুক ইন্টিগ্রেশনগুলো ব্ল্যাক বক্সে পরিণত হয়\n\nওয়েবহুক হলো যখন একটি অ্যাপ আপনার অ্যাপকে বলে যে কিছু ঘটেছে। একটি পেমেন্ট প্রোভাইডার বলে “payment succeeded”, একটি ফর্ম টুল বলে “new submission”, কিংবা একটি CRM রিপোর্ট করে “deal updated”。 সবকিছু সহজ মনে হয় যতক্ষণ না কিছু ভেঙে যায় এবং আপনি অনুভব করেন—কোনো একটি পেইজ নেই খুলবার, কোনো স্পষ্ট ইতিহাস নেই, এবং নিরাপদভাবে যা ঘটেছে তা রিপ্লে করার উপায় নেই।\n\nএজন্যই ওয়েবহুক সমস্যা এত হতাশাজনক হয়। রিকোয়েস্ট আসে (বা আসে না)। আপনার সিস্টেম এটিকে প্রক্রিয়াজাত করে (বা ব্যর্থ হয়)। প্রথম সংকেত প্রায়ই একটি অস্পষ্ট টিকিট—“কাস্টমার চেক আউট করতে পারছে না” বা “স্ট্যাটাস আপডেট হয়নি”। যদি প্রোভাইডার রিট্রাই করে, আপনি ডুপ্লিকেট পেতে পারেন। যদি তারা কোন পে-লোড ফিল্ড বদলে দেয়, আপনার পার্সার কিছু অ্যাকাউন্টের জন্যই ভেঙে যেতে পারে।\n\nসাধারণ উপসর্গ:\n\n- “মিসিং” ইভেন্ট যেখানে আপনি বলতে পারেন না সেগুলো কখনো পাঠানো হয়নি নাকি শুধু প্রক্রিয়াকরণ হয়নি\n- ডুপ্লিকেট ডেলিভারি যা ডুপ্লিকেট সাইড-এফেক্ট তৈরি করে (দুটি ইনভয়েস, দুইটি ইমেইল, দুইবার স্ট্যাটাস চেঞ্জ)\n- পে-লোড পরিবর্তন (নতুন ফিল্ড, অনুপস্থিত ফিল্ড, ভুল টাইপ) যা শুধুমাত্র কখনও কখনও ব্যর্থ করে\n- স্বাক্ষর পরীক্ষা যা একটি এনভায়রনমেন্টে পাস করে এবং অন্যটাতে ব্যর্থ হয়\n\nএকটি ডিবাগেবল ওয়েবহুক সেটআপ অনুমানভিত্তিক নয়। এটি ট্রেসযোগ্য (আপনি প্রতিটি ডেলিভারি ও কীভাবে হ্যান্ডল করেছে তা খুঁজে পেতে পারেন), পুনরাবৃত্তিযোগ্য (আপনি নিরাপদে একটি পুরাতন ইভেন্ট রিপ্লে করতে পারেন), এবং যাচাইযোগ্য (আপনি অথেনটিসিটি এবং প্রক্রিয়াজাতকরণ ফলাফল প্রমাণ করতে পারবেন)। যখন কেউ জানতে চায় “এই ইভেন্টের কি হয়েছে?”, আপনি মিনিটের মধ্যে প্রমাণ সহ উত্তর দিতে সক্ষম হওয়া উচিত।\n\nযদি আপনি প্ল্যাটফর্মের উপর অ্যাপ বানান যেমন AppMaster, এই মানসিকতা আরও জরুরি হয়ে ওঠে। ভিজ্যুয়াল লজিক দ্রুত বদলাতে পারে, কিন্তু আপনাকে এখনও একটি স্পষ্ট ইভেন্ট ইতিহাস ও নিরাপদ রিপ্লে নিশ্চিত করতে হবে যাতে এক্সটার্নাল সিস্টেম ব্ল্যাক বক্সে না পরিণত হয়।\n\n## ওয়েবহুক পর্যবেক্ষণযোগ্য করতে ন্যূনতম ডেটা\n\nচাপের মধ্যে ডিবাগ করলে প্রতি বার আপনাকে একই বেসিকগুলো দরকার: একটি রেকর্ড যা আপনি বিশ্বাস করেন, সার্চ করতে পারেন, এবং রিপ্লে করতে পারেন। তা ছাড়া প্রতিটি ওয়েবহুক একক রহস্যই হয়ে থাকে।\n\nনির্ধারণ করুন আপনার সিস্টেমে একটি সিংগেল ওয়েবহুক “ইভেন্ট” কী মানে। এটিকে একটি রসিদ হিসেবে বিবেচনা করুন: একটি ইনকামিং রিকোয়েস্ট সমান একটি স্টোর করা ইভেন্ট, এমনকি যদি প্রক্রিয়াকরণ পরে ঘটে।\n\nন্যূনতমভাবে সংরক্ষণ করুন:\n\n- Event ID: প্রোভাইডারের ID থাকলে সেটি ব্যবহার করুন; না হলে একটি জেনারেট করুন।\n- Trusted receipt data: কখন এটি আপনি পেয়েছেন, এবং কে পাঠিয়েছে (প্রোভাইডার নাম, এন্ডপয়েন্ট, IP যদি আপনি রাখেন)। received_at কে পে-লোডের ভিতরের টাইমস্ট্যাম্প থেকে আলাদা রাখুন।\n- Processing status ও একটি কারণ: কয়েকটি ছোট স্টেট ব্যবহার করুন (received, verified, handled, failed) এবং একটি সংক্ষিপ্ত failure reason স্টোর করুন।\n- Raw request ও একটি parsed view: অডিট ও স্বাক্ষর যাচাইকরণে জন্য কাঁচা বডি ও হেডার ঠিক যেভাবে এসেছে তেমনই সংরক্ষণ করুন, সাথে সার্চ ও সাপোর্টের জন্য একটি parsed JSON ভিউ রাখুন।\n- Correlation keys: এক বা দুইটি ফিল্ড যেগুলো দিয়ে আপনি সার্চ করতে পারেন (order_id, invoice_id, user_id, ticket_id)।\n\nউদাহরণ: একটি পেমেন্ট প্রোভাইডার “payment_succeeded” পাঠায় কিন্তু আপনার কাস্টমারের কাছে এখনও unpaid দেখাচ্ছে। যদি আপনার ইভেন্ট লগে কাঁচা রিকোয়েস্ট থাকে, আপনি স্বাক্ষর নিশ্চিত করতে পারেন এবং নিখুঁত পরিমাণ ও মুদ্রা দেখতে পাবেন। যদি এতে invoice_id থাকে, সাপোর্ট সেই ইনভয়েস থেকে ইভেন্টটি খুঁজে পেতে পারবে, দেখতে পারবে ইভেন্টটি “failed” এ আটকে আছে, এবং ইঞ্জিনিয়ারিং-কে একটি স্পষ্ট এরর রিজন দিতে পারবে।\n\nAppMaster-এ একটি প্র্যাকটিক্যাল পদ্ধতি হলো Data Designer-এ একটি “WebhookEvent” টেবিল রাখা, এবং প্রতিটি ধাপ সম্পন্ন হলে একটি Business Process স্ট্যাটাস আপডেট করে। টুলটাই গুরুত্বপূর্ণ নয়—কনসিস্টেন্ট রেকর্ডই।\n\n## ইভেন্ট স্ট্রাকচার স্ট্যান্ডার্ডাইজ করুন যাতে লগগুলো পড়তে সহজ হয়\n\nযদি প্রতিটি প্রোভাইডার ভিন্ন পে-লোড শেপ পাঠায়, আপনার লগ সবসময় এলোমেলো লাগবে। একটি স্থিতিশীল ইভেন্ট “এনভেলপ” ডিবাগিং দ্রুত করে কারণ আপনি প্রতিবারই একই ফিল্ডগুলো স্ক্যান করতে পারেন, যদিও ডেটা বদলে যায়।\n\nএকটি ব্যবহারযোগ্য এনভেলপ সাধারণত অন্তর্ভুক্ত করে:\n\n- id (ইউনিক ইভেন্ট id)\n- type (স্পষ্ট ইভেন্ট নাম, যেমন invoice.paid)\n- created_at (কখন ইভেন্ট ঘটেছে, না যে আপনি কখন পেয়েছেন)\n- data (বিজনেস পে-লোড)\n- version (যেমন v1)\n\nএখানে একটি সহজ উদাহরণ যা আপনি লোগ করে স্টোর করতে পারেন ঠিক যেমনটি আছে:\n\n```json
{
"id": "evt_01H...",
"type": "payment.failed",
"created_at": "2026-01-25T10:12:30Z",
"version": "v1",
"correlation": {"order_id": "A-10492", "customer_id": "C-883"},
"data": {"amount": 4990, "currency": "USD", "reason": "insufficient_funds"}
}
```\n\nএকটি নামকরণ স্টাইল (snake_case বা camelCase) বেছে নিন এবং সেটিতেই কড়া থাকুন। টাইপ নিয়ে অপরিবর্তিততা বজায় রাখুন: কখনো amount স্ট্রিংভাবে এবং কখনো নম্বর হিসেবে রাখবেন না।\n\nভার্সনিং আপনার সেফটি নেট। যখন ফিল্ড পরিবর্তন করতে হবে, v2 প্রকাশ করুন এবং কিছু সময় v1 কাজ করে রাখতে দিন। এটা সাপোর্ট ইস্যুগুলো প্রতিরোধ করে এবং আপগ্রেড ডিবাগ করা অনেক সহজ করে তোলে।\n\n## স্বাক্ষর যাচাইকরণ — কনসিস্টেন্ট ও টেস্টযোগ্য করে রাখুন\n\nস্বাক্ষর আপনার ওয়েবহুক এন্ডপয়েন্টকে খোলা দরজা হতে আটকায়। যাচাইকরণ ছাড়া, যারা আপনার URL জানে তারা ফেক ইভেন্ট পাঠাতে পারবে এবং অ্যাটাকাররা আসল রিকোয়েস্ট টেম্পার করার চেষ্টা করতে পারবে।\n\nসর্বাধিক সাধারণ প্যাটার্ন হলো shared secret দিয়ে HMAC স্বাক্ষর। সেন্ডার কাঁচা রিকোয়েস্ট বডি (সবচেয়ে ভালো) বা একটি canonical string সাইন করে। আপনি HMAC পুনর্গণনা করে তুলনা করবেন। অনেক প্রোভাইডার টাইমস্ট্যাম্পও সাইন করে যাতে ক্যাচ করা রিকোয়েস্ট পরে রিপ্লে না করা যায়।\n\nএকটি যাচাইকরণ রুটিন বিরক্তিকরভাবে সাদাসিধে হওয়া উচিত:\n\n- ঠিক যেভাবে এসেছে তেমন কাঁচা বডি পড়ুন (JSON পার্সিংয়ের আগে)।\n- প্রোভাইডারের অ্যালগরিদম ও আপনার সিক্রেট ব্যবহার করে স্বাক্ষর পুনর্গণনা করুন।\n- একটি কনস্ট্যান্ট-টাইম তুলনা ফাংশন ব্যবহার করে মিলুন।\n- পুরানো টাইমস্ট্যাম্প প্রত্যাখ্যান করুন (সংক্ষিপ্ত উইন্ডো ব্যবহার করুন, কয়েক মিনিটের মতো)।\n- ক্লোজ ফেইল: কিছুই অনুপস্থিত বা ম্যালফরমড হলে invalid হিসেবে বিবেচনা করুন।\n\nএটাকে টেস্টযোগ্য রাখুন। যাচাইকরণ একটি ছোট ফাংশনে রাখুন এবং জানা-ভালো ও জানা-খারাপ স্যাম্পল দিয়ে টেস্ট লিখুন। সাধারণ টাইম সিংক হলো পার্স করা JSON সাইন করা কাঁচা বাইট না করে।\n\nদিন একে থেকেই সিক্রেট রোটেশন প্ল্যান করুন। ট্রানজিশনের সময় দুইটি অ্যাক্টিভ সিক্রেট সাপোর্ট করুন: প্রথমে নতুনটা চেষ্টা করুন, তারপর আগেরটায় fallback করুন।\n\nযখন যাচাইকরণ ব্যর্থ হয়, পর্যাপ্ত লোগ রাখুন কিন্তু সিক্রেট লিক না করতে বিশেষ যত্ন নিন: প্রোভাইডার নাম, টাইমস্ট্যাম্প (এবং সেটা খুব পুরানো কিনা), স্বাক্ষর ভ্যার্সন, রিকোয়েস্ট/করিলেশন ID, এবং কাঁচা বডির একটি সংক্ষিপ্ত হ্যাশ (গোপনীয়তা রক্ষায় কাঁচা বডি নয়)।\n\n## রিট্রাই ও আইডেম্পোটেন্সি — ডুপ্লিকেট সাইড-এফেক্ট ছাড়া\n\nরিট্রাই সাধারণ। প্রোভাইডার টাইমআউট, নেটওয়ার্ক ইস্যু, বা 5xx রেসপন্সে রিট্রাই করে। এমনকি যদি আপনার সিস্টেম কাজটি করে ফেলেছে, প্রোভাইডার হয়ত আপনার রেসপন্স সময়মত পায়নি, তাই একই ইভেন্ট আবারও আসতে পারে।\n\nআগেই সিদ্ধান্ত নিন কোন রেসপন্সগুলি “রিট্রাই” বনাম “বন্ধ” নির্দেশ করে। অনেক টিম নীচের মত নিয়ম ব্যবহার করে:\n\n- 2xx: গ্রহণ করা, রিট্রাই বন্ধ\n- 4xx: কনফিগারেশন বা রিকোয়েস্ট সমস্যার ইঙ্গিত, সাধারণত রিট্রাই बंद\n- 408/429/5xx: অস্থায়ী ব্যর্থতা বা রেট লিমিট, রিট্রাই করুন\n\nআইডেম্পোটেন্সি মানে একই ইভেন্ট একাধিক বার হ্যান্ডল করলেও সাইড-এফেক্ট পুনরাবৃত্তি না হওয়া (দুবার চার্জ করা, ডুপ্লিকেট অর্ডার তৈরি, দুইবার ইমেইল পাঠানো)। ওয়েবহুককে at-least-once ডেলিভারি হিসেবে বিবেচনা করুন।\n\nএকটি বাস্তবসম্মত প্যাটার্ন হলো প্রতিটি ইনকামিং ইভেন্টের ইউনিক ID এবং প্রক্রিয়াজাতকরণের আউটকাম স্টোর করা। পুনরাবৃত্ত ডেলিভারিতে:\n\n- যদি এটি সফল হয়, 2xx রিটার্ন করুন এবং কিছু করবেন না।\n- যদি এটি ব্যর্থ হয়, অভ্যন্তরীণ প্রক্রিয়াজাতকরণ পুনরায় চেষ্টা করুন (বা retryable স্ট্যাটাস রিটার্ন করুন)।\n- যদি এটি চলমান থাকে, সমান্তরাল কাজ এড়ান এবং একটি সংক্ষিপ্ত “accepted” রেসপন্স দিন।\n\nঅভ্যন্তরীণ রিট্রাইয়ের জন্য, exponential backoff ব্যবহার করুন এবং অ্যাটেম্পট সীমা দিন। ক্যাপের পরে ইভেন্টটিকে “needs review” স্টেটে নিয়ে যান সাথে সর্বশেষ এরর। AppMaster-এ এটি একটি ছোট টেবিলের সাথে পরিষ্কারভাবে মানচিত্রিত হয়: ইভেন্ট IDs ও স্ট্যাটাস এবং একটি Business Process যে রিট্রাই শিডিউল করে ও পুনরাবৃত্ত ব্যর্থতাগুলি রুট করে।\n\n## রিপ্লে টুল — সাপোর্ট টিমকে দ্রুত সমস্যার সমাধান করাতে সাহায্য করে\n\nরিট্রাই স্বয়ংক্রিয়। রিপ্লে ইচ্ছাকৃত।\n\nএকটি রিপ্লে টুল “আমরা মনে করি এটা পাঠানো হয়েছিল” কে একটি নির্দিষ্ট টেস্টে পরিণত করে একই পে-লোড দিয়ে। এটি তখনই নিরাপদ যখন দুইটি শর্ত সত্য: আইডেম্পোটেন্সি এবং একটি অডিট ট্রেইল। আইডেম্পোটেন্সি দ্বৈত চার্জিং, দ্বৈত শিপিং, বা দ্বৈত ইমেইল প্রতিরোধ করে। অডিট ট্রেইল বলে কি রিপ্লে করা হয়েছে, কে করেছে, এবং কি হয়েছে।\n\n### একক-ইভেন্ট রিপ্লে বনাম সময়-পরিসর রিপ্লে\n\nসিঙ্গেল-ইভেন্ট রিপ্লে সাধারণ সাপোর্ট কেস: একটি কাস্টমার, একটি ব্যর্থ ইভেন্ট, ফিক্সের পরে পুনরায় ডেলিভার করুন। টাইম-রেঞ্জ রিপ্লে ইনসিডেন্টের জন্য: একটি প্রোভাইডার আউটেজ নির্দিষ্ট উইন্ডোতে ঘটেছে এবং আপনাকে সব কিছু পুনরায় পাঠাতে হবে যা ব্যর্থ হয়েছিল।\n\nসিলেকশন সহজ রাখুন: ইভেন্ট টাইপ, সময়-পরিসর, এবং স্ট্যাটাস (failed, timed out, বা delivered কিন্তু unacknowledged) দিয়ে ফিল্টার করুন, তারপর একটি ইভেন্ট বা ব্যাচ রিপ্লে করুন।\n\n### দুর্ঘটনা রোধের জন্য গার্ডরেইল\n\nরিপ্লে শক্তিশালী হওয়া উচিত, কিন্তু বিপজ্জনক নয়। কিছু গার্ডরেইল সাহায্য করবে:\n\n- রোল-ভিত্তিক অ্যাক্সেস\n- প্রতিটি ডেস্টিনেশনের জন্য রেট লিমিট\n- অডিট রেকর্ডে জমা রাখতে হলে রিপ্লে করার কারণ লেখার বাধ্যতা\n- বড় ব্যাচ রিপ্লের জন্য ঐচ্ছিক অনুমোদন\n- ভ্যালিডেশন ছাড়া পাঠায় না এমন একটি dry-run মোড\n\nরিপ্লে-র পরে, মূল ইভেন্টের পাশে ফলাফল দেখান: success, এখনও ব্যর্থ (সর্বশেষ এরর সহ), বা ignored (আইডেম্পোটেন্সি দিয়ে ডুপ্লিকেট শনাক্ত করা হয়েছে)।\n\n## ইভেন্ট লগ — ইনসিডেন্টের সময় কার্যকর হওয়া উচিত\n\nযখন একটি ওয়েবহুক ইনসিডেন্টের সময় ভেঙে পড়ে, আপনাকে মিনিটের মধ্যে উত্তর দরকার। একটি ভালো লগ স্পষ্ট গল্প বলে: কী এসেছে, আপনি এর সঙ্গে কী করেছেন, এবং কোথায় আটকে গেছে।\n\nকাঁচা রিকোয়েস্ট ঠিক যেভাবে এসেছে তেমনই সংরক্ষণ করুন: টাইমস্ট্যাম্প, পথ, মেথড, হেডার, এবং কাঁচা বডি। ভেন্ডররা ফিল্ড বদলে দিলে বা আপনার পার্সার ডেটা ভুল পড়লে কাঁচা পে-লোডই আপনার গ্রাউন্ড ট্রুথ। সংরক্ষণ করার আগে সংবেদনশীল মানগুলো মাস্ক করুন (অথরাইজেশন হেডার, টোকেন, এবং এমন কোনো পার্সোনাল বা পেমেন্ট ডেটা যা আপনার প্রয়োজন নেই)।\n\nকাঁচা ডেটই যথেষ্ট নয়। একটি পার্সড, সার্চযোগ্য ভিউও রাখুন: ইভেন্ট টাইপ, এক্সটার্নাল ইভেন্ট ID, কাস্টমার/অ্যাকাউন্ট আইডেন্টিফায়ার, সম্পর্কিত অবজেক্ট ID (invoice_id, order_id), এবং আপনার অভ্যন্তরীণ করিলেশন ID। এটাই সাপোর্টকে “কাস্টমার 8142-র সব ইভেন্ট” খুঁজে পেতে দেয় প্রতি পে-লোড খুলে না দেখে।\n\nপ্রক্রিয়াজাতকরণের সময় একটি সংক্ষিপ্ত ধাপ টাইমলাইন রাখুন সঙ্গত শব্দভাণ্ডার দিয়ে, উদাহরণ: “validated signature”, “mapped fields”, “checked idempotency”, “updated records”, “queued follow-ups”。\n\nরিটেনশন গুরুত্বপূর্ণ। বাস্তব বিলম্ব ও বিবাদের জন্য যথেষ্ট ইতিহাস রাখুন, কিন্তু সবকিছু অনন্তকাল ধরে রাখবেন না। প্রথমে কাঁচা পে-লোড মুছে বা অ্যানোনিমাইজ করার কথা বিবেচনা করুন, অথচ হালকা মেটাডেটা দীর্ঘ সময় রাখুন।\n\n## ধাপে ধাপে: একটি ডিবাগেবল ওয়েবহুক পাইপলাইন তৈরি করুন\n\nরিসিভারকে একটি ছোট পাইপলাইনের মতো তৈরি করুন যেখানে স্পষ্ট চেকপয়েন্ট আছে। প্রতিটি রিকোয়েস্ট একটি স্টোর করা ইভেন্ট হয়, প্রতিটি প্রক্রিয়াজাতকরণ চালানো একটি অ্যাটেম্পট হয়, এবং প্রতিটি ব্যর্থতা সার্চযোগ্য হয়।\n\n### রিসিভার পাইপলাইন\n\nHTTP এন্ডপয়েন্টকে কেবল intake হিসেবে বিবেচনা করুন। শুরুর দিকে ন্যূনতম কাজ করুন, তারপর ওয়ার্কারকে কাজটি পাঠান যেন টাইমআউট রহস্যজনক আচরণে পরিণত না হয়।\n\n1. হেডার, কাঁচা বডি, রিসিপ্ট টাইমস্ট্যাম্প, এবং প্রোভাইডার ক্যাপচার করুন।\n2. স্বাক্ষর যাচাই করুন (বা একটি পরিষ্কার “failed verification” স্ট্যাটাস স্টোর করুন)।\n3. একটি স্থিতিশীল ইভেন্ট ID দ্বারা কিউতে প্রক্রিয়াজাতকরণ নির্ধারণ করুন।\n4. ওয়ার্কার-এ প্রক্রিয়াজাতকরণ চালান আইডেম্পোটেন্সি চেক ও বিজনেস অ্যাকশন সহ।\n5. চূড়ান্ত ফলাফল (success/failure) এবং একটি ব্যবহারযোগ্য এরর মেসেজ রেকর্ড করুন।\n\nপ্র্যাকটিসে, আপনি দুইটি মূল রেকর্ড চাইবেন: প্রতিটি ওয়েবহুক ইভেন্টের জন্য একটি সারি, এবং প্রতিটি প্রক্রিয়াজাতকরণ অ্যাটেম্পটের জন্য একটি সারি।\n\nএকটি সলিড ইভেন্ট মডেলে থাকতে পারে: event_id, provider, received_at, signature_status, payload_hash, payload_json (বা raw payload), current_status, last_error, next_retry_at। অ্যাটেম্পট রেকর্ড রাখতে পারে: attempt_number, started_at, finished_at, http_status (যদি প্রযোজ্য), error_code, error_text।\n\nএকবার ডেটা থাকলে, একটি ছোট অ্যাডমিন পেজ যোগ করুন যাতে সাপোর্ট event ID, customer ID, বা সময়-পরিসর দিয়ে সার্চ করতে পারে এবং স্ট্যাটাস দিয়ে ফিল্টার করতে পারে। এটা সহজ এবং দ্রুত রাখুন।\n\nএক-অফ ব্যর্থতার উপর নয়, প্যাটার্নে এলার্ট সেট করুন। উদাহরণ: “প্রোভাইডার 5 মিনিটে 10 বার ব্যর্থ” বা “একটি ইভেন্ট দীর্ঘ সময় ধরে failed এ আটকে আছে”।\n\n### সেন্ডার প্রত্যাশা\n\nযদি আপনি সেন্ডিং সাইড নিয়ন্ত্রণ করেন, তিনটি জিনিস স্ট্যান্ডার্ডাইজ করুন: সর্বদা একটি ইভেন্ট ID অন্তর্ভুক্ত করুন, সর্বদা একইভাবে পে-লোড সাইন করুন, এবং সাধারণ ভাষায় একটি রিট্রাই নীতি প্রকাশ করুন। এতে একজন পার্টনার যখন বলে “আমরা পাঠিয়েছি” এবং আপনার সিস্টেম কিছু না দেখায় তখন বিরতিহীন কথাবার্তা রোধ হয়।\n\n## উদাহরণ: পেমেন্টস ওয়েবহুক "failed" থেকে "fixed" পর্যন্ত রিপ্লে সহ\n\nএকটি সাধারণ প্যাটার্ন হলো একটি Stripe ওয়েবহুক যা দুইটি কাজ করে: একটি Order রেকর্ড তৈরি করে, তারপর ইমেইল/এসএমএস-এর মাধ্যমে একটি রসিদ পাঠায়। এটা সহজ শোনালেও এক ইভেন্ট ব্যর্থ হলে কেউ জানে না গ্রাহক চার্জ হয়েছে কি না, অর্ডার আছে কি না, বা রসিদ পাঠানো হয়েছে কি না।\n\nরিয়েলিস্টিক একটি ব্যর্থতা: আপনি আপনার Stripe সাইনিং সিক্রেট রোটেট করেন। কয়েক মিনিটের জন্য আপনার এন্ডপয়েন্ট এখনও পুরনো সিক্রেট দিয়ে যাচাই করে, তাই Stripe ইভেন্ট ডেলিভার করে কিন্তু আপনার সার্ভার সেগুলো 401/400 দিয়ে প্রত্যাখ্যান করে। ড্যাশবোর্ডে “webhook failed” দেখায়, আর আপনার অ্যাপ লগ শুধুমাত্র বলে “invalid signature”。\n\nভালো লগগুলো কারণটিকে স্পষ্ট করে। ব্যর্থ ইভেন্টের জন্য রেকর্ডে একটি স্থিতিশীল ইভেন্ট ID থাকা উচিত এবং পর্যাপ্ত যাচাইকরণ ডিটেইল যাতে মিসম্যাচটি নির্দিষ্ট করা যায়: স্বাক্ষর ভার্সন, স্বাক্ষর টাইমস্ট্যাম্প, যাচাইকরণ রেজাল্ট, এবং একটি স্পষ্ট রিজেক্ট কারণ (ভুল সিক্রেট বনাম টাইমস্ট্যাম্প ড্রিফ্ট)। রোটেশনের সময়, কোন সিক্রেট চেষ্টা করা হয়েছে তা লগ করা সহায়ক (উদাহরণ “current” বনাম “previous”), কাঁচা সিক্রেট নয়।\n\nএকবার সিক্রেট ঠিক করা হলে এবং স্বল্প সময়ের জন্য “current” ও “previous” উভয়ই গ্রহণযোগ্য হলে, ব্যাকলগ হ্যান্ডল করাও করতে হয়। একটি রিপ্লে টুল এটিকে দ্রুত কাজ করে পরিণত করে:\n\n1) event_id দ্বারা ইভেন্টটি খুঁজুন।\n2) নিশ্চিত করুন ব্যর্থতার কারণটি সমাধান হয়েছে।\n3) ইভেন্টটি রিপ্লে করুন।\n4) আইডেম্পোটেন্সি যাচাই করুন: Order একবার তৈরি হয়, রসিদ একবার পাঠানো হয়।\n5) টিকিটে রিপ্লে ফলাফল ও টাইমস্ট্যাম্প যোগ করুন।\n\n## সাধারণ ভুলগুলো এবং সেগুলো এড়ানোর উপায়\n\nঅধিকাংশ ওয়েবহুক সমস্যা রহস্যময় মনে হয় কারণ সিস্টেমগুলো কেবল চূড়ান্ত এরর রেকর্ড করে। প্রতিটি ডেলিভারিকে ছোট একটি ইনসিডেন্ট রিপোর্ট হিসেবে বিবেচনা করুন: কী এসেছে, আপনি কী সিদ্ধান্ত নিলেন, এবং এরপর কী হলো।\n\nকিছু সাধারণ ভুল বারবার দেখা যায়:\n\n- সম্পূর্ণ লাইফসাইকেল (received, verified, queued, processed, failed, retried) লোগ না করে কেবল exception লোগ করা\n- মাস্ক না করে পুরো পে-লোড ও হেডার সংরক্ষণ করা, পরে দেখা যায় আপনি সিক্রেট বা পার্সোনাল ডেটা ক্যাপচার করেছেন\n- রিট্রাইকে নতুন ইভেন্ট হিসেবে হ্যান্ডল করা, ফলে ডবল চার্জ বা ডুপ্লিকেট মেসেজ\n- ইভেন্ট স্থায়ীভাবে স্টোর করার আগে 200 OK রিটার্ন করা, ফলে ড্যাশবোর্ড সবুজ দেখায় কিন্তু কাজ পরে মারা যায়\n\nপ্রায়োগিক সমাধানগুলো:\n\n- একটি ন্যূনতম, সার্চযোগ্য রিকোয়েস্ট রেকর্ড এবং স্ট্যাটাস চেঞ্জগুলো স্টোর করুন।\n- ডিফল্টভাবে সংবেদনশীল ফিল্ড মাস্ক করুন এবং কাঁচা পে-লোডের অ্যাক্সেস সীমাবদ্ধ করুন।\n- কেবল কোডে নয়, ডাটাবেস স্তরে আইডেম্পোটেন্সি প্রয়োগ করুন।\n- ইভেন্ট স্থায়ীভাবে স্টোর হওয়ার পরে acknowledge করুন।\n- রিপ্লে একটি সাপোর্টেড ফ্লো হিসেবে তৈরি করুন, একটি এক-অফ স্ক্রিপ্ট নয়।\n\nআপনি যদি AppMaster ব্যবহার করে থাকেন, এই অংশগুলো প্ল্যাটফর্মে স্বাভাবিকভাবে ফিট করে: Data Designer-এ একটি ইভেন্ট টেবিল, ভেরিফিকেশন ও প্রক্রিয়াজাতকরণের জন্য স্ট্যাটাস-চালিত Business Process, এবং সার্চ ও রিপ্লের জন্য একটি অ্যাডমিন UI।\n\n## দ্রুত চেকলিস্ট ও পরবর্তী ধাপ\n\nপ্রতি বার একই বেসিক লক্ষ্য করুন:\n\n- প্রতিটি ইভেন্টের একটি ইউনিক event_id আছে, এবং আপনি কাঁচা পে-লোড যেভাবে পেয়েছেন তেমনি সংরক্ষণ করেন।\n- প্রতিটি রিকোয়েস্টে স্বাক্ষর যাচাইকরণ চলে, এবং ব্যর্থতাগুলো একটি স্পষ্ট কারণ সহ লোগ হয়।\n- রিট্রাই predictable, এবং হ্যান্ডলারগুলো আইডেম্পোটেন্ট।\n- রিপ্লে অনুমোদিত রোলে সীমাবদ্ধ এবং একটি অডিট ট্রেইল রাখে।\n- লগগুলো event_id, provider id, status, এবং সময় অনুযায়ী সার্চযোগ্য, এবং একটি সংক্ষিপ্ত “কি ঘটলো” সারাংশ আছে।\n\nএইগুলোর একটিও না থাকলে একটি ইন্টিগ্রেশন ব্ল্যাক বক্সে পরিণত হতে পারে। যদি আপনি কাঁচা পে-লোড সংরক্ষণ না করেন, আপনি প্রমাণ করতে পারবেন না প্রোভাইডার কী পাঠিয়েছিল। যদি স্বাক্ষর ব্যর্থতার রিপোর্ট স্পষ্ট না হয়, আপনি ঘণ্টাখানেক কেবল বিতর্কে সময় ব্যয় করবেন যে কার দোষ।\n\nযদি আপনি প্রতিটি উপাদান হাতেকলমে কোড না করে দ্রুত তৈরী করতে চান, AppMaster (appmaster.io) আপনাকে ডেটা মডেল, প্রক্রিয়াজাতকরণ ফ্লো, এবং অ্যাডমিন UI এক জায়গায় সংগ্রহ করতে সাহায্য করতে পারে, এবং একই সাথে চূড়ান্ত অ্যাপের জন্য বাস্তব সোর্স কোড জেনারেট করে।


