দীর্ঘকালীন কাজের জন্য ঘটনাভিত্তিক ওয়ার্কফ্লো বনাম রিকোয়েস্ট‑রেসপন্স এপিআই
অনুমোদন, টাইমার, রিট্রাই ও অডিট ট্রেইলসহ দীর্ঘ-চলমান প্রসেসের জন্য ঘটনাভিত্তিক ওয়ার্কফ্লো বনাম রিকোয়েস্ট-রেসপন্স এপিআই কীভাবে ভিন্ন এবং কখন কোনটি উত্তম তা তুলনা করুন।

কেন ব্যবসায়িক অ্যাপে দীর্ঘ-চলমান প্রসেসগুলো জটিল\n\nকোনো প্রসেস “দীর্ঘ-চলমান” যখন তা একটিবারে শেষ হয় না। সেটা মিনিট, ঘণ্টা বা দিন সময় নিতে পারে কারণ মানুষ, সময় বা বাইরের সিস্টেমের উপর নির্ভর করে। অনুমোদন, হ্যান্ডঅফ এবং অপেক্ষা থাকা যেকোনো কাজ এই স্তরে পড়ে।\n\nএখানেই সরল request-response API চিন্তা ভাঙতে শুরু করে। একটি API কল দ্রুত বিনিময়ের জন্য তৈরি: অনুরোধ পাঠান, উত্তর নিন, চালিয়ে যান। দীর্ঘ কাজগুলো একধরনের কাহিনীর মতো যার অধ্যায় আছে। আপনাকে থামতে হবে, ঠিক কোথায় আছেন সেটা মনে রাখতে হবে, এবং পরে অনুমান না করে আবার চালাতে হবে।\n\nএটি প্রতিদিনকার ব্যবসায়িক অ্যাপে দেখা যায়: ম্যানেজার ও ফাইন্যান্স উভয়ের অনুমোদন লাগা ক্রয় অনুমোদন, ডকুমেন্ট চেকের জন্য অপেক্ষা করা অনবোর্ডিং, পেমেন্ট প্রোভাইডারের উপর নির্ভরশীল রিফান্ড, বা পর্যালোচনা করে অ্যাক্সেস প্রয়োগ করা রিকোয়েস্ট।\n\nযখন টিমগুলো একটি দীর্ঘ প্রসেসকে একক API কল হিসেবে দেখে, কয়েকটি প্রত্যাশিত সমস্যা দেখা দেয়:\n\n- রিস্টার্ট বা ডিপ্লয়ের পরে অ্যাপ স্টেট হারায় এবং নির্ভরযোগ্যভাবে পুনরায় চালানো যায় না।\n- রিট্রাই হলে ডুপ্লিকেট তৈরি হয়: দ্বিতীয় পেমেন্ট, দ্বিতীয় ইমেল, দ্বিগুণ অনুমোদন।\n- মালিকানা অস্পষ্ট হয়ে যায়: পরবর্তী কাজটি অনুরোধকারী, ম্যানেজার নাকি একটি সিস্টেম জব করবে তা কেউ জানে না।\n- সাপোর্টের দৃশ্যমানতা নেই এবং "কোথায় আটকে আছে?" এর উত্তর পেতে লগ খোঁজাখুঁজি করতে হয়।\n- অপেক্ষার লজিক (টাইমার, রিমাইন্ডার, ডেডলাইন) ভঙ্গুর ব্যাকগ্রাউন্ড স্ক্রিপ্টে পড়ে যায়।\n\nএকটি স্পষ্ট দৃশ্য: একজন কর্মী সফটওয়্যার অ্যাক্সেস অনুরোধ করে। ম্যানেজার দ্রুত অনুমোদন করে, কিন্তু IT-কে প্রোভিশন করতে দুই দিন লাগে। যদি অ্যাপ প্রসেস স্টেট ধরে রাখতে, রিমাইন্ডার পাঠাতে এবং নিরাপদে রিস্যুম করতে না পারে, তাহলে মানুয়াল ফলো‑আপ, বিভ্রান্ত ব্যবহারকারী এবং অতিরিক্ত কাজ হয়।\n\nএই কারণেই দীর্ঘ-চলমান ব্যবসায়িক প্রসেসগুলোর জন্য ঘটনাভিত্তিক ওয়ার্কফ্লো বনাম রিকোয়েস্ট-রেসপন্স এপিআই—এই বিকল্পগুলোর নির্বাচন গুরুত্বপূর্ণ।\n\n## দুইটি মানসিক মডেল: সিঙ্ক্রোনাস কল বনাম সময়ের ওপর ইভেন্ট\n\nসবচেয়ে সরল তুলনা এক প্রশ্নে এসে পড়ে: কাজ কি ব্যবহারকারী অপেক্ষা করার সময়েই শেষ হয়, নাকি তারা চলে যাওয়ার পর চলতেই থাকে?\n\nএকটি request-response API একটি একক বিনিময়: একবার কল, একবার রেসপন্স। এটি দ্রুত ও পূর্বানুমানযোগ্য কাজের জন্য মানায়, যেমন একটি রেকর্ড তৈরি করা, কোট গণনা করা, বা স্টক চেক করা। সার্ভার কাজ করে, সফলতা বা ব্যর্থতা ফেরত দেয়, এবং ইন্টারঅ্যাকশন শেষ।\n\nএকটি ঘটনাভিত্তিক ওয়ার্কফ্লো সময়ের ওপর প্রতিক্রিয়াগুলোর সিরিজ। কিছু ঘটে (অর্ডার তৈরি, ম্যানেজার অনুমোদন, টাইমার সময় মূল্যহীন হওয়া) এবং ওয়ার্কফ্লো পরবর্তী ধাপে চলে যায়। এই মডেলটিই উপযুক্ত যেখানে হ্যান্ডঅফ, অপেক্ষা, রিট্রাই ও রিমাইন্ডার থাকে।\n\nব্যবহারিক পার্থক্যটি হচ্ছে স্টেট।\n\nrequest-response-এ স্টেট প্রায়ই চলতি রিকোয়েস্ট ও সার্ভারের মেমরিতে থাকে যতক্ষণ না রেসপন্স পাঠানো হয়। ইভেন্ট-ড্রিভেন ওয়ার্কফ্লোতে স্টেট সংরক্ষণ করতে হয় (উদাহরণ: PostgreSQL) যাতে প্রসেস পরে পুনরায় চালানো যায়।\n\nফেইলিউর হ্যান্ডলিংও বদলে যায়। request-response সাধারণত ব্যর্থতা যোগাযোগ করে এবং ক্লায়েন্টকে পুনরায় চেষ্টা করতে বলে। ওয়ার্কফ্লো ব্যর্থতাকে রেকর্ড করে এবং পরিস্থিতি ভালো হলে নিরাপদভাবে রিট্রাই করতে পারে। এছাড়া তারা প্রতিটি ধাপকে একটি ইভেন্ট হিসেবে লগ করে, যা ইতিহাস পুনর্গঠন সহজ করে।\n\nসহজ উদাহরণ: “খরচ রিপোর্ট জমা দিন” সিঙ্ক্রোনাস হতে পারে। “অনুমোদন নিন, ৩ দিন অপেক্ষা করুন, ম্যানেজারকে স্মরণ করিয়ে দিন, তারপর পে করুন” নয়।\n\n## অনুমোদন: প্রতিটি উপায় মানব সিদ্ধান্তকে কিভাবে হ্যান্ডেল করে\n\nঅনুমোদনগুলোই যেখানে দীর্ঘ-চলমান কাজ সত্যি রূপ নেয়। সিস্টেম ধাপ মিলিসেকেন্ডে শেষ হয়, কিন্তু মানুষ উত্তর দিতে দুই মিনিট বা দুই দিন নিতে পারে। মূল ডিজাইন প্রশ্ন হচ্ছে: আপনি কি সেই অপেক্ষাটিকে একটি paus করা প্রসেস হিসেবে মডেল করবেন, না কি পরে আসা একটি নতুন মেসেজ হিসেবে?\n\nrequest-response API-তে অনুমোদন প্রায়ই অস্বস্তিকরভাবে দাঁড়ায়:\n\n- ব্লকিং (ব্যবহারিক নয়)\n- পোলিং (ক্লায়েন্ট বারবার “অনুমোদিত হয়েছে কি?” জিজ্ঞেস করে)\n- কলব্যাক/ওয়েবহুক (সার্ভার পরে আপনাকে কল করে)\n\nএসব কাজ করে, কিন্তু মানুষিক সময়কে API সময়ের সাথে সংযুক্ত করতে অতিরিক্ত প্লাম্বিং লাগে।\n\nইভেন্ট-ভিত্তিক পদ্ধতিতে অনুমোদন একটি গল্পের মতো পড়ে। অ্যাপ কিছু রেকর্ড করে যেমন “ExpenseSubmitted,” তারপর পরে “ExpenseApproved” বা “ExpenseRejected” আসে। ওয়ার্কফ্লো ইঞ্জিন (বা আপনার নিজের স্টেট মেশিন) পরবর্তী ইভেন্ট আসলে রেকর্ডটিকে এগিয়ে নিয়ে যায়। এটি বেশিরভাগ মানুষের ব্যবসায়িক ধাপের চিন্তার সঙ্গে মেলে: জমা দিন, পর্যালোচনা করুন, সিদ্ধান্ত নিন।\n\nনিয়োজিততা দ্রুত জটিলতা এনে দেয় যখন একাধিক অনুমোদনকারী ও এসকেলেশন নিয়ম থাকে। আপনি হয়ত ম্যানেজার এবং ফাইন্যান্স—দুইজনের অনুমোদন চাইতে পারেন, আবার সিনিয়র ম্যানেজার ওভাররাইড করতে পারবেন। যদি আপনি সেই নিয়মগুলো স্পষ্টভাবে মডেল না করেন, প্রসেসটি বোঝা ও অডিট করা কঠিন হয়ে যায়।\n\n### একটি সহজ স্কেলেবল অনুমোদন মডেল\n\nপ্রায়োগিক প্যাটার্ন হচ্ছে একটি “রিকোয়েস্ট” রেকর্ড রাখা, তারপর সিদ্ধান্তগুলো আলাদাভাবে সংরক্ষণ করা। এইভাবে আপনি অনেক অনুমোদনকারী সমর্থন করতে পারবেন মূল লজিক না বদলে।\n\nকয়েকটি ডেটা আইটেমকে ফার্স্ট‑ক্লাস রেকর্ড হিসেবে ক্যাপচার করুন:\n\n- অনুমোদন অনুরোধ: কী অনুমোদন হচ্ছে এবং বর্তমান স্ট্যাটাস\n- ব্যক্তিগত সিদ্ধান্ত: কে সিদ্ধান্ত নিয়েছে, অনুমোদন/প্রত্যাখ্যান, টাইমস্টাম্প, কারণ\n- প্রয়োজনীয় অনুমোদনকারীরা: ভূমিকা বা ব্যক্তি, এবং অর্ডারিং নিয়ম\n- ফলাফল নিয়ম: “যে কেউ একজন্তে,” “সংখ্যাগরিষ্ঠ,” “সব প্রয়োজনীয়,” “ওভাররাইড অনুমোদিত”\n\nযে কোনো ইমপ্লিমেনটেশনই বেছে নিন, সর্বদা রাখুন — কে কখন কেন কী অনুমোদন বা প্রত্যাখ্যান করেছে তা ডেটা হিসেবে, শুধু লগ লাইনের মতো নয়।\n\n## টাইমার ও অপেক্ষা: রিমাইন্ডার, ডেডলাইন ও এসকেলেশন\n\nঅপেক্ষা হচ্ছে যেখানে দীর্ঘ কাজগুলো জটিল মনে হতে শুরু করে। মানুষ লাঞ্চে যায়, ক্যালেন্ডার ব্যস্ত থাকে, এবং “আমরা ফিরে আসব” হয়ে যায় “এখন কার দায়িত্ব?” এটি ঘটনাভিত্তিক ওয়ার্কফ্লো বনাম রিকোয়েস্ট-রেসপন্স এপিআইয়ের মধ্যে স্পষ্ট পার্থক্যগুলোর একটি।\n\nrequest-response API-তে সময় অদ্ভুত। HTTP কলের টাইমআউট আছে, তাই আপনি দুই দিন একটি অনুরোধ খোলা রাখতে পারবেন না। টিমগুলো সাধারণত প্যাটার্নগুলোর দিকে যায় যেমন পোলিং, ডাটাবেস স্ক্যান করে আলাদা একটি শিডিউলড জব, বা ম্যানুয়াল স্ক্রিপ্ট যখন কিছু ওভারডিউ হয়। এগুলো কাজ করে, কিন্তু অপেক্ষার লজিক প্রসেসের বাইরে থাকে। কোর্নার কেসগুলো সহজেই মিস হয়ে যায় — উদাহরণ: জব দুটি বার চালালে কী হয়, বা রিমাইন্ডারের ঠিক আগে রেকর্ডটি পরিবর্তিত হলে কী হয়।\n\nওয়ার্কফ্লোতে সময়কে একটি সাধারণ ধাপ হিসেবে দেখা হয়। আপনি বলতে পারেন: ২৪ ঘণ্টা অপেক্ষা করুন, একটি রিমাইন্ডার পাঠান, তারপর মোট ৪৮ ঘন্টার পরে এসকেলেট করুন। সিস্টেম স্টেট রাখে, তাই ডেডলাইনগুলো আলাদা “ক্রন + কোয়েরি” প্রকল্পে লুকায়িত থাকে না।\n\nএকটি সহজ নিয়ম এমন হতে পারে:\n\nখরচ রিপোর্ট জমা হওয়ার পর ১ দিন অপেক্ষা করুন। যদি স্ট্যাটাস এখনও "Pending" থাকে, ম্যানেজারকে মেসেজ পাঠান। ২ দিনের পরে, যদি এখনও পেন্ডিং থাকে, ম্যানেজারের লিডকে পুনরায় নিয়োগ করুন এবং এসকেলেশন রেকর্ড করুন।\n\nটায়মার ফায়ার করার সময় কিন্তু বিশ্ব বদলে গেলে কি করবেন—এইটাই মূল বিষয়। একটি ভালো ওয়ার্কফ্লো সবসময় কাজ করার আগে বর্তমান স্টেট পুনরায় যাচাই করে:\n\n- সর্বশেষ স্ট্যাটাস লোড করুন\n- নিশ্চিত করুন এটা এখনও পেন্ডিং\n- নিশ্চিত করুন অ্যাসাইনি এখনও বৈধ (টিম পরিবর্তন হতে পারে)\n- যা সিদ্ধান্ত নেবেন তা রেকর্ড করুন এবং কেন নেয়া হলো তা লিখে রাখুন\n\n## রিট্রাই ও ব্যর্থতা পুনরুদ্ধার বিনা ডুপ্লিকেট অ্যাকশন\n\nরিট্রাই হচ্ছে যখন কিছু আপনার নিয়ন্ত্রণে নেই এমন কারণে ব্যর্থ হয়: একটি পেমেন্ট গেটওয়ে টাইমআউট করে, ইমেল প্রোভাইডার সাময়িক ভুল রিটার্ন করে, বা আপনার অ্যাপ ধাপ A সংরক্ষণ করে কিন্তু ধাপ B-এর আগে ক্র্যাশ করে। বিপদটি সহজ: আপনি আবার চেষ্টা করলে ভুলবশত একই অ্যাকশন দু’বার হয়ে যেতে পারে।\n\nrequest-response-এ সাধারণ প্যাটার্ন হচ্ছে ক্লায়েন্ট একটি এন্ডপয়েন্ট কল করে, অপেক্ষা করে, এবং স্পষ্ট সফলতা না পেলে আবার চেষ্টা করে। সেটি নিরাপদ করতে হলে সার্ভারকে পুনরাবৃত্ত কলগুলিকে একই অভিপ্রায় হিসেবে হ্যান্ডেল করতে হবে।\n\nএকটি বাস্তবসম্মত সমাধান হলো idempotency কী: ক্লায়েন্ট একটি ইউনিক টোকেন পাঠায় যেমন pay:invoice-583:attempt-1। সার্ভার ওই কী-র জন্য আউটকাম সংরক্ষণ করে এবং পুনরাবৃত্তির ক্ষেত্রেও একই ফলাফল ফেরত দেয়। এটি ডাবল চার্জ, ডুপ্লিকেট টিকেট বা ডুপ্লিকেট অনুমোদনকে প্রতিরোধ করে।\n\nইভেন্ট-ড্রিভেন ওয়ার্কফ্লোতে আরেক ধরনের ডুপ্লিকেট ঝুঁকি থাকে। ইভেন্টগুলো প্রায়ই at-least-once ডেলিভারি করে, যার অর্থ ডুপ্লিকেট আসতে পারে এমনকি সবকিছু ঠিকঠাক থাকলেও। কনজিউমারদের ডেডুপ্লিকেশন করতে হবে: ইভেন্ট আইডি (বা ব্যবসায়িক কী যেমন invoice_id + step) সংরক্ষণ করে পুনরাবৃত্তিকে উপেক্ষা করুন। এটি ওয়ার্কফ্লো অর্কেস্ট্রেশনের মূল পার্থক্য: request-response নিরাপদ কল রেপ্লে‑র ওপর ফোকাস করে, আর ইভেন্ট নিরাপদ মেসেজ রেপ্লে‑র ওপর।\n\nকয়েকটি রিট্রাই নিয়ম উভয় মডেলেই কাজ করে:\n\n- ব্যাকঅফ ব্যবহার করুন (উদাহরণ: 10s, 30s, 2m).\n- একটি সর্বোচ্চ প্রচেষ্টা সীমা নির্ধারণ করুন।\n- সাময়িক ত্রুটি (রিট্রাই) ও স্থায়ী ত্রুটি (দ্রুত ফেইল) আলাদা করুন।\n- পুনরাবৃত্ত ব্যর্থতাগুলোকে “needs attention” স্টেটে পাঠান।\n- প্রতিটি প্রচেষ্টা লগ করুন যাতে পরে বোঝানো যায় কি ঘটেছিল।\n\nরিট্রাইগুলো প্রসেসের মধ্যে স্পষ্ট হওয়া উচিত, লুকোনো আচরণ নয়। এভাবেই ব্যর্থতাকে দৃশ্যমান ও মেরামতযোগ্য করা যায়।\n\n## অডিট ট্রেইল: প্রসেসকে ব্যাখ্যাযোগ্য করা\n\nঅডিট ট্রেইল হল আপনার “কেন” ফাইল। যখন কেউ বলে, “কেন এই খরচ প্রত্যাখ্যাত করা হয়েছে?” আপনাকে অনুমান না করেই উত্তর দিতে হবে, এমনকি মাস পরে। এটি ঘটনাভিত্তিক ওয়ার্কফ্লো এবং request-response উভয়ের ক্ষেত্রেই জরুরি, কিন্তু কাজটি আলাদা ভাবে করে।\n\nযে কোনো দীর্ঘ-চলমান প্রসেসের জন্য, সেই ফ্যাক্টগুলো রেকর্ড করুন যেগুলো দিয়ে আপনি গল্পটি রেপ্লে করতে পারবেন:\n\n- অ্যাক্টর: কে করেছে (ব্যবহারকারী, সার্ভিস, বা সিস্টেম টাইমার)\n- সময়: কখন ঘটলো (টাইমজোনসহ)\n- ইনপুট: তখন কী জানা ছিল (পরিমাণ, ভেন্ডর, নীতি সীমা, অনুমোদন)\n- আউটপুট: কি সিদ্ধান্ত/অ্যাকশন নেওয়া হয়েছিল (অনুমোদিত, প্রত্যাখ্যাত, পেড, রিট্রাই করা)\n- রুল ভার্সন: কোন পলিসি/লজিক ভার্সন ব্যবহার করা হয়েছিল\n\nইভেন্ট-ড্রিভেন ওয়ার্কফ্লো অডিটিংকে সহজ করতে পারে কারণ প্রতিটি ধাপ স্বাভাবিকভাবে একটি ইভেন্ট উৎপন্ন করে যেমন “ManagerApproved” বা “PaymentFailed.” যদি আপনি সেই ইভেন্টগুলো পে-লোড এবং অ্যাক্টরের সাথে সংরক্ষণ করেন, একটি পরিষ্কার টাইমলাইন পাওয়া যায়। মূল কথা হচ্ছে ইভেন্টগুলো বর্ণনামূলক রাখুন এবং কেস অনুযায়ী প্রশ্ন চালানোর মতো সেভ করুন।\n\nrequest-response এপিআইও অডিটযোগ্য হতে পারে, কিন্তু গল্পটি সাধারণত বিভিন্ন সার্ভিসে ছড়িয়ে থাকে। এক এন্ডপয়েন্ট বলবে “approved,” আরেকটি বলবে “payment requested,” আর তৃতীয়টি বলবে “retry succeeded।” যদি প্রতিটির ফরম্যাট বা ফিল্ড আলাদা হয়, অডিট একটি গোয়েন্দা কাজ হয়ে দাঁড়ায়।\n\nএকটি সহজ সমাধান হলো একটি শেয়ার্ড “কেস আইডি” (কোরিলেশন আইডি) — এটি প্রতিটি রিকোয়েস্ট, ইভেন্ট এবং ডাটাবেস রেকর্ডে লাগান, যেমন “EXP-2026-00173.” তখন আপনি পুরো যাত্রা ট্রেস করতে পারবেন।\n\n## সঠিক পদ্ধতি নির্বাচন করা: শক্তি ও ট্রেড‑অফ\n\nসেরা পছন্দ নির্ভর করে আপনার কি এখনই উত্তর দরকার, না কি প্রসেসটি ঘণ্টা বা দিন ধরে চলতে থাকবে।\n\nRequest-response ভালো যখন কাজটি সংক্ষিপ্ত এবং নিয়মগুলো সরল। ব্যবহারকারী একটি ফর্ম জমা দেয়, সার্ভার সেটি ভ্যালিডেট করে, ডেটা সেভ করে, এবং সফলতা বা ত্রুটি ফেরত দেয়। এটি স্পষ্ট, একক ধাপের কাজগুলোর জন্যও মানায় যেমন তৈরি, আপডেট বা অনুমতি যাচাই।\n\nএটা কষ্ট দেয় যখন একটি “একক অনুরোধ” গোপনে অনেক ধাপে পরিণত হয়: অনুমোদনের অপেক্ষা, একাধিক বাইরের সিস্টেম কল, টাইমআউট হ্যান্ডলিং, বা পরবর্তী পদক্ষেপের ওপর শাখা। আপনি বা তো একটি কানেকশন খোলে রাখবেন (ভঙ্গুর), বা আপনি অপেক্ষা ও রিট্রাইগুলো ব্যাকগ্রাউন্ড জব‑এ ঠেলে দেবেন যা বোঝা কঠিন।\n\nইভেন্ট-ড্রিভেন ওয়ার্কফ্লো তখন জ্বলজ্বল করে যখন প্রসেসটি সময়ের ওপর একটি কাহিনী। প্রতিটি ধাপ একটি নতুন ইভেন্ট (approved, rejected, timer fired, payment failed) এর প্রতিক্রিয়ায় সিদ্ধান্ত নেয়। এতে paus, রিট্রাই, এবং কেন সিস্টেমটা এটা করলো—তা পরিষ্কার ট্রেইল রাখা সহজ হয়।\n\nকিছু বাস্তব ট্রেড‑অফ আছে:\n\n- সরলতা বনাম টেকসইতা: request-response শুরুতে সহজ, ইভেন্ট-ড্রিভেন দীর্ঘ বিলম্বে নিরাপদ।\n- ডিবাগিং ধরন: request-response সরাসরি ধারায় চলে, ওয়ার্কফ্লোতে ধাপগুলো জুড়ে ট্রেস করা লাগে।\n- টুলিং ও অভ্যাস: ইভেন্টগুলোর জন্য ভাল লগিং, কোরিলেশন আইডি এবং পরিষ্কার স্টেট মডেল দরকার।\n- পরিবর্তন ব্যবস্থাপনা: ওয়ার্কফ্লো যত বৃদ্ধি পায়, শাখাগুলি যত বাড়ে; ইভেন্ট-ড্রিভেন ডিজাইন ভালোভাবে মডেল করলে নতুন পথে খোলার ক্ষেত্রে সহায়ক।\n\nএকটি বাস্তব উদাহরণ: একটি খরচ রিপোর্ট—ম্যানেজার অনুমোদন, তারপর ফাইন্যান্স রিভিউ, তারপর পেমেন্ট। যদি পেমেন্ট ব্যর্থ হয়, আপনি রিট্রাই চান ডাবল‑পেমেন্ট না করে। এটি স্বাভাবিকভাবেই ইভেন্ট-ড্রিভেন। আর যদি কেবল “খরচ জমা” এবং দ্রুত চেক হয়, request-response যথেষ্ট।\n\n## ধাপে ধাপে: একটি দীর্ঘ-চলমান প্রসেস ডিজাইন করা যা বিলম্ব টিকে টিকিয়ে রাখতে পারে\n\nদীর্ঘ-চলমান ব্যবসায়িক প্রসেসগুলো সাধারণত বিরক্তিকরভাবে ব্যর্থ হয়: ব্রাউজার ট্যাব বন্ধ, সার্ভার রিস্টার্ট, অনুমোদন তৃতীয় দিনেও নাও আসা, বা পেমেন্ট প্রোভাইডার টাইমআউট। যেকোন মডেলই পছন্দ করুন, শুরু থেকেই সেই বিলম্বগুলোকে বিবেচনায় নিয়ে ডিজাইন করুন।\n\nপ্রথমে একটি ছোট স্টেট সেট সংজ্ঞায়িত করুন যা আপনি সংরক্ষণ ও রিস্যুম করতে পারেন। যদি আপনি ডাটাবেসে বর্তমান স্টেটটি নির্দেশ করতে না পারেন, আপনার সত্যিকারের রিসুমেবল ওয়ার্কফ্লো নেই।\n\n### একটি সহজ ডিজাইন সিকোয়েন্স\n\n1. সীমানা নির্ধারণ করুন: শুরু ট্রিগার, সমাপ্তি শর্ত এবং কয়েকটি মূল স্টেট (Pending approval, Approved, Rejected, Expired, Completed) ঠিক করুন।\n2. ইভেন্ট ও সিদ্ধান্তগুলোর নামকরণ করুন: সময়ের ওপর কী কী ঘটতে পারে লিখে রাখুন (Submitted, Approved, Rejected, TimerFired, RetryScheduled). ইভেন্ট নামগুলো অতীত কাল ব্যবহার করুন।\n3. অপেক্ষার পয়েন্ট চিহ্নিত করুন: কোথায় প্রসেস একজন মানুষের, বাইরের সিস্টেমের, বা ডেডলাইনের জন্য paus করে।\n4. প্রতিটি ধাপে টাইমার ও রিট্রাই নিয়ম যোগ করুন: সময় পেরুবে কী হবে বা কল ব্যর্থ হলে কী হবে (ব্যাকঅফ, সর্বোচ্চ প্রচেষ্টা, এসকেলেট, ত্যাগ)।\n5. কীভাবে প্রসেস পুনরায় চালু হবে তা সংজ্ঞায়িত করুন: প্রতিটি ইভেন্ট বা কলব্যাকে, সংরক্ষিত স্টেট লোড করুন, যাচাই করুন এটা এখনও বৈধ, তারপর পরবর্তী স্টেটে যান।\n\nরিস্টার্টগুলো টিকে থাকার জন্য, চালিয়ে যাওয়ার জন্য ন্যূনতম ডেটা পERSIST করুন। পুনরায় চালানোর জন্য যথেষ্ট সংরক্ষণ করুন যাতে অনুমান করার দরকার না পড়ে:\n\n- প্রসেস ইনস্ট্যান্স আইডি এবং বর্তমান স্টেট\n- পরবর্তী কে কাজ করতে পারে (অ্যাসাইনি/রোল) এবং তারা কী সিদ্ধান্ত নিয়েছে\n- ডেডলাইন (due_at, remind_at) ও এসকেলেশন লেভেল\n- রিট্রাই মেটাডেটা (চেষ্টার সংখ্যা, শেষ ত্রুটি, next_retry_at)\n- সাইড‑ইফেক্টের জন্য আইডেম্পোটেন্সি কী বা “ইতিমধ্যে করা” ফ্ল্যাগ\n\nআপনি যদি "বর্তমানে আমরা কোথায় আছি" এবং "পরবর্তী কী অনুমোদিত" ডাটাবেস থেকে পুনর্গঠন করতে পারেন, তবে বিলম্ব আর ভয়ানক হবে না।\n\n## সাধারণ ভুল ও কীভাবে এড়াবেন\n\nদীর্ঘ-চলমান প্রসেসগুলো বেশিরভাগই তখনই ভাঙে যখন বাস্তব ব্যবহারকারীরা আসে। অনুমোদন দুই দিন নেয়, একটি রিট্রাই ভুল সময়ে ফায়ার করে, এবং আপনি ডাবল পেমেন্ট বা অনুপস্থিত অডিট ট্রেইল পেয়ে যান।\n\nসাধারণ ভুলগুলো:\n\n- HTTP রিকোয়েস্ট খোলা রাখা যখন একজন মানুষের অনুমোদনের জন্য অপেক্ষা হচ্ছে। এটি টাইমআউট হয়, সার্ভার রিসোর্স বাঁধে এবং ব্যবহারকারীকে মিথ্যে ধারণা দেয় যে “কিছু হচ্ছে।”\n- আইডেম্পোটেন্সি ছাড়া কলগুলো রিট্রাই করা। নেটওয়ার্ক গ্লিচ ডুপ্লিকেট ইনভয়েস, ডুপ্লিকেট ইমেইল বা পুনরাবৃত্ত “Approved” ট্রানজিশন তৈরি করতে পারে।\n- প্রসেস স্টেট সংরক্ষণ না করা। যদি স্টেট মেমরিতে থাকে, রিস্টার্টে তা মুছে যায়। যদি স্টেট কেবল লগে থাকে, আপনি নির্ভরযোগ্যভাবে চালিয়ে যেতে পারবেন না।\n- অস্পষ্ট অডিট ট্রেইল। ইভেন্টগুলোর আলাদা ঘড়ি ও ফরম্যাট থাকলে টাইমলাইন একটি ইনসিডেন্ট বা কমপ্লায়েন্স রিভিউতে বিশ্বাসযোগ্য থাকে না।\n- অ্যাসিঙ্ক এবং সিঙ্ক মিশিয়ে ফেলার ফলে একক সত্যের উৎস না থাকা। একটি সিস্টেম বলে “Paid,” অন্যটি বলে “Pending,” এবং কেউ কোনটি সঠিক তা জানে না।\n\nএকটি সহজ উদাহরণ: খরচ রিপোর্ট চ্যাটে অনুমোদিত হয়, একটি ওয়েবহুক দেরিতে আসে, এবং পেমেন্ট API রিট্রাই পায়। স্টেট ও আইডেম্পোটেন্সি না থাকলে রিট্রাই ডাবল পেমেন্ট পাঠাতে পারে, এবং আপনার রেকর্ডগুলো স্পষ্টভাবে ব্যাখ্যা করবে না কেন তা ঘটেছে।\n\nএকটি বড় অংশের সমাধান হল স্পষ্টতা:\n\n- স্টেট ট্রানজিশনগুলো (Requested, Approved, Rejected, Paid) ডাটাবেসে পERSIST করুন, কে/কী পরিবর্তন করেছে তা সহ।\n- প্রত্যেকটি বাইরের সাইড-ইফেক্টের জন্য idempotency কী ব্যবহার করুন এবং ফলাফল সংরক্ষণ করুন।\n- “অনুরোধ গ্রহণ করুন” এবং “কাজ সম্পন্ন করুন” আলাদা রাখুন: দ্রুত রিটার্ন দিন, তারপর ব্যাকগ্রাউন্ডে ওয়ার্কফ্লো সম্পন্ন করুন।\n- টাইমস্ট্যাম্প স্ট্যান্ডার্ডাইজ করুন (UTC), কোরিলেশন আইডি যোগ করুন, এবং অনুরোধ ও আউটকাম উভয় রেকর্ড করুন।\n\n## গঠনের আগে দ্রুত চেকলিস্ট\n\nদীর্ঘ-চলমান কাজ একটা নিখুঁত কলের চেয়ে বেশি—এটি বিলম্ব, মানুষ ও ত্রুটির পরেও সঠিক থাকা সম্পর্কে।\n\nআপনার প্রসেস জন্য “নিরাপদভাবে চালিয়ে যাওয়া” কী মানে তা লিখে রাখুন। যদি অ্যাপ মাঝপথে রিস্টার্ট হয়, আপনাকে শেষ পরিচিত ধাপ থেকে অনুমান না করে চালিয়ে যেতে সক্ষম হতে হবে।\n\nপ্রায়োগিক চেকলিস্টঃ\n\n- ক্র্যাশ বা ডিপ্লয়ের পরে প্রসেস কিভাবে রিস্যাম করবে তা সংজ্ঞায়িত করুন। কি স্টেট সেভ হবে, এবং পরবর্তী কি চালাবে?\n- প্রতিটি ইনস্ট্যান্সকে একটি ইউনিক প্রসেস কী দিন (যেমন ExpenseRequest-10482) এবং একটি স্পষ্ট স্ট্যাটাস মডেল (Submitted, Waiting for Manager, Approved, Paid, Failed) দিন।\n- অনুমোদনগুলোকে কেবল আউটকাম হিসেবে নয়, রেকর্ড হিসেবে বিবেচনা করুন: কে অনুমোদন/প্রত্যাখ্যান করেছে, কখন, এবং মন্তব্য বা কারণ কোড।\n- অপেক্ষার নিয়মগুলো ম্যাপ করুন: রিমাইন্ডার, ডেডলাইন, এসকেলেশন, মেয়াদোত্তীর্ণতা। প্রতিটি টাইমারের জন্য একজন মালিক নামান (ম্যানেজার, ফাইন্যান্স, সিস্টেম)।\n- ব্যর্থতা হ্যান্ডলিং পরিকল্পনা করুন: রিট্রাই সীমিত ও নিরাপদ হতে হবে, এবং একটি “needs review” স্টপ থাকা উচিত যেখানে একজন মানুষ ডেটা ঠিক করে বা পুনরায় চেষ্টা অনুমোদন করে।\n\nএকটি স্বাস্থ্য পরীক্ষা: কল্পনা করুন পেমেন্ট প্রোভাইডার টাইমআউট করে যখন আপনি ইতিমধ্যে কার্ড চার্জ করে ফেলেছেন। আপনার ডিজাইনটি কিভাবে ডাবল‑চার্জ প্রতিরোধ করবে এবং প্রসেসটি সম্পন্ন হতে দেবে—এটাই পরীক্ষা।\n\n## উদাহরণ: ডেডলাইন ও পেমেন্ট রিট্রাই সহ খরচ অনুমোদন\n\nদৃশ্য: একজন কর্মী $120 ট্যাক্সি রসিদের জন্য রিইম্বার্সমেন্ট অনুরোধ করে। এটি ম্যানেজারের ৪৮ ঘণ্টার মধ্যে অনুমোদন দরকার। অনুমোদিত হলে সিস্টেম কর্মীকে পেমেন্ট পাঠায়। যদি পেমেন্ট ব্যর্থ হয়, সেটি নিরাপদভাবে রিট্রাই করে এবং পরিষ্কার রেকর্ড রেখে দেয়।\n\n### Request-response ওয়াকথ্রু\n\nrequest-response এপিআইতে অ্যাপ সাধারণত এমনভাবে চলে যেন কথোপকথনটি বারবার চেক করতে হবে।\n\nকর্মী Submit ট্যাপ করে। সার্ভার একটি রিইম্বার্সমেন্ট রেকর্ড তৈরি করে স্ট্যাটাস “Pending approval” এবং একটি আইডি ফেরত দেয়। ম্যানেজার নোটিফিকেশন পায়, কিন্তু কর্মীর অ্যাপ সাধারণত পরিবর্তন দেখার জন্য পোলিং করে, উদাহরণ: “GET reimbursement status by ID।”\n\n৪৮ ঘণ্টার ডেডলাইন রক্ষা করতে, আপনি হয়ত একটি শিডিউলড জব চালান যা ওভারডিউ রিকোয়েস্ট স্ক্যান করে, বা একটি ডেডলাইন টাইমস্ট্যাম্প সংরক্ষণ করে এবং পোলগুলিতে চেক করেন। যদি জব দেরি করে, ব্যবহারকারীরা স্টেইল স্ট্যাটাস দেখতে পায়।\n\nযখন ম্যানেজার অনুমোদন করেন, সার্ভার স্ট্যাটাস “Approved” এ ফ্লিপ করে এবং পেমেন্ট প্রোভাইডারে কল করে। যদি Stripe সাময়িক ত্রুটি ফেরত দেয়, সার্ভার সিদ্ধান্ত নেবে এখন রিট্রাই করবে, পরে রিট্রাই নির্ধারণ করবে, না কি ফেইল করে। আদর্শভাবে আইডেম্পোটেন্সি কী না থাকলে, রিট্রাই দ্বিগুণ পেআউট তৈরি করতে পারে।\n\n### ইভেন্ট-ড্রিভেন ওয়াকথ্রু\n\nইভেন্ট-ড্রিভেন মডেলে প্রতিটি পরিবর্তন একটি রেকর্ডেড ফ্যাক্ট।\n\nকর্মী Submit করে, একটি “ExpenseSubmitted” ইভেন্ট তৈরি হয়। একটি ওয়ার্কফ্লো শুরু হয় এবং অপেক্ষা করে বা “ManagerApproved” বা ৪৮ ঘণ্টার টায়মার ইভেন্ট “DeadlineReached” এ এসে যায়। যদি টাইমার আগে ফায়ার করে, ওয়ার্কফ্লো “AutoRejected” ও কারণ রেকর্ড করে।\n\nঅনুমোদন এলে ওয়ার্কফ্লো “PayoutRequested” রেকর্ড করে এবং পেমেন্ট চেষ্টা করে। যদি Stripe টাইমআউট করে, এটি “PayoutFailed” সহ একটি ত্রুটি কোড রেকর্ড করে, ১৫ মিনিট পরে রিট্রাই শিডিউল করে, এবং আইডেম্পোটেন্সি কী ব্যবহার করে কেবল একবার “PayoutSucceeded” রেকর্ড করে।\n\nব্যবহারকারী যা দেখে সেটা সরল থাকে:\n\n- Pending approval (৪৮ ঘন্টা বাকি)\n- Approved, পেমেন্ট চলছে\n- পেমেন্ট রিট্রাই নির্ধারিত\n- Paid\n\nঅডিট ট্রেইল টাইমলাইনের মতো পড়ে: submitted, approved, deadline checked, payout attempted, failed, retried, paid।\n\n## পরবর্তী ধাপ: মডেলটিকে কার্যকর অ্যাপে পরিণত করা\n\nএকটি বাস্তব প্রসেস বেছে নিয়ে এটি এন্ড-টু-এন্ড নির্মাণ করুন আগে আপনি এটি সাধারণীকরণ করুন। খরচ অনুমোদন, অনবোর্ডিং, এবং রিফান্ড হ্যান্ডলিং ভালো স্টার্টার কারণ এগুলোতে মানব ধাপ, অপেক্ষা এবং ব্যর্থতা পথ আছে। লক্ষ্য ছোট রাখুন: একটি প্রধান পাথ এবং সবচেয়ে সাধারণ দুটো ব্যতিক্রম অন্তর্ভুক্ত করুন।\n\nপ্রসেসটিকে স্টেট ও ইভেন্ট হিসেবে লিখুন, স্ক্রিন হিসেবে নয়। উদাহরণ: “Submitted” -> “ManagerApproved” -> “PaymentRequested” -> “Paid,” শাখাগুলো যেমন “ApprovalRejected” বা “PaymentFailed।” যখন আপনি অপেক্ষার পয়েন্ট ও সাইড-ইফেক্টগুলো স্পষ্টভাবে দেখেন, তখন ঘটনাভিত্তিক ওয়ার্কফ্লো বনাম request-response API নির্বাচন বাস্তবসম্মত হয়।\n\nপ্রসেস স্টেট কোথায় থাকবে তা সিদ্ধান্ত নিন। যদি ফ্লো সহজ হয় এবং আপনি সব আপডেট এক জায়গায় প্রয়োগ করতে পারেন, একটি ডাটাবেস পর্যাপ্ত হতে পারে। যখন টাইমার, রিট্রাই ও ব্রাঞ্চিং দরকার, একটি ওয়ার্কফ্লো ইঞ্জিন সহায়তা করে কারণ এটি পরবর্তী কি হওয়া উচিত তা ট্র্যাক করে।\n\nপ্রথম দিন থেকেই অডিট ফিল্ড যোগ করুন। কে কী করেছে, কখন, এবং কেন (মন্তব্য বা কারণ কোড) সংরক্ষণ করুন। যখন কেউ জিজ্ঞেস করে, “কেন এই পেমেন্ট রিট্রাই করা হল?” আপনি লোগ খুঁটিয়ে না দেখে স্পষ্ট উত্তর দিতে পারবেন।\n\nযদি আপনি এই ধরনের ওয়ার্কফ্লো কোনো নো‑কোড প্ল্যাটফর্মে বানাচ্ছেন, AppMaster (appmaster.io) একটি অপশন যেখানে আপনি PostgreSQL-এ ডেটা মডেল করে ভিজ্যুয়ালভাবে প্রসেস লজিক তৈরি করতে পারেন, যা ওয়েব ও মোবাইল অ্যাপ জুড়ে অনুমোদন ও অডিট ট্রেইল ধারাবাহিক রাখতে সাহায্য করে।
প্রশ্নোত্তর
রিকোয়েস্ট-রেসপন্স ব্যবহার করুন যখন কাজটি দ্রুত এবং পূর্বানুমানযোগ্যভাবে শেষ হয়—উদাহরণ: একটি রেকর্ড তৈরি করা বা একটি ফর্ম যাচাইকরণ। ইভেন্ট-ড্রিভেন ওয়ার্কফ্লো ব্যবহার করুন যখন প্রসেস মিনিট থেকে দিন পর্যন্ত বিস্তৃত হয়, মানব অনুমোদন থাকে, বা টাইমার, রিট্রাই ও নিরাপদ রিস্যুম প্রয়োজন।
দীর্ঘকালীন কাজগুলো একটি একক HTTP রিকোয়েস্টে ফিট করে না কারণ কানেকশন টাইমআউট হয়, সার্ভার রিস্টার্ট হতে পারে, এবং কাজ প্রায়ই মানুষ বা বাইরের সিস্টেমের উপর নির্ভরশীল। যদি আপনি এটি একটি কল হিসেবে আচরণ করেন, তো আপনি সাধারণত স্টেট হারান, রিট্রাইতে ডুপ্লিকেশন পান, এবং অপেক্ষার জন্য ছড়ানো ব্যাকগ্রাউন্ড স্ক্রিপ্ট তৈরি করেন।
একটি সাধারণ পদ্ধতি হলো আপনার প্রসেস স্টেট ডাটাবেসে সংরক্ষণ করা এবং এটিকে কেবল স্পষ্ট ট্রানজিশনগুলোর মাধ্যমে এগিয়ে নেওয়া। প্রসেস ইনস্ট্যান্স আইডি, বর্তমান স্ট্যাটাস, পরবর্তী কে কাজ করবে এবং গুরুত্বপূর্ণ টাইমস্ট্যাম্পগুলো সংরক্ষণ করুন যাতে ডিপ্লয়, ক্র্যাশ বা বিলম্বের পরে নিরাপদে রিস্যাম করা যায়।
ব্লক করে রাখা বা ধারাবাহিকভাবে পোলিংয়ের বদলে, অনুমোদনকে একটি paus করা ধাপ হিসেবে মডেল করুন যা সিদ্ধান্ত এলে পুনরায় চালু হয়। প্রতিটি সিদ্ধান্তকে ডেটা হিসেবে রেকর্ড করুন (কে সিদ্ধান্ত নিয়েছে, কখন, অনুমোদন/প্রত্যাখ্যান ও কারণ) যাতে ওয়ার্কফ্লো পূর্বানুমানযোগ্যভাবে এগোয় এবং পরে অডিট করা যায়।
পোলিং সহজ কেসে কাজ করতে পারে, তবে এটি শব্দ বাড়ায় এবং বিলম্ব যোগ করে কারণ ক্লায়েন্ট বারবার 'হয়েছে কি?' জিজ্ঞেস করে। ভালো ডিফল্ট হলো: পরিবর্তনে সার্ভার থেকে নোটিফিকেশন পাঠানো এবং ক্লায়েন্ট চাহিদামতো রিফ্রেশ করা—তবে সার্ভারই স্টেটের একমাত্র উৎস হওয়া উচিত।
টাইমকে প্রসেসের অংশ হিসেবে বিবেচনা করুন: ডেডলাইন ও রিমাইন্ডার টাইমগুলো সংরক্ষণ করুন, এবং টায়মার ফায়ার হলে বর্তমান স্টেট পুনরায় যাচাই করে তারপর কাজ করুন। এভাবে আপনি এমন রিমাইন্ডার প্রতিরোধ করবেন যেগুলো আগে থেকেই অনুমোদিত আইটেমে পাঠানো হচ্ছে, এবং এসকেলেশনগুলো কনসিস্টেন্ট থাকবে এমনকি যদি জবগুলো দেরি করে বা একাধিকবার চালানো হয়।
পেমেন্ট বা ইমেল পাঠানোর মতো সাইড-ইফেক্টের জন্য প্রতিটি অনুক্রমগত কাজের জন্য idempotency কী ব্যবহার করুন এবং সেই কী-র জন্য আউটকাম সংরক্ষণ করুন। এতে রিট্রাই করলে একই ইচ্ছাকে পুনরায় চালানো হলে একই ফলাফল ফিরে দেয় এবং পুনরায় কার্যসম্পাদন করে না।
ইভেন্টসকে একাধিকবার ডেলিভারি করা হতে পারে বলে ধরে নিন এবং কনজিউমারগুলোকে ডুপ্লিকেট থেকে বাঁচাতে ডিজাইন করুন। একটি বাস্তবসম্মত পদ্ধতি হলো ইভেন্ট আইডি (বা ধাপের জন্য ব্যবসায়িক কী) সংরক্ষণ করা এবং পুনরাবৃত্তি হলে উপেক্ষা করা—এতে রেপ্লে একই অ্যাকশন পুনরায় ট্রিগার করবে না।
দীর্ঘ-চলমান ওয়ার্কফ্লোর জন্য একটি অডিট ট্রেল এমন তথ্য রাখুক যাতে পুরো গল্পটি রেপ্লে করা যায়: অ্যাক্টর (কে করলো), টাইমস্ট্যাম্প (কখন), তখন জানা ইনপুট, আউটপুট/ফলাফল, এবং কোন রুল/পলিসি ভার্সন ব্যবহার করা হয়েছে। সবকিছুর সাথে একটি সিংগেল কেস বা কোরিলেশন আইডি লাগান যাতে সাপোর্ট সহজে বলতে পারে 'এটি কোন ধাপে আটকা আছে'।
একটি অনুরোধ রেকর্ডকে 'কেস' হিসেবে রাখুন, সিদ্ধান্তগুলো আলাদা করে সংরক্ষণ করুন, এবং স্টেট পরিবর্তনগুলোকে পERSIST করা ট্রানজিশনগুলোর মাধ্যমে ড্রাইভ করুন যাতে পুনরায় খেলা (replay) করা যায়। কোনো-কোড টুলে (যেমন AppMaster) PostgreSQL-এ ডেটা মডেল করে ভিজ্যুয়ালভাবে লজিক নির্মাণ করলে অনুমোদন, রিট্রাই ও অডিট ফিল্ডগুলো কনসিস্টেন্ট রাখাটা সহজ হয়।


