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

বাস্তবে কেন ওয়েবহুক ব্যর্থ হয়
যখন কেউ বলে “ওয়েবহুক ভেঙে গেছে,” তারা সাধারণত তিনটি অবস্থার একটির কথা বোঝায়: ইভেন্টগুলো কখনো পৌঁছায়নি, ইভেন্টগুলো দুবার এসেছে, বা ইভেন্টগুলো বিভ্রান্তিকর ক্রমে এসেছে। তাদের দৃষ্টিতে সিস্টেমটি কিছুই “মিস” করেছে। আপনার দৃষ্টিতে, প্রোভাইডার পাঠিয়েছিল কিন্তু আপনার এন্ডপয়েন্ট গ্রহণ করেনি, প্রক্রিয়াকরণ হয়নি, বা প্রত্যাশিতভাবে রেকর্ড করা হয়নি।
ওয়েবহুকগুলো পাবলিক ইন্টারনেটে থাকে। অনুরোধ বিলম্বিত হয়, রিট্রাই হয়, এবং কখনো কখনো অর্ডার ইনভার্টেড হয়ে যায়। বেশিরভাগ প্রোভাইডার টাইমআউট বা নন-2xx রেসপন্স দেখলে আগ্রাসীভাবে রিট্রাই করে। এতে একটি ছোট সমস্যা (ধীর ডাটাবেস, ডিপ্লয়, সংক্ষিপ্ত আউটেজ) ডুপ্লিকেট এবং রেস কন্ডিশনে পরিণত করে।
খারাপ লগ এই ঘটনাগুলোকে র্যান্ডম মনে করায়। যদি আপনি প্রমাণ করতে না পারেন যে অনুরোধটি প্রামাণিক ছিল, আপনি নিরাপদভাবে সেই অনুরোধের উপর কাজ করতে পারবেন না। যদি গ্রাহকের অভিযোগকে নির্দিষ্ট একটি ডেলিভারি-চেষ্টার সাথে বেঁধে দিতে না পারেন, আপনি আন্দাজে কাটতে হবে।
বেশিরভাগ বাস্তব সমস্যাগুলো কয়েকটি ক্যাটাগরির মধ্যে পড়ে:
- “মিসিং” ইভেন্ট (আপনি টাইমআউট করলেন, অ্যারর রিটার্ন করলেন, বা অ্যাকনলেজ করার পরে ব্যর্থ হলেন)
- ডুপ্লিকেট (রিট্রাই+নন-আইডেমপোটেন্ট হ্যান্ডলার)
- ভুল অর্ডার (আপনি ধরে নিলেন ডেলিভারি অর্ডার = ইভেন্ট অর্ডার)
- রহস্যময় অনুরোধ (সিগনেচার যাচাই নেই, তাই সঠিক/ভুয়া আলাদা করা যায় না)
প্রায়োগিক লক্ষ্য সহজ: প্রকৃত ইভেন্টগুলো একবার গ্রহণ করুন, ভুয়ো অস্বীকার করুন, এবং এমন একটি পরিষ্কার ট্রেইল রাখুন যাতে গ্রাহকের রিপোর্ট মিনিটের মধ্যে ডিবাগ করা যায়।
ওয়েবহুক আসলে কিভাবে কাজ করে
ওয়েবহুক হল একজন প্রোভাইডার আপনার প্রকাশ করা একটি এন্ডপয়েন্টে পাঠায় এমন একটি HTTP অনুরোধ। আপনি এটিকে API কলের মতো পুল করে আনেন না। পাঠক যখন কিছু হয় তখন পুশ করে, এবং আপনার কাজ হল তা দ্রুত গ্রহণ করা এবং নিরাপদভাবে প্রক্রিয়াকরণ করা।
একটি সাধারণ ডেলিভারিতে থাকে একটি অনুরোধ বডি (প্রায়ই JSON) এবং হেডারগুলো যা আপনাকে যাচাই এবং ট্র্যাক করতে সাহায্য করে। অনেক প্রোভাইডার একটি টাইমস্ট্যাম্প, একটি ইভেন্ট টাইপ (যেমন invoice.paid), এবং একটি ইউনিক ইভেন্ট ID দেয় যাকে ডুপ্লিকেট সনাক্ত করতে সংরক্ষণ করা যায়।
টিমগুলোকে যে অংশটি অবাক করে: ডেলিভারি প্রায়ই কখনোই “ঠিক একবার” হয় না। বেশিরভাগ প্রোভাইডারের লক্ষ্য থাকে “অন্তত একবার” — যার মানে একই ইভেন্ট একাধিকবার আসতে পারে, কখনো কখনো মিনিট বা ঘণ্টা পরে।
রিট্রাই হয় সাধারণ কারণগুলোতে: আপনার সার্ভার ধীর বা টাইমআউট হচ্ছে, আপনি 500 রিটার্ন করেছেন, তাদের নেটওয়ার্ক আপনার 200 দেখেনি, বা ডিপ্লয়/ট্রাফিক স্পাইক চলাকালীন এন্ডপয়েন্ট অল্প সময়ের জন্য অনুপলব্ধ ছিল।
টাইমআউট বিশেষভাবে জটিল। আপনার সার্ভার অনুরোধটি পেয়েও থাকতে পারে এবং এমনকি প্রক্রিয়াকরণও শেষ করে ফেলতে পারে, কিন্তু রেসপন্স পাঠাতে সময়পূর্বক পৌঁছায় না। প্রোভাইডারের দৃষ্টিতে এটি ব্যর্থ হয়েছে, তাই তারা রিট্রাই করে। সুরক্ষা না থাকলে, আপনি একই ইভেন্ট দুইবার প্রক্রিয়াকরণ করবেন।
একটি ভাল মানসিক মডেল: HTTP অনুরোধকে “ডেলিভারি-চেষ্টা” হিসেবে বিবেচনা করুন, ইভেন্ট হিসেবে নয়। ইভেন্টটি তার ID দ্বারা চিহ্নিত। আপনার প্রক্রিয়াকরণ সেই ID-এর ওপর ভিত্তি করে হওয়া উচিত, না প্রোভাইডার কতবার কল করেছে তার ওপর ভিত্তি করে।
সোজা ভাষায় ওয়েবহুক সাইনিং
ওয়েবহুক সাইনিং সেই প্রক্রিয়া যার মাধ্যমে পাঠকারী প্রমাণ করে অনুরোধটি সত্যিই তাদের কাছ থেকে এসেছে এবং পথের মধ্যে বদলানো হয়নি। সাইনিং না থাকলে, যে কেউ আপনার ওয়েবহুক URL অনুমান করে ভুয়া “payment succeeded” বা “user upgraded” ইভেন্ট পোস্ট করতে পারে। আরও খারাপ, একটি বাস্তব ইভেন্ট পথিমধ্যে (amount, customer ID, event type) বদলে যেতে পারে এবং আপনার অ্যাপে বৈধ বলে দেখাতে পারে।
সর্বাধিক প্রচলিত প্যাটার্ন হলো শেয়ার্ড সিক্রেট নিয়ে HMAC। দুই পক্ষই একই সিক্রেট জানে। পাঠক ঠিক যেই র ক ক ক (raw request body) ব্যবহার করে HMAC গণনা করে এবং সিগ্নেচার পে-লোডের সাথে পাঠায়। আপনার কাজ হল একই বাইটগুলোর ওপর HMAC পুনরায় গণনা করা এবং সিগ্নেচার মিলছে কিনা পরীক্ষা করা।
সিগ্নেচার ডেটা সাধারণত একটি HTTP হেডারে রাখা হয়। কিছু প্রোভাইডার সেখানে টাইমস্ট্যাম্পও দেয় যাতে আপনি রিপ্লে সুরক্ষা যোগ করতে পারেন। কম ক্ষেত্রে, সিগ্নেচার JSON বডির মধ্যে এম্বেড করা হয়, যা ঝুঁকিপূর্ণ কারণ পার্সার বা পুনঃসিরিয়ালাইজেশন ফরম্যাট বদলে verification ভাঙতে পারে।
সিগ্নেচার তুলনা করার সময়, সাধারণ স্ট্রিং সমানতা ব্যবহার করবেন না। মৌলিক তুলনা টাইমিং ডিফারেন্স লিক করবে যা আক্রমনকারীদের অনেক চেষ্টা করে সঠিক সিগ্নেচার অনুমান করতে সাহায্য করতে পারে। আপনার ভাষা বা ক্রিপ্টো লাইব্রেরির একটি constant-time comparison ফাংশন ব্যবহার করুন এবং মিসম্যাচ হলে প্রত্যাখ্যান করুন।
যদি গ্রাহক রিপোর্ট করে “তোমাদের সিস্টেম একটি ইভেন্ট গ্রহণ করে যা আমরা কখনো পাঠাইনি”, তাহলে সিগ্নেচার চেক দিয়ে শুরু করুন। যদি সিগ্নেচার যাচাই না হয়, আপনার সিক্রেট মিসম্যাচ আছে বা আপনি ভুল বাইট হ্যাশ করছেন (উদাহরণ: পার্স করা JSON বদলে raw body) হতে পারে। যদি সেগুলি পাশ করে, তবে পাঠকের পরিচয় বিশ্বাস করা যায় এবং ডেডুপিং, অর্ডারিং, এবং রিট্রাই পরীক্ষা করতে পারেন।
ধাপে ধাপে: ওয়েবহুক সিগ্নেচার যাচাই
বিশ্বস্ত ওয়েবহুক হ্যান্ডলিং একটি একবাক্যে নিয়ম দিয়ে শুরু হয়: আপনি যা পেয়েছেন তা যাচাই করুন, আপনি যা আশা করেছেন তা নয়।
নিরাপদভাবে যাচাই করার উপায়
ঠিক যেভাবে এসেছে তেমনি raw request body ক্যাপচার করুন। যাচাই করার আগে JSON পার্স করে পুনরায় সিরিয়ালাইজ করবেন না। ক্ষুদ্র ভিন্নতা (হোয়াইটস্পেস, কী-অর্ডার, ইউনিকোড) বাইট বদলে দিতে পারে এবং বৈধ সিগ্নেচারকে অবৈধ দেখাতে পারে।
তারপর প্রোভাইডার যে সই করার জন্য চায় সেই সঠিক পে-লোড তৈরি করুন। অনেক সিস্টেম একটি স্ট্রিং সই করে যেমন timestamp + "." + raw_body। টাইমস্ট্যাম্প শুধুই সাজসজ্জা নয়—এটি পুরোনো অনুরোধগুলি প্রত্যাখ্যান করার জন্য আছে।
শেয়ার্ড সিক্রেট এবং প্রয়োজনীয় হ্যাশ (প্রায়শই SHA-256) ব্যবহার করে HMAC গণনা করুন। সিক্রেট একটি নিরাপদ স্টোরএ রাখুন এবং এটিকে পাসওয়ার্ডের মতো ট্রিট করুন।
শেষে, আপনার গণনা করা মানটি সিগ্নেচার হেডারের সঙ্গে constant-time তুলনা দিয়ে মিলান করুন। যদি না মিলে, 4xx রিটার্ন করুন এবং থামুন। অসংগত হলে “যাচাই সত্ত্বেও গ্রহণ” করবেন না।
দ্রুত ইনপ্লিমেন্টেশন চেকলিস্ট:
- বাইট হিসেবে বডি একবার পড়ুন, সংরক্ষণ করুন, এবং একই বাইটগুলো যাচাইতে ব্যবহার করুন।
- সই করা স্ট্রিং ঠিকভাবে পুনর্নির্মাণ করুন, বিভাজক এবং টাইমস্ট্যাম্প ফরম্যাটিংসহ।
- সঠিক সিক্রেট ও অ্যালগরিদম দিয়ে HMAC গণনা করুন।
- সিগ্নেচার মানগুলো নিরাপদভাবে তুলনা করুন এবং মিসম্যাচ প্রত্যাখ্যান করুন।
- যাচাই কেন ব্যর্থ হয়েছে তা লগ করুন (হেডার অনুপস্থিত, খারাপ টাইমস্ট্যাম্প, মিল নেই) তবে সিক্রেট বা পূর্ণ সিগ্নেচার লগ করবেন না।
দ্রুত উদাহরণ
একজন গ্রাহক রিপোর্ট করল “ওয়েবহুক কাজ করা বন্ধ করে দিয়েছে” যখন আপনি JSON পার্সিং মिडলওয়্যার যোগ করেছিলেন। আপনি সিগ্নেচার মিসম্যাচ দেখেন, প্রধানত বড় পে-লোডে। সমাধান সাধারণত যাচাই করা যে raw body-ই যাচাইতে ব্যবহার করছেন পার্স করার আগে, এবং কোন ধাপ ব্যর্থ হয়েছে সেটা লগ করা (উদাহরণ: “signature header missing” বনাম “timestamp outside allowed window”)। ওই একটি ডিটেইল প্রায়শই ডিবাগিং সময়কে ঘণ্টা থেকে মিনিটে নামিয়ে আনে।
আইডেমপোটেন্সি কী: একবার গ্রহণ, নিরাপদভাবে
প্রোভাইডাররা রিট্রাই করে কারণ ডেলিভারি গ্যারান্টেড নয়। আপনার সার্ভার কিছু সময়ের জন্য ডাউন থাকতে পারে, একটি নেটওয়ার্ক হপ অনুরোধ হারাতে পারে, বা হ্যান্ডলার টাইমআউট হতে পারে। প্রোভাইডার ধরে নেয় “হয়তো এটা কাজ করেছে” এবং একই ইভেন্ট আবার পাঠায়।
আইডেমপোটেন্সি কী হল সেই রসিদ নম্বর যা আপনি ব্যবহার করেন যাতে আপনি ইতোমধ্যেই প্রক্রিয়াজাত ইভেন্ট চিনতে পারেন। এটি একটি সিকョরিটি ফিচার নয়, এবং সিগ্নেচার যাচাইকরণের বিকল্পও নয়। এটা রেস কন্ডিশন মিটাতে সাহায্য করবে না যদি আপনি এটি কনকারেন্ট কন্টেক্সটে সঠিকভাবে সংরক্ষণ ও চেক না করেন।
কী চয়ন আপনার প্রোভাইডার যে মান দেয় তার ওপর নির্ভর করে। রিট্রাইগুলোর মধ্যে স্থিতিশীল একটি মান পছন্দ করুন:
- Event ID (যখন একটি ইভেন্ট এক ব্যবসায়িক পরিবর্তনের সমতুল্য)
- Delivery ID বা message ID (যদি রিট্রাইগুলো একই ডেলিভারি আইডি রাখে)
- স্থায়ী ফিল্ডগুলোর হ্যাশ (যদি কোনো ID না থাকে)
ওয়েবহুক পেলে প্রথমে সেই কী স্টোরে লিখুন একটি ইউনিকনেস নিয়ম ব্যবহার করে যাতে মাত্র একটি অনুরোধ “জয়ী” হয়। তারপর ইভেন্ট প্রক্রিয়াকরণ করুন। একই কী আবার দেখলে, কোনো কাজ না করে সফল (success) রিটার্ন করুন।
সংরক্ষিত “রসিদ” কম কিন্তু উপযোগী রাখুন: কী, প্রক্রিয়াকরণের অবস্থা (received/processed/failed), টাইমস্ট্যাম্প (first seen/last seen), এবং একটি ন্যূনতম সারাংশ (ইভেন্ট টাইপ এবং সম্পর্কিত অবজেক্ট ID)। অনেক দল 7–30 দিনের মতো কী রাখে যাতে দেরী রিট্রাই এবং বেশিরভাগ গ্রাহক রিপোর্ট কভার হয়।
বাস্তব ট্র্যাফিক ব্লক না করে রিপ্লে সুরক্ষা
রিপ্লে সুরক্ষা একটি सरल কিন্তু কটু সমস্যাকে বন্ধ করে: কেউ একটি বাস্তব ওয়েবহুক অনুরোধ (বৈধ সিগ্নেচার সহ) ক্যাপচার করে পরে আবার পাঠায়। যদি আপনার হ্যান্ডলার প্রতিটি ডেলিভারিকে নতুন ধরে নেয়, সেই রিপ্লে ডুপ্লিকেট রিফান্ড, পুনরাবৃত্ত ব্যবহারকারী আমন্ত্রণ, বা পুনরাবৃত্ত স্ট্যাটাস পরিবর্তন ঘটাতে পারে।
সাধারণ পদ্ধতি হল পে-লোড ছাড়াও টাইমস্ট্যাম্প সাইন করা। আপনার ওয়েবহুক হেডারগুলোর মধ্যে থাকতে পারে X-Signature এবং X-Timestamp। গ্রহণের সময় সিগ্নেচার যাচাই করুন এবং টাইমস্ট্যাম্প শর্ট উইন্ডোর ভেতর ফ্রেশ কিনা সেটা চেক করুন।
ক্লক ড্রিফটই সাধারণত ভুল প্রত্যাখ্যাতির কারণ। আপনার সার্ভার ও পাঠকের সার্ভার একে অপরের থেকে মিনিট বা দুইটা পেছনে থাকতে পারে, এবং নেটওয়ার্ক ডেলিভারি বিলম্ব করতে পারে। একটি গ্রেস রাখুন এবং প্রত্যাখ্যানের কারণ লগ করুন।
প্রায়োগিক নিয়ম যা ভাল কাজ করে:
- গ্রহণ করুন যদি
abs(now - timestamp) <= window(উদাহরণ: 5 মিনিট প্লাস ছোট গ্রেস) - বাস্তব সুরক্ষার জন্য আইডেমপোটেন্সির ওপর নির্ভর করুন। উইন্ডোর ভেতর হলেও রিট্রাইগুলো ডাবল-আপ্লাই করবে না।
- টাইম আউটের জন্য প্রত্যাখ্যান করলে একটি স্পষ্ট 4xx দিন এবং প্রাপ্ত টাইমস্ট্যাম্প এবং আপনার সার্ভার সময় লগ করুন।
টাইমস্ট্যাম্প অনুপস্থিত হলে, আপনি কেবলমাত্র সময়ভিত্তিক রিপ্লে সুরক্ষা করতে পারবেন না। সে ক্ষেত্রে আইডেমপোটেন্সির ওপর বেশি নির্ভর করুন (দ্বিতীয়বারের ইভেন্ট ID সংরক্ষণ করে প্রত্যাখ্যান) এবং পরবর্তী ওয়েবহুক ভার্সনে টাইমস্ট্যাম্প ধরা বাধ্যতামূলক করার কথা ভাবুন।
সিক্রেট রোটেশনও গুরুত্বপূর্ণ। আপনি যদি সাইনিং সিক্রেট ঘুরান, ছোট এক ওভারল্যাপ পিরিয়ডের জন্য একাধিক সক্রিয় সিক্রেট রাখুন। প্রথমে নতুন সিক্রেট দিয়ে যাচাই করুন, তারপর পুরনোগুলোর দিকেFallback রাখুন। এটি রোলআউটের সময় গ্রাহক বিরতি প্রতিরোধ করে। যদি আপনার টিম দ্রুত এন্ডপয়েন্ট চালায় (উদাহরণ: Koder.ai ব্যবহার করে কোড জেনারেট করা এবং স্ন্যাপশট ও রোলব্যাক করা), সেই ওভারল্যাপ উইন্ডো সাহায্য করে কারণ পুরোনো ভার্সনগুলো সাময়িকভাবে লাইভ থাকতে পারে।
হ্যান্ডলার ডিজাইন করুন যাতে রিট্রাই ক্ষতি না করে
রিট্রাই স্বাভাবিক। প্রত্যেক ডেলিভারি হয়তো ডুপ্লিকেট, বিলম্বিত, বা অর্ডার-বহির্ভূত হতে পারে এই অনুমান রাখুন। আপনার হ্যান্ডলার একইভাবে আচরণ করা উচিত যে এটি ইভেন্ট একবার দেখুক বা পাঁচবার।
রিকুয়েস্ট পথ ছোট রাখুন। ইভেন্ট গ্রহণ করতে যা দরকার ঠিকততাই করুন, তারপর ভারি কাজ ব্যাকগ্রাউন্ড জব-এ সরান।
একটি সহজ প্যাটার্ন যা প্রোডাকশনে টিকে থাকে:
- বেসিক ভ্যালিডেট করুন (মেথড, কনটেন্ট টাইপ, প্রয়োজনীয় হেডার)
- প্রামাণিকতা যাচাই করুন (signature) এবং ব্যর্থ হলে প্রত্যাখ্যান করুন
- পে-লোড পার্স ও ভ্যালিডেট করুন
- ইভেন্ট ID (বা idempotency key) দিয়ে ডেডুপ করুন ইউনিক কনস্ট্রেইন্ট সহ একটি টেবিলে
- ইভেন্ট ID নিয়ে কাজ এনকিউ করুন, তারপর রেসপন্ড করুন
2xx রিটার্ন করুন কেবল তখনই যখন আপনি সিগ্নেচার যাচাই করেছেন এবং ইভেন্ট রেকর্ড (বা কিউ করা) করেছেন। যদি আপনি 200 ফেরত দিয়ে কিছুই সংরক্ষণ না করে দেন, ক্র্যাশ হলে ইভেন্ট হারাতে পারেন। যদি আপনি রেসপন্ড করার আগে ভারি কাজ করেন, টাইমআউট রিট্রাই ট্রিগার করে এবং সাইড-এফেক্ট পুনরাবৃত্তি হতে পারে।
ধীর ডাউনস্ট্রীম সিস্টেমই রিট্রাইকে কষ্টদায়ক করে। যদি আপনার ইমেল প্রোভাইডার, CRM, বা ডাটাবেস ধীর হয়, একটি কিউ ব্যবহার করে বিলম্ব শোষণ করুন। ওয়ার্কার ব্যাকঅফ নিয়ে রিট্রাই করতে পারে, এবং আপনি আটকে থাকা জবগুলোর অ্যালার্ট করতে পারবেন প্রোভাইডার ব্লক না করে।
আউট-অফ-অর্ডার ইভেন্টও ঘটে। উদাহরণ: একটি subscription.updated subscription.created এর আগে আসতে পারে। সহনশীলতা তৈরি করুন বর্তমান স্টেট চেক করে পরিবর্তন প্রয়োগ করে, upsert ব্যবহার করে, এবং “not found” হলে স্থায়ী ব্যর্থতার বদলে পরে পুনরায় চেষ্টা করার যুক্তি ব্যবহার করুন যেখানে তা আক্ষরিকভাবেই যুক্তিযুক্ত।
প্রচলিত ভুলগুলো যা ট্রেস করা কঠিন বাগ তৈরি করে
অনেক “র্যান্ডম” ওয়েবহুক সমস্যা নিজেরাই করা। এগুলো নেটওয়ার্ক ফ্ল্যাকি মনে হয়, কিন্তু একাধিক বার একই প্যাটার্নে ঘটে, সাধারণত ডিপ্লয়ের পরে, সিক্রেট রোটেশনের পরে, বা পার্সিং-এ ছোট পরিবর্তনের পরে।
সবচেয়ে সাধারণ সিগনেচার বাগ হচ্ছে ভুল বাইট হ্যাশ করা। যদি আপনি আগে JSON পার্স করেন, আপনার সার্ভার এটা পুনরায় ফরম্যাট করতে পারে (হোয়াইটস্পেস, কী-অর্ডার, নাম্বার ফরম্যাটিং)। তারপর আপনি ভিন্ন বডি দিয়ে সিগ্নেচার যাচাই করছেন, এবং যাচাই ব্যর্থ হচ্ছে যদিও পে-লোড আসল। সবসময় ঠিক যেভাবে র ক ক ক বাইট এসেছে সেগুলো দিয়েই যাচাই করুন।
পরের বড় বিভ্রান্তি হচ্ছে সিক্রেট। টিমগুলো স্টেজিং-এ পিশ করে কিন্তু ভুল করে প্রোড সিক্রেট দিয়ে যাচাই করে, বা ঘূর্ণনের পরে পুরনো সিক্রেট রেখে দেয়। যখন গ্রাহক রিপোর্ট করে “শুধু এক পরিবেশেই ত্রুটি,” প্রথমে ভুল সিক্রেট বা ভুল কনফিগ ধরে নিন।
কিছু ভুল যা দীর্ঘ তদন্ত করে:
- ডিবাগের জন্য পুরো বডি লগ করা, তারপর টোকেন, ইমেইল, বা পেমেন্ট ডিটেইল লিক হওয়া
- সাইড-এফেক্ট করে 500 রিটার্ন করা (ইমেইল পাঠানো, অর্ডার আপডেট করা)। রিট্রাই সাইড-এফেক্টগুলো পুনরাবৃত্তি করবে
- এমন একটি আইডেমপোটেন্সি কী ব্যবহার করা যা সত্যিই ইউনিক নয় (উদাহরণ: ইভেন্ট টাইপ + মিনিট). বাস্তব ইভেন্টগুলো “ডুপ্লিকেট” হিসেবে বাদ পড়ে
- 2xx রেসপন্সকে “প্রসেসড” ধরা যখন আপনার কোড কেবল কাজ কিউ করেছে যা পরে ব্যর্থ হয়
উদাহরণ: একজন গ্রাহক বলে “order.paid কখনো এলো না।” আপনি দেখেন সিগ্নেচার ব্যর্থতা শুরু হয়েছিল একটি রিফ্যাক্টরের পরে যা রিকোয়েস্ট পার্সিং মিডলওয়্যার বদলে দেয়। মিডলওয়্যার JSON পড়ে এবং পুনরায় এনকোড করে, ফলে আপনার সিগনেচার চেক এখন পরিবর্তিত বডি ব্যবহার করছে। সমাধান সহজ, কিন্তু সেটা খুঁজে পেতে হলে কী পরীক্ষা করতে হয় জানা থাকতে হবে।
গ্রাহক-রিপোর্ট দ্রুত ডিবাগ করুন
যখন একজন গ্রাহক বলে “তোমাদের ওয়েবহুক ফায়ার করেনি,” এটি আন্দাজ নয় বরং ট্রেস-প্রবলেম হিসাবে বিবেচনা করুন। প্রোভাইডারের একটি সুনির্দিষ্ট ডেলিভারি-চেষ্টা ধরে সেটি আপনার সিস্টেম দিয়ে অনুসরণ করুন।
শুরু করুন প্রোভাইডারের ডেলিভারি আইডেন্টিফায়ার, রিকোয়েস্ট ID, বা ইভেন্ট ID নিয়ে। ঐ এক মান দিয়ে আপনাকে মিলযুক্ত লগ এন্ট্রি দ্রুত খুঁজে পাওয়া উচিত।
তারপর তিনটি বিষয় ক্রমে চেক করুন:
- সিগনেচার যাচাই পাস করেছিল কি?
- আপনার টাইমস্ট্যাম্প বা রিপ্লে উইন্ডো চেক পাস করেছিল কি (যদি ব্যবহার করেন)?
- আইডেমপোটেন্সি এটিকে নতুন বলে চিহ্নিত করেছিল নাকি ডুপ্লিকেট?
তারপর নিশ্চিত করুন আপনি প্রোভাইডারকে কী রিটার্ন করেছেন। ধীর 200 একটি 500-র মতই খারাপ হতে পারে যদি প্রোভাইডার টাইমআউট করে এবং রিট্রাই করে। স্ট্যাটাস কোড, রেসপন্স সময়, এবং আপনার হ্যান্ডলার ভারি কাজ করার আগে অ্যাকনলেজ করেছে কিনা তা দেখুন।
পুনরুত্পাদন প্রয়োজন হলে নিরাপদভাবে করুন: একটি রেড্যাক্টেড raw request স্যাম্পল সংরক্ষণ করুন (কী হেডারগুলো এবং raw body) এবং একই সিক্রেট ও যাচাই কোড ব্যবহার করে টেস্ট এনভায়রনমেন্টে রিপ্লে করুন।
10 মিনিটে চালাবার দ্রুত চেকলিস্ট
ওয়েবহুক ইন্টিগ্রেশন হঠাৎ করে “র্যান্ডম” ভাবে ফেল করলে, দ্রুত কাজ করাই পুরো ব্যাপারে বেশি গুরুত্বপূর্ণ। এই রানবুকটি সাধারণ কারণগুলো ধরে ফেলে।
প্রথমে একটি কংক্রীট উদাহরণ নিন: প্রোভাইডার নাম, ইভেন্ট টাইপ, আনুমানিক টাইমস্ট্যাম্প (টাইমজোন সহ), এবং গ্রাহক যে ইভেন্ট ID দেখতে পায় সেটি।
তারপর যাচাই করুন:
- সিগনেচার যাচাই raw request body বাইট ব্যবহার করে হচ্ছে (JSON পার্সিংয়ের আগে) এবং সঠিক সিক্রেট ব্যবহার হচ্ছে ঐ পরিবেশের জন্য
- রিপ্লে চেক বাস্তব রিট্রাই প্রকৃতির সাথে মানানসই (এবং আপনার সার্ভার ক্লক ঠিক আছে)
- আইডেমপোটেন্সি সত্যিই ডেডুপ করে (unique constraint, প্রসেসিংয়ের আগে লেখা, যুক্তিসঙ্গত রিটেনশন)
- আপনার হ্যান্ডলার শুধুমাত্র যাচাই ও টেকসই রেকর্ড/কিউ করার পরে অ্যাকনলেজ করে
- লগে একটি ন্যূনতম, সার্চযোগ্য রসিদ আছে: provider, event_id, signature_ok, replay_ok, idempotency_status, response_code, latency_ms
প্রোভাইডার যদি বলে “আমরা 20 বার রিট্রাই করেছি,” প্রথমে সাধারণ প্যাটার্নগুলো দেখুন: ভুল সিক্রেট (সিগনেচার 실패), ক্লক ড্রিফট (রিপ্লে উইন্ডো), পে-লোড সাইজ সীমা (413), টাইমআউট (কোন রেসপন্স), এবং ডাউনস্ট্রীম ডিপেন্ডেন্সি থেকে 5xx।
উদাহরণ: “মিসড ইভেন্ট” রিপোর্ট ট্রেসিং
একজন গ্রাহক ইমেল করে: “আগেরদিন আমরা একটি invoice.paid ইভেন্ট মিস করেছি। আমাদের সিস্টেম আপডেট হয়নি।” দ্রুত ট্রেস করার পদ্ধতি:
প্রথমে নিশ্চিত করুন প্রোভাইডার ডেলিভারি চেষ্টা করেছে কি না। ইভেন্ট ID, টাইমস্ট্যাম্প, ডেস্টিনেশন URL, এবং আপনার এন্ডপয়েন্ট যে এক্সাক্ট রেসপন্স কোড রিটার্ন করেছে তা নিয়ে যান। যদি রিট্রাই থাকে, প্রথম ব্যর্থতার কারণ এবং পরে কোন রিট্রাই সফল হয়েছে কি না তা নোট করুন।
এরপর এজে আপনার কোড কি দেখেছিল তা যাচাই করুন: ঐ এন্ডপয়েন্টের জন্য কনফিগার করা সাইনিং সিক্রেট নিশ্চিত করুন, raw request body ব্যবহার করে সিগ্নেচার পুনগণনা করুন, এবং গ্রহণকৃত রিকোয়েস্ট টাইমস্ট্যাম্প আপনার অনুমোদিত উইন্ডোর সাথে মিল আছে কি না দেখুন।
রিট্রাইয়ের সময় রিপ্লে উইন্ডো নিয়ে সতর্ক থাকুন। যদি আপনার উইন্ডো 5 মিনিট এবং প্রোভাইডার 30 মিনিট পরে রিট্রাই করে, আপনি একটি বৈধ রিট্রাই প্রত্যাখ্যান করতে পারেন। যদি সেটাই আপনার পলিসি হয়, নিশ্চিত করুন এটি মানসিকভাবে ইচ্ছাকৃত এবং ডকুমেন্ট করা আছে। না হলে উইন্ডো বর্ধিত করুন বা লজিক পরিবর্তন করুন যাতে আইডেমপোটেন্সি প্রধান রক্ষাকবচ থাকে।
যদি সিগ্নেচার এবং টাইমস্ট্যাম্প ঠিক থাকে, ইভেন্ট ID সিস্টেম জুড়ে অনুসরণ করুন এবং উত্তর করুন: আপনি এটি প্রক্রিয়াকরণ করেছেন, ডেডুপ করেছেন নাকি ড্রপ করেছেন?
সাধারণ ফলাফলগুলো:
- Deduped: আইডেমপোটেন্সি কী ইতিমধ্যেই ছিল, তাই আপনি 200 রিটার্ন করে ব্যবসায়িক লজিক পুনরায় চালাননি।
- Rejected: ভ্যালিডেশন ব্যর্থ হয়েছে (সিগনেচার মিল নেই, টাইমস্ট্যাম্প পুরোনো, হেডার অনুপস্থিত)।
- Timed out: হ্যান্ডলার অনেক সময় নিয়েছিল, প্রোভাইডার এটিকে ব্যর্থ চিহ্নিত করল, তারপর রিট্রাই করল।
গ্রাহককে উত্তর দিচ্ছে সময় সংক্ষিপ্ত ও নির্দিষ্ট রাখুন: “আমরা 10:03 এবং 10:33 UTC-এ ডেলিভারি চেষ্টা পেয়েছি। প্রথমটি 10s পরে টাইমআউট হয়েছে; রিট্রাই প্রত্যাখ্যাত হয়েছে কারণ টাইমস্ট্যাম্প আমাদের 5-মিনিট উইন্ডো ছাড়িয়ে গেছে। আমরা উইন্ডো বর্ধিত করেছি এবং দ্রুত অ্যাকনলেজ যোগ করেছি। দরকার হলে ইভেন্ট ID X আবার পাঠাবেন।”
পরবর্তী ধাপ: এটাকে পুনরাবৃত্তিযোগ্য করুন
ওয়েবহুক বন্ধ করার দ্রুততম উপায় হল প্রতিটি ইন্টিগ্রেশন একই প্লেবুক অনুসরণ করা। আপনি এবং পাঠক যে চুক্তি করেছে তা লিখে রাখুন: প্রয়োজনীয় হেডার, সঠিক সাইনিং পদ্ধতি, কোন টাইমস্ট্যাম্প ব্যবহার হবে, এবং কোন ID আপনি ইউনিক মনে করবেন।
তারপর প্রতিটি ডেলিভারি-চেষ্টার জন্য আপনি যা রেকর্ড করবেন তা স্ট্যান্ডার্ড করুন। একটি ছোট রসিদ লগ সাধারণত যথেষ্ট: received_at, event_id, delivery_id, signature_valid, idempotency_result (new/duplicate), handler_version, এবং response status।
একটি কর্মপদ্ধতি যা বৃদ্ধি পেলে কার্যকর থাকে:
- একটি ডেডিকেটেড টেস্ট এন্ডপয়েন্ট রাখুন যা সিগনেচার যাচাই করে এবং ব্যবসায়িক অ্যাকশন না করে 2xx রিটার্ন করে
- ডিবাগ ও রিপ্লে করা পর্যন্ত কেবলমাত্র সংক্ষিপ্ত সময়ের জন্য raw request body এবং কী হেডারগুলো সংরক্ষণ করুন
- একটি রিপ্লে-সেইফ reprocess জব তৈরি করুন যা সংরক্ষিত ইভেন্টগুলো একই হ্যান্ডলার কোড পাথে পুনরায় চালায়
- সাপোর্ট, QA, এবং ইঞ্জিনিয়ারিং সবাই যে একটি অভ্যন্তরীণ চেকলিস্ট অনুসরণ করবে সেটি রাখুন
আপনি যদি Koder.ai (koder.ai)-এ অ্যাপ বানান, Planning Mode ওয়েবহুক কনট্র্যাক্ট প্রথমে সংজ্ঞায়িত করার (হেডার, সাইনিং, IDs, রিট্রাই বিহেভিওর) জন্য ভালো উপায় এবং তারপর বিভিন্ন প্রজেক্ট জুড়ে একটি সামঞ্জস্যপূর্ণ এন্ডপয়েন্ট ও রসিদ রেকর্ড জেনারেট করে। ঐ কনসিস্টেন্সিটিই ডিবাগিংকে দ্রুত করে, হিরোইক নয়।
সাধারণ প্রশ্ন
Why do webhooks seem to “randomly” fail or duplicate in production?
কারণ ওয়েবহুক ডেলিভারি সাধারণত at-least-once, ঠিক একবারই না। প্রোভাইডার টাইমআউট, 5xx রেসপন্স, এবং কখনও কখনও আপনার 2xx দেখা না গেলে রিট্রাই করে, তাই ডুপ্লিকেট, বিলম্ব, এবং অর্ডার-বহির্ভূত ডেলিভারি দেখা যায় এমনকি যখন সবই “ঠিকঠাক” চলছে।
What’s the safest basic flow for handling a webhook request?
এই নিয়মটি অনুসরণ করুন: প্রথমে সিগনেচার যাচাই করুন, তারপর ইভেন্ট সংরক্ষণ/ডেডুপ করুন, তারপর 2xx রেসপন্ড দিন, তারপর ভারি কাজ ব্যাকগ্রাউন্ডে করুন।
আপনি যদি রেসপন্ড করার আগে ভারি কাজ করেন, তাহলে টাইমআউটে রিট্রাই হবে; আর যদি রেকর্ড করার আগে রেটসপন্ড করেন, ক্র্যাশ হলে ইভেন্ট হারাতে পারেন।
How do I avoid signature mismatches when verifying webhooks?
ঠিক যেভাবে সার্ভারকে এসেছে সেই র ক ক ক (raw request body bytes) ব্যবহার করুন। যাচাইয়ের আগে JSON পার্স করে পুনরায় সিরিয়ালাইজ করবেন না—স্পেস, কী-অর্ডার, এবং নম্বর ফরম্যাটিং বদলে যেতে পারে এবং সিগনেচার ভাঙতে পারে।
এছাড়াও নিশ্চিত করুন যে আপনি প্রোভাইডারের সই করা পে-লোড ঠিক মতো পুনর্নির্মাণ করছেন (প্রায়শই timestamp + "." + raw_body)।
What should my endpoint do when signature verification fails?
একটি 4xx ফেরত দিন (সাধারণত 400 বা 401) এবং পে-লোড প্রক্রিয়াকরণ বন্ধ রাখুন।
তথ্যগত কারণ লগ করুন (সিগনেচার হেডার নেই, মিল নেই, টাইমস্ট্যাম্প আউট অফ উইন্ডো) কিন্তু সিক্রেট বা পূর্ণ সংবেদনশীল পে-লোড লগ করবেন না।
What is an idempotency key for webhooks, and which value should I use?
আইডেমপোটেন্সি কী হলো একটি স্থিতিশীল ইউনিক আইডেন্টিফায়ার যা আপনি সংরক্ষণ করেন যাতে রিট্রাই করতে গেলে সাইড-এফেক্টগুলি পুনরায় না ঘটে।
সেরা অপশনগুলো:
- Event ID (যখন এক ইভেন্ট একটি ব্যবসায়িক পরিবর্তনের জন্য একক)
- Delivery/message ID (যদি রিট্রাইগুলো একই ডেলিভারি আইডি রাখে)
- স্থায়ী ফিল্ডগুলোর হ্যাশ (শেষ বিকল্প)
কনকারেন্সির মধ্যে একটাই বিজয়ী হতে যাতে একটি unique constraint প্রয়োগ করুন।
How do I dedupe webhooks without race conditions?
আইডেমপোটেন্সি কীটি সাইড-এফেক্ট করার আগে লিখুন, এবং ইউনিকনেস রুল ব্যবহার করুন। তারপর সফল হলে প্রক্রিয়াকরণ মার্ক করুন, বা ব্যর্থ হলে রেকর্ড রেখে নিরাপদ রিট্রাই দিন।
ইনসার্ট যদি ফেইল করে কারণ কী আগে থেকেই আছে, তাহলে 2xx রিটার্ন করুন এবং ব্যবসায়িক কাজ স্কিপ করুন।
How do I add replay protection without rejecting legitimate retries?
পে-লোডের সাথে একটি টাইমস্ট্যাম্প সইয়ের ডেটায় অন্তর্ভুক্ত করুন এবং একটি সংক্ষিপ্ত উইন্ডো-এর বাইরে থাকা অনুরোধ প্রত্যাখ্যান করুন (উদাহরণ: কয়েক মিনিট)।
বৈধ রিট্রাই বন্ধ না করতে:
- কিছু ক্লক ড্রিফট অনুমান করুন
- প্রত্যাখ্যানের সময় সার্ভারের সময় এবং গ্রহণকৃত টাইমস্ট্যাম্প লগ করুন
- ডুপ্লিকেট প্রতিরোধে আইডেমপোটেন্সি কে প্রধান নিরাপত্তা হিসেবে রাখুন; টাইম উইন্ডো প্রধানত পুরোনো রিপ্লে বন্ধ করার জন্য
How should I handle out-of-order webhook events?
ডেলিভারি অর্ডারকে ইভেন্ট অর্ডারের সমতূল্য ধরে নেবেন না। হ্যান্ডলারগুলোকে সহনশীল রাখুন:
- সম্ভব হলে upserts ব্যবহার করুন
- পরিবর্তন করার আগে বর্তমান অবস্থা চেক করুন
- যদি অবজেক্ট না পাওয়া যায়, তখন স্থায়ী ব্যর্থতার বদলে পরে (কিউ থেকে) পুনরায় চেষ্টা বিবেচনা করুন
ইভেন্ট ID এবং টাইপ সংরক্ষণ করুন যাতে অর্ডার অদ্ভুত হলেও কি ঘটেছে বোঝা যায়।
What should I log so webhook debugging doesn’t turn into guessing?
প্রতিটি ডেলিভারি-চেষ্টার জন্য একটি ছোট “রসিদ” লগ করুন যাতে আপনি একটি ইভেন্ট শেষ পর্যন্ত ট্রেস করতে পারেন:
- provider, event_id, delivery_id
- signature_ok, replay_ok
- idempotency result (new/duplicate)
- response_code, latency_ms
- timestamps (received/first_seen/last_seen)
লগগুলো ইভেন্ট ID দ্বারা সার্চযোগ্য রাখুন যেন সাপোর্ট দ্রুত গ্রাহকের রিপোর্ট উত্তর দিতে পারে।
What’s a fast way to investigate a customer report that “a webhook never arrived”?
একটি একক নির্দিষ্ট আইডেন্টিফায়ার চান: event ID বা delivery ID এবং আনুমানিক টাইমস্ট্যাম্প।
তারপর এই ক্রমে চেক করুন:
- সিগনেচার যাচাই ফলাফল
- টাইমস্ট্যাম্প/রিপ্লে উইন্ডো ফলাফল (যদি ব্যবহার করে)
- আইডেমপোটেন্সি ফলাফল (new vs duplicate)
- আপনি কী রিটার্ন করেছিলেন (status code + latency)
Koder.ai ব্যবহার করলে হ্যান্ডলার প্যাটার্ন কনসিস্টেন্ট রাখুন (verify → record/dedupe → queue → respond)। কনসিস্টেন্সি এই চেকগুলো দ্রুত করে।