<?xml version="1.0" encoding="UTF-8"?><rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>Rafe Uddaraj, articles in Bangla</title><description>Deep dives into how software systems work: databases, distributed systems, and architecture.</description><link>https://www.rafeuddaraj.me/</link><language>bn</language><item><title>Engineering Roadmap: Why &apos;Exactly Once&apos; Delivery Is Mostly a Lie</title><link>https://www.rafeuddaraj.me/bn/blog/exactly-once-delivery-myth-distributed-systems/</link><guid isPermaLink="true">https://www.rafeuddaraj.me/bn/blog/exactly-once-delivery-myth-distributed-systems/</guid><description>ডিস্ট্রিবিউটেড সিস্টেমে নেটওয়ার্ক লেভেলে এক্স্যাক্টলি-ওয়ানস ডেলিভারি কেন গাণিতিকভাবে অসম্ভব, এবং আইডেমপোটেন্সি, ট্রানজেকশনাল আউটবক্স ও ইনবক্স প্যাটার্ন দিয়ে কীভাবে প্রোডাকশনে ইফেক্টিভলি-ওয়ানস আর্কিটেকচার বানাবেন তার কমপ্লিট ইঞ্জিনিয়ারিং গাইড।</description><pubDate>Tue, 08 Sep 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;শুরুতেই একটি বাস্তব production incident কল্পনা করুন। ধরুন আপনি একটি ই-কমার্স প্ল্যাটফর্মের Payment API তৈরি করেছেন। ইউজার যখন চেকআউট বাটনে ক্লিক করে, আপনার Payment Service সেই রিকোয়েস্টটি প্রসেস করে Stripe বা PayPal-এর মতো পেমেন্ট গেটওয়েতে পাঠায়। সিস্টেম ডিজাইন রিভিউয়ের সময় কোড ও ফ্লো একদম নিখুঁত মনে হচ্ছিল।&lt;/p&gt;
&lt;p&gt;একদিন রাত ৩টায় আপনার PagerDuty-তে অ্যালার্ট বাজল। কাস্টমার সাপোর্ট থেকে জানানো হলো, শত শত ইউজারের ব্যাংক কার্ড থেকে একই অর্ডারের জন্য দুইবার করে টাকা কেটে নেওয়া হয়েছে।&lt;/p&gt;
&lt;p&gt;আপনি প্রোডাকশন লগ ওপেন করে ইনভেস্টিগেট করে দেখলেন পর্দার আড়ালে ঠিক কী ঘটেছিল:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;আপনার Payment Service পেমেন্ট গেটওয়েতে HTTP POST রিকোয়েস্ট পাঠাল: &lt;code&gt;Charge $100&lt;/code&gt;।&lt;/li&gt;
&lt;li&gt;পেমেন্ট গেটওয়ে ইউজারের কার্ড থেকে &lt;code&gt;$100&lt;/code&gt; চার্জ করে সফলভাবে ট্রানজেকশন সম্পন্ন করল।&lt;/li&gt;
&lt;li&gt;গেটওয়ে থেকে আপনার সার্ভারে &lt;code&gt;200 OK&lt;/code&gt; রেসপন্স প্যাকেট ফেরত আসার ঠিক এক মিলি-সেকেন্ড আগে মাঝপথের নেটওয়ার্ক কানেকশন ড্রপ করল এবং আপনার সার্ভার পেল একটি &lt;code&gt;TCP Socket Timeout&lt;/code&gt;।&lt;/li&gt;
&lt;li&gt;আপনার Payment Service-এর দৃষ্টিকোণ থেকে সে কোনোভাবেই জানে না টাকা আসলে কেটেছে নাকি রিকোয়েস্টটি গেটওয়ে পর্যন্ত পৌঁছায়ইনি।&lt;/li&gt;
&lt;li&gt;আপনার অ্যাপ্লিকেশনকে ফল্ট-টল্যারেন্ট বানানোর জন্য একটি সাধারণ &lt;code&gt;Retry Mechanism&lt;/code&gt; যুক্ত করা ছিল। নেটওয়ার্ক টাইমআউট দেখে সার্ভিসটি সাথে সাথে আরেকটি Retry রিকোয়েস্ট পাঠাল।&lt;/li&gt;
&lt;li&gt;পেমেন্ট গেটওয়ে দ্বিতীয় রিকোয়েস্টটি পেয়ে ইউজারের কার্ড থেকে আবার &lt;code&gt;$100&lt;/code&gt; চার্জ করে নিল।&lt;/li&gt;
&lt;/ol&gt;
&lt;figure&gt;&lt;img src=&quot;https://raw.githubusercontent.com/rafeuddaraj/rafes-blog-assets/refs/heads/exactly-once-delivery-myth-distributed-systems/assets/payment-double-charge.svg&quot; alt=&quot;Double Charge Production Incident&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;800&quot; height=&quot;350&quot;&gt;&lt;figcaption&gt;Double Charge Production Incident&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;একজন ইউজারের একাউন্ট থেকে &lt;code&gt;$100&lt;/code&gt;-এর বদলে &lt;code&gt;$200&lt;/code&gt; কেটে নেওয়া হলো। এটাই হলো Distributed System-এ &lt;strong&gt;Exactly-Once Delivery&lt;/strong&gt;-র আসল সংকট।&lt;/p&gt;
&lt;p&gt;ডিস্ট্রিবিউটেড আর্কিটেকচারে &quot;Exactly-Once&quot; গ্যারান্টি শুনতে খুব আকর্ষণীয় ও সরল মনে হলেও, বাস্তব নেটওয়ার্ক ফিজিক্সে এটি অর্জন করা গাণিতিকভাবে অসম্ভব। মনোলিথ থেকে মাইক্রোসার্ভিসে শিফট করার পর ইঞ্জিনিয়াররা সবচেয়ে বড় ভুল করেন নেটওয়ার্কের রিলায়েবিলিটিকে শতভাগ নিশ্চিত ধরে নিয়ে।&lt;/p&gt;
&lt;p&gt;আজকের এই ডিপ ডাইভে আমরা ডিস্ট্রিবিউটেড সিস্টেমের লো-লেভেল মেকানিক্সে ঢুকব। আমরা দেখব কেন নেটওয়ার্ক লেয়ারে Exactly-Once নিশ্চিত করা অসম্ভব, এবং কীভাবে সিনিয়র ইঞ্জিনিয়াররা ডাটাবেজ ও অ্যাপ্লিকেশন লেয়ারে &lt;strong&gt;Idempotency&lt;/strong&gt;, &lt;strong&gt;Transactional Outbox&lt;/strong&gt;, এবং &lt;strong&gt;Inbox Pattern&lt;/strong&gt; ব্যবহার করে প্রোডাকশনে &lt;strong&gt;Effectively-Once&lt;/strong&gt; আর্কিটেকচার তৈরি করেন।&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;network-uncertainty-এবং-the-lost-ack-problem&quot;&gt;Network Uncertainty এবং The Lost ACK Problem&lt;/h2&gt;
&lt;p&gt;ডিস্ট্রিবিউটেড সিস্টেমের মৌলিক অনিশ্চয়তা বুঝতে হলে প্রথমে নেটওয়ার্ক লেয়ারের লিমিটেশন বুঝতে হবে। যখন দুটি স্বাধীন সার্ভার বা নোড নেটওয়ার্কের মাধ্যমে যোগাযোগ করে, তখন মাঝখানের নেটওয়ার্ক ক্যাবল, সুইচ ও রাউটার হলো পুরো সিস্টেমের সবচেয়ে আনরিলায়েবল কম্পোনেন্ট।&lt;/p&gt;
&lt;p&gt;কম্পিউটার সায়েন্সের একটি ক্লাসিক থিওরেম হলো &lt;strong&gt;Two Generals&apos; Problem&lt;/strong&gt;। এটি গাণিতিকভাবে প্রমাণ করে যে, একটি অনির্ভরযোগ্য কমিউনিকেশন চ্যানেলের ওপর দাঁড়িয়ে দুটি আলাদা নোড কখনোই কোনো বিষয়ে ১০০% নিশ্চয়তায় একমত হতে পারে না।&lt;/p&gt;
&lt;p&gt;Sender যখন কোনো Message বা Request পাঠায়, তখন তার দৃষ্টিকোণ থেকে তিনটি সম্ভাবনার যেকোনো একটি ঘটতে পারে:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Request Lost:&lt;/strong&gt; রিকোয়েস্ট মাঝপথে হারিয়ে গেছে (প্যাকেট লস বা রাউটার ড্রপ)। সার্ভার কিছুই পায়নি।&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Server Crashed Pre-Execution:&lt;/strong&gt; সার্ভার রিকোয়েস্ট পেয়েছে কিন্তু প্রসেস করার আগেই মেমোরি ক্র্যাশ বা পাওয়ার অফ হয়ে গেছে।&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Execution Succeeded but ACK Lost:&lt;/strong&gt; সার্ভার রিকোয়েস্ট পেয়েছে, ডাটাবেজে সেভ করেছে, কিন্তু তার পাঠানো কনফার্মেশন বা ACK (Acknowledgement) প্যাকেট মাঝপথে নেটওয়ার্ক ড্রপের কারণে সেন্ডারের কাছে পৌঁছায়নি।&lt;/li&gt;
&lt;/ol&gt;
&lt;figure&gt;&lt;img src=&quot;https://raw.githubusercontent.com/rafeuddaraj/rafes-blog-assets/refs/heads/exactly-once-delivery-myth-distributed-systems/assets/network-lost-ack.svg&quot; alt=&quot;The Lost ACK Problem&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;800&quot; height=&quot;300&quot;&gt;&lt;figcaption&gt;The Lost ACK Problem&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;সবচেয়ে বড় সমস্যা হলো, Sender যখন একটি &lt;code&gt;Timeout Error&lt;/code&gt; পায়, সে কোনোভাবেই জানতে পারে না ১, ২, এবং ৩ নম্বর ঘটনার মধ্যে ঠিক কোনটি ঘটেছে।&lt;/p&gt;
&lt;p&gt;সেন্ডার যদি ধরে নেয় &quot;কাজ হয়নি&quot; এবং আবার রিকোয়েস্ট পাঠায়, তবে ৩ নম্বর ক্ষেত্রে ডুপ্লিকেট অপারেশন ঘটে যায়। আবার সেন্ডার যদি ধরে নেয় &quot;কাজ হয়ে গেছে&quot;, তবে ১ ও ২ নম্বর ক্ষেত্রে চিরতরে ডাটা লস হয়।&lt;/p&gt;
&lt;div class=&quot;callout&quot; role=&quot;note&quot; data-type=&quot;note&quot;&gt;
&lt;p class=&quot;callout-title&quot;&gt;ডাকঘরের চিঠির অ্যানালজি&lt;/p&gt;
&lt;p&gt;আপনি যদি ডাকযোগে কাউকে একটি গুরুত্বপূর্ণ চিঠি পাঠান এবং কোনো ফিরতি উত্তর না পান, তবে আপনি নিশ্চিত হতে পারবেন না যে চিঠিটি হারিয়ে গেছে, নাকি প্রাপক চিঠিটি ঠিকই পেয়েছেন কিন্তু রিপ্লাই দিতে ভুলে গেছেন। ডিস্ট্রিবিউটেড সিস্টেমের ACK ড্রপ ঠিক এইভাবেই কাজ করে। সেন্ডার বাধ্য হয়ে দ্বিতীয় চিঠি পাঠায়।&lt;/p&gt;
&lt;/div&gt;
&lt;hr&gt;
&lt;h2 id=&quot;three-delivery-semantics-at-most-once-at-least-once-exactly-once&quot;&gt;Three Delivery Semantics: At-Most-Once, At-Least-Once, Exactly-Once&lt;/h2&gt;
&lt;p&gt;নেটওয়ার্কের এই অনিশ্চয়তা সামাল দিতে ইন্ডাস্ট্রিতে মেসেজ ডেলিভারিকে তিনটি ক্যাটাগরিতে ভাগ করা হয়:&lt;/p&gt;
&lt;figure&gt;&lt;img src=&quot;https://raw.githubusercontent.com/rafeuddaraj/rafes-blog-assets/refs/heads/exactly-once-delivery-myth-distributed-systems/assets/delivery-semantics.svg&quot; alt=&quot;Delivery Semantics Comparison&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;800&quot; height=&quot;350&quot;&gt;&lt;figcaption&gt;Delivery Semantics Comparison&lt;/figcaption&gt;&lt;/figure&gt;
&lt;h3 id=&quot;১-at-most-once-০-বা-১-বার-ডেলিভারি&quot;&gt;১. At-Most-Once (০ বা ১ বার ডেলিভারি)&lt;/h3&gt;
&lt;p&gt;এই মডেলে কোনো ফেইলর হলে কোনোভাবেই Retry করা হয় না (Fire and Forget)।&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;সুবিধা:&lt;/strong&gt; সিস্টেমে কখনোই ডুপ্লিকেট ডাটা তৈরি হবে না।&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;ঝুঁকি:&lt;/strong&gt; নেটওয়ার্কে যেকোনো গ্লিচ হলে মেসেজ চিরতরে হারিয়ে যাবে (High Data Loss)।&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;ব্যবহার:&lt;/strong&gt; লগিং, রিয়েল-টাইম মেট্রিক্স বা IoT সেন্সর ডেটা, যেখানে প্রতি সেকেন্ডে লাখ লাখ ডাটা আসে এবং দু-একটা ডাটা হারালে ব্যবসার কোনো ক্ষতি নেই।&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;২-at-least-once-১-বা-একাধিক-বার-ডেলিভারি&quot;&gt;২. At-Least-Once (১ বা একাধিক বার ডেলিভারি)&lt;/h3&gt;
&lt;p&gt;এই মডেলে মেসেজ পাঠানোর পর যদি নির্দিষ্ট সময়ে ACK না আসে, তবে সেন্ডার বারবার Retry করতে থাকে যতক্ষণ না কনফার্মেশন পায়।&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;সুবিধা:&lt;/strong&gt; মেসেজ হারানোর সম্ভাবনা শূন্য (Zero Data Loss)।&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;ঝুঁকি:&lt;/strong&gt; নেটওয়ার্কে ACK ড্রপ হলে কনজিউমার একই মেসেজ একাধিকবার রিসিভ করবে (Guaranteed Duplicates)।&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;ব্যবহার:&lt;/strong&gt; ফিন্যান্সিয়াল লেজার, অর্ডার প্রসেসিং এবং এন্টারপ্রাইজ মেসেজ কিউ (RabbitMQ, SQS, Kafka default)।&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;৩-exactly-once-ঠিক-১-বার-ডেলিভারি&quot;&gt;৩. Exactly-Once (ঠিক ১ বার ডেলিভারি)&lt;/h3&gt;
&lt;p&gt;এটি হলো ইঞ্জিনিয়ারদের বহু আকাঙ্খিত স্বপ্ন, যেখানে মেসেজ ঠিক একবারই ট্রাভেল করবে এবং একবারই প্রসেস হবে। কিন্তু নেটওয়ার্ক ফিজিক্সের বাস্তবতায় পিওর নেটওয়ার্ক লেভেলে এটি অসম্ভব। তবে অ্যাপ্লিকেশন ও ডাটাবেজ লেয়ারের সমন্বয়ে আমরা এটিকে &lt;strong&gt;Effectively-Once&lt;/strong&gt; আকারে সিমুলেট করতে পারি।&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;the-core-misconception-delivery-বনাম-processing&quot;&gt;The Core Misconception: Delivery বনাম Processing&lt;/h2&gt;
&lt;p&gt;সফটওয়্যার ইঞ্জিনিয়ারদের একটি বড় ভুল ধারণা হলো তারা মনে করেন &quot;Message Delivery&quot; এবং &quot;Message Processing&quot; একই বিষয়।&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Delivery (Network Layer):&lt;/strong&gt; মেসেজটি ব্রোকার বা সেন্ডার থেকে রিসিভারের নেটওয়ার্ক সকেটে পৌঁছানো।&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Processing (Application Layer):&lt;/strong&gt; মেসেজের ভেতরের পেলোড পড়ে বিজনেস কোড এক্সিকিউট করা।&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Side Effect (Storage / Third-party Layer):&lt;/strong&gt; ডাটাবেজে ব্যালেন্স আপডেট করা, ফাইল রাইট করা, কিংবা Stripe বা Twilio-তে API কল পাঠানো।&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;নেটওয়ার্ক লেভেলে ডুপ্লিকেট মেসেজ ডেলিভারি হওয়া আপনি কখনোই শতভাগ আটকাতে পারবেন না। কিন্তু আপনার অ্যাপ্লিকেশন লজিক যদি এমন হয় যে একই মেসেজ দশবার আসলেও বিজনেস সাইড-ইফেক্ট ঠিক একবারই ঘটবে, তবে ইউজারের দৃষ্টিকোণ থেকে পুরো সিস্টেমটি &lt;strong&gt;Effectively-Once&lt;/strong&gt; হিসেবে কাজ করবে।&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;আসল-শত্রু-duplicate-message-নয়-duplicate-side-effect&quot;&gt;আসল শত্রু Duplicate Message নয়, Duplicate Side Effect&lt;/h2&gt;
&lt;p&gt;একটি ডিস্ট্রিবিউটেড সিস্টেমে ডুপ্লিকেট মেসেজ আসা কোনো সমস্যা নয়। আসল সমস্যা তৈরি হয় যখন ডুপ্লিকেট মেসেজের কারণে সিস্টেমে &lt;strong&gt;Duplicate Side Effect&lt;/strong&gt; ঘটে।&lt;/p&gt;
&lt;figure&gt;&lt;img src=&quot;https://raw.githubusercontent.com/rafeuddaraj/rafes-blog-assets/refs/heads/exactly-once-delivery-myth-distributed-systems/assets/duplicate-side-effects.svg&quot; alt=&quot;The Real Enemy: Duplicate Side Effects&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;800&quot; height=&quot;400&quot;&gt;&lt;figcaption&gt;The Real Enemy: Duplicate Side Effects&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;যদি একটি পেমেন্ট মেসেজ দুইবার প্রসেস হওয়ার কারণে:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;ইউজারের ক্রেডিট কার্ডে দুইবার চার্জ হয় (&lt;code&gt;Charge Card x2&lt;/code&gt;),&lt;/li&gt;
&lt;li&gt;ইনভেন্টরি থেকে দুইবার স্টক মাইনাস হয় (&lt;code&gt;Reduce Stock x2&lt;/code&gt;),&lt;/li&gt;
&lt;li&gt;ডাটাবেজে দুটি আলাদা অর্ডার তৈরি হয় (&lt;code&gt;Create Order x2&lt;/code&gt;),&lt;/li&gt;
&lt;li&gt;ইউজারের কাছে দুটি কনফার্মেশন ইমেইল চলে যায়,&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;তখন পুরো সিস্টেমের স্টেট করাপ্ট হয়ে যায়। আমাদের আর্কিটেকচারাল লক্ষ্য হলো ডুপ্লিকেট মেসেজ আসবেই, কিন্তু প্রতিটি সাইড-ইফেক্টকে সেফগার্ড করতে হবে।&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;idempotency-the-practical-escape-hatch&quot;&gt;Idempotency: The Practical Escape Hatch&lt;/h2&gt;
&lt;p&gt;ডুপ্লিকেট সাইড-ইফেক্ট থেকে বাঁচার সবচেয়ে শক্তিশালী হাতিয়ার হলো &lt;strong&gt;Idempotency (আইডেমপোটেন্সি)&lt;/strong&gt;।&lt;/p&gt;
&lt;p&gt;গণিত ও কম্পিউটার সায়েন্সে একটি অপারেশনকে Idempotent বলা হয় যদি সেই অপারেশনটি একবার চালানোর ফলাফল আর একশোবার চালানোর ফলাফল সম্পূর্ণ একই থাকে (&lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:1em;vertical-align:-0.25em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.1076em;&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;mopen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.1076em;&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;mopen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;mclose&quot;&gt;))&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mrel&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:1em;vertical-align:-0.25em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.1076em;&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;mopen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;mclose&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;)।&lt;/p&gt;
&lt;figure&gt;&lt;img src=&quot;https://raw.githubusercontent.com/rafeuddaraj/rafes-blog-assets/refs/heads/exactly-once-delivery-myth-distributed-systems/assets/idempotency-flow.svg&quot; alt=&quot;Idempotency Flow Architecture&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;800&quot; height=&quot;400&quot;&gt;&lt;figcaption&gt;Idempotency Flow Architecture&lt;/figcaption&gt;&lt;/figure&gt;
&lt;h3 id=&quot;idempotency-key-কীভাবে-কাজ-করে&quot;&gt;Idempotency Key কীভাবে কাজ করে:&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;ক্লায়েন্ট যখন কোনো গুরুত্বপূর্ণ রিকোয়েস্ট তৈরি করে, সে একটি গ্লোবালি ইউনিক আইডি তৈরি করে হেডারে পাঠিয়ে দেয় (যেমন: &lt;code&gt;Idempotency-Key: 9b1deb4d-3b7d-4bad-9bdd-2b0d7b3dcb6d&lt;/code&gt;)।&lt;/li&gt;
&lt;li&gt;সার্ভার কোনো বিজনেস লজিক চালানোর আগে এই Key দিয়ে তার সেন্ট্রাল স্টোরে (Redis বা PostgreSQL) চেক করে।&lt;/li&gt;
&lt;li&gt;যদি Key আগে থেকেই পাওয়া যায় এবং স্ট্যাটাস &lt;code&gt;COMPLETED&lt;/code&gt; থাকে, তবে সার্ভার নতুন করে কোনো পেমেন্ট বা প্রসেসিং না করে ক্যাশড রেসপন্সটি সাথে সাথে রিটার্ন করে দেয়।&lt;/li&gt;
&lt;li&gt;যদি Key না থাকে, সার্ভার স্ট্যাটাসটিকে &lt;code&gt;IN_PROGRESS&lt;/code&gt; হিসেবে লক করে, মূল বিজনেস কাজ সম্পন্ন করে, রেসপন্স সেভ করে এবং স্ট্যাটাস &lt;code&gt;COMPLETED&lt;/code&gt; করে দেয়।&lt;/li&gt;
&lt;/ol&gt;
&lt;div class=&quot;callout&quot; role=&quot;note&quot; data-type=&quot;tip&quot;&gt;
&lt;p class=&quot;callout-title&quot;&gt;HTTP Methods ও Idempotency&lt;/p&gt;
&lt;p&gt;RESTful API ডিজাইনে &lt;code&gt;GET&lt;/code&gt;, &lt;code&gt;PUT&lt;/code&gt;, এবং &lt;code&gt;DELETE&lt;/code&gt; মেথডগুলো নিয়ম অনুযায়ী naturalmente idempotent। একটি রিসোর্স আপনি ১০ বার ডিলিট করার রিকোয়েস্ট পাঠালেও ডাটাবেজের ফাইনাল স্টেট একই থাকবে (রিসোর্সটি মুছে গেছে)। কিন্তু &lt;code&gt;POST&lt;/code&gt; মেথড স্বভাবতই idempotent নয়। তাই Payment, Transfer, বা Order তৈরির মতো ক্রিটিক্যাল &lt;code&gt;POST&lt;/code&gt; এন্ডপয়েন্টে &lt;code&gt;Idempotency-Key&lt;/code&gt; হেডার বাধ্যতামূলক করা উচিত।&lt;/p&gt;
&lt;/div&gt;
&lt;hr&gt;
&lt;h2 id=&quot;database-unique-constraint-ও-check-then-insert-trap&quot;&gt;Database Unique Constraint ও Check-Then-Insert Trap&lt;/h2&gt;
&lt;p&gt;অনেকে অ্যাপ্লিকেশনের মেমোরিতে সাধারণ &lt;code&gt;if (!exists)&lt;/code&gt; চেক দিয়ে আইডেমপোটেন্সি বানানোর চেষ্টা করেন:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;style&gt;.expressive-code{font-family:var(--ec-uiFontFml);font-size:var(--ec-uiFontSize);font-weight:var(--ec-uiFontWg);line-height:var(--ec-uiLineHt);text-size-adjust:none;-webkit-text-size-adjust:none}.expressive-code *:not(:is(svg, svg *)){all:revert;box-sizing:border-box}.expressive-code pre{display:flex;margin:0;padding:0;border:var(--ec-brdWd) solid var(--ec-brdCol);border-radius:calc(var(--ec-brdRad) + var(--ec-brdWd));background:var(--ec-codeBg)}.expressive-code pre:focus-visible{outline:3px solid var(--ec-focusBrd);outline-offset:-3px}.expressive-code pre &gt; code{all:unset;display:block;flex:1 0 100%;padding:var(--ec-codePadBlk) 0;color:var(--ec-codeFg);font-family:var(--ec-codeFontFml);font-size:var(--ec-codeFontSize);font-weight:var(--ec-codeFontWg);line-height:var(--ec-codeLineHt)}.expressive-code pre{overflow-x:auto}.expressive-code pre.wrap .ec-line .code{white-space:pre-wrap;overflow-wrap:break-word;min-width:min(20ch, var(--ecMaxLine, 20ch))}.expressive-code pre.wrap .ec-line .code span.indent{white-space:pre}.expressive-code pre::-webkit-scrollbar,.expressive-code pre::-webkit-scrollbar-track{background-color:inherit;border-radius:calc(var(--ec-brdRad) + var(--ec-brdWd));border-top-left-radius:0;border-top-right-radius:0}.expressive-code pre::-webkit-scrollbar-thumb{background-color:var(--ec-sbThumbCol);border:4px solid transparent;background-clip:content-box;border-radius:10px}.expressive-code pre::-webkit-scrollbar-thumb:hover{background-color:var(--ec-sbThumbHoverCol)}.expressive-code pre::-webkit-scrollbar-corner{background:transparent}.expressive-code .ec-line{direction:ltr;unicode-bidi:isolate;display:grid;grid-template-areas:&apos;gutter code&apos;;grid-template-columns:auto 1fr;position:relative}.expressive-code .ec-line .gutter{grid-area:gutter;color:var(--ec-gtrFg)}.expressive-code .ec-line .gutter &gt; *{pointer-events:none;user-select:none;-webkit-user-select:none}.expressive-code .ec-line .gutter ~ .code{--ecLineBrdCol:var(--ec-gtrBrdCol)}.expressive-code .ec-line.highlight .gutter{color:var(--ec-gtrHlFg)}.expressive-code .ec-line .code{grid-area:code;position:relative;box-sizing:content-box;padding-inline-start:calc(var(--ecIndent, 0ch) + var(--ec-codePadInl) - var(--ecGtrBrdWd));padding-inline-end:var(--ec-codePadInl);text-indent:calc(var(--ecIndent, 0ch) * -1)}.expressive-code .ec-line .code::before,.expressive-code .ec-line .code::after,.expressive-code .ec-line .code :where(*){text-indent:0}.expressive-code .ec-line .code{--ecGtrBrdWd:var(--ec-gtrBrdWd);border-inline-start:var(--ecGtrBrdWd) solid var(--ecLineBrdCol, transparent)}.expressive-code .sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0, 0, 0, 0);white-space:nowrap;border-width:0}.expressive-code .ec-line.mark{--tmLineBgCol:var(--ec-tm-markBg)}.expressive-code .ec-line.mark .code{--ecLineBrdCol:var(--ec-tm-markBrdCol)}.expressive-code .ec-line.ins{--tmLineBgCol:var(--ec-tm-insBg);--tmLabel:var(--ec-tm-insDiffIndContent)}.expressive-code .ec-line.ins .code{--ecLineBrdCol:var(--ec-tm-insBrdCol)}.expressive-code .ec-line.ins .code::before{color:var(--ec-tm-insDiffIndCol)}.expressive-code .ec-line.del{--tmLineBgCol:var(--ec-tm-delBg);--tmLabel:var(--ec-tm-delDiffIndContent)}.expressive-code .ec-line.del .code{--ecLineBrdCol:var(--ec-tm-delBrdCol)}.expressive-code .ec-line.del .code::before{color:var(--ec-tm-delDiffIndCol)}.expressive-code .ec-line.mark,.expressive-code .ec-line.ins,.expressive-code .ec-line.del{background:var(--tmLineBgCol)}.expressive-code .ec-line.mark .code,.expressive-code .ec-line.ins .code,.expressive-code .ec-line.del .code{--ecGtrBrdWd:var(--ec-tm-lineMarkerAccentWd)}.expressive-code .ec-line.mark .code::before,.expressive-code .ec-line.ins .code::before,.expressive-code .ec-line.del .code::before{display:block;position:absolute;left:0;box-sizing:border-box;content:var(--tmLabel, &apos; &apos;);padding-inline-start:var(--ec-tm-lineDiffIndMargLeft);text-align:center;white-space:pre}.expressive-code .ec-line.mark.tm-label .code::before,.expressive-code .ec-line.ins.tm-label .code::before,.expressive-code .ec-line.del.tm-label .code::before{background:var(--ecLineBrdCol);padding:0 calc(var(--ec-tm-lineMarkerLabelPadInl) + var(--ec-tm-lineMarkerAccentWd)) 0 var(--ec-tm-lineMarkerLabelPadInl);color:var(--ec-tm-lineMarkerLabelCol)}.expressive-code .ec-line mark{--tmInlineBgCol:var(--ec-tm-markBg);--tmInlineBrdCol:var(--ec-tm-markBrdCol)}.expressive-code .ec-line ins{--tmInlineBgCol:var(--ec-tm-insBg);--tmInlineBrdCol:var(--ec-tm-insBrdCol)}.expressive-code .ec-line del{--tmInlineBgCol:var(--ec-tm-delBg);--tmInlineBrdCol:var(--ec-tm-delBrdCol)}.expressive-code .ec-line mark,.expressive-code .ec-line ins,.expressive-code .ec-line del{all:unset;display:inline-block;position:relative;--tmBrdL:var(--ec-tm-inlMarkerBrdWd);--tmBrdR:var(--ec-tm-inlMarkerBrdWd);--tmRadL:var(--ec-tm-inlMarkerBrdRad);--tmRadR:var(--ec-tm-inlMarkerBrdRad);margin-inline:0.025rem;padding-inline:var(--ec-tm-inlMarkerPad);border-radius:var(--tmRadL) var(--tmRadR) var(--tmRadR) var(--tmRadL);background:var(--tmInlineBgCol);background-clip:padding-box}.expressive-code .ec-line mark.open-start,.expressive-code .ec-line ins.open-start,.expressive-code .ec-line del.open-start{margin-inline-start:0;padding-inline-start:0;--tmBrdL:0px;--tmRadL:0}.expressive-code .ec-line mark.open-end,.expressive-code .ec-line ins.open-end,.expressive-code .ec-line del.open-end{margin-inline-end:0;padding-inline-end:0;--tmBrdR:0px;--tmRadR:0}.expressive-code .ec-line mark::before,.expressive-code .ec-line ins::before,.expressive-code .ec-line del::before{content:&apos;&apos;;position:absolute;pointer-events:none;display:inline-block;inset:0;border-radius:var(--tmRadL) var(--tmRadR) var(--tmRadR) var(--tmRadL);border:var(--ec-tm-inlMarkerBrdWd) solid var(--tmInlineBrdCol);border-inline-width:var(--tmBrdL) var(--tmBrdR)}.expressive-code .frame{all:unset;position:relative;display:block;--header-border-radius:calc(var(--ec-brdRad) + var(--ec-brdWd));--tab-border-radius:calc(var(--ec-frm-edTabBrdRad) + var(--ec-brdWd));--button-spacing:0.4rem;--code-background:var(--ec-frm-edBg);border-radius:var(--header-border-radius);box-shadow:var(--ec-frm-frameBoxShdCssVal)}.expressive-code .frame .header{display:none;z-index:1;position:relative;border-radius:var(--header-border-radius) var(--header-border-radius) 0 0}.expressive-code .frame.has-title pre,.expressive-code .frame.has-title code,.expressive-code .frame.is-terminal pre,.expressive-code .frame.is-terminal code{border-top:none;border-top-left-radius:0;border-top-right-radius:0}.expressive-code .frame .title:empty:before{content:&apos;\a0&apos;}.expressive-code .frame.has-title:not(.is-terminal){--button-spacing:calc(1.9rem + 2 * (var(--ec-uiPadBlk) + var(--ec-frm-edActTabIndHt)))}.expressive-code .frame.has-title:not(.is-terminal) .title{position:relative;color:var(--ec-frm-edActTabFg);background:var(--ec-frm-edActTabBg);background-clip:padding-box;margin-block-start:var(--ec-frm-edTabsMargBlkStart);padding:calc(var(--ec-uiPadBlk) + var(--ec-frm-edActTabIndHt)) var(--ec-uiPadInl);border:var(--ec-brdWd) solid var(--ec-frm-edActTabBrdCol);border-radius:var(--tab-border-radius) var(--tab-border-radius) 0 0;border-bottom:none;overflow:hidden}.expressive-code .frame.has-title:not(.is-terminal) .title::after{content:&apos;&apos;;position:absolute;pointer-events:none;inset:0;border-top:var(--ec-frm-edActTabIndHt) solid var(--ec-frm-edActTabIndTopCol);border-bottom:var(--ec-frm-edActTabIndHt) solid var(--ec-frm-edActTabIndBtmCol)}.expressive-code .frame.has-title:not(.is-terminal) .header{display:flex;background:linear-gradient(to top, var(--ec-frm-edTabBarBrdBtmCol) var(--ec-brdWd), transparent var(--ec-brdWd)),linear-gradient(var(--ec-frm-edTabBarBg), var(--ec-frm-edTabBarBg));background-repeat:no-repeat;padding-inline-start:var(--ec-frm-edTabsMargInlStart)}.expressive-code .frame.has-title:not(.is-terminal) .header::before{content:&apos;&apos;;position:absolute;pointer-events:none;inset:0;border:var(--ec-brdWd) solid var(--ec-frm-edTabBarBrdCol);border-radius:inherit;border-bottom:none}.expressive-code .frame.is-terminal{--button-spacing:calc(1.9rem + var(--ec-brdWd) + 2 * var(--ec-uiPadBlk));--code-background:var(--ec-frm-trmBg)}.expressive-code .frame.is-terminal .header{display:flex;align-items:center;justify-content:center;padding-block:var(--ec-uiPadBlk);padding-block-end:calc(var(--ec-uiPadBlk) + var(--ec-brdWd));position:relative;font-weight:500;letter-spacing:0.025ch;color:var(--ec-frm-trmTtbFg);background:var(--ec-frm-trmTtbBg);border:var(--ec-brdWd) solid var(--ec-brdCol);border-bottom:none}.expressive-code .frame.is-terminal .header::before{content:&apos;&apos;;position:absolute;pointer-events:none;left:var(--ec-uiPadInl);width:2.1rem;height:0.56rem;line-height:0;background-color:var(--ec-frm-trmTtbDotsFg);opacity:var(--ec-frm-trmTtbDotsOpa);-webkit-mask-image:var(--ec-frm-trmIcon);-webkit-mask-repeat:no-repeat;mask-image:var(--ec-frm-trmIcon);mask-repeat:no-repeat}.expressive-code .frame.is-terminal .header::after{content:&apos;&apos;;position:absolute;pointer-events:none;inset:0;border-bottom:var(--ec-brdWd) solid var(--ec-frm-trmTtbBrdBtmCol)}.expressive-code .frame pre{background:var(--code-background)}.expressive-code .copy{display:flex;gap:0.25rem;flex-direction:row;position:absolute;inset-block-start:calc(var(--ec-brdWd) + var(--button-spacing));inset-inline-end:calc(var(--ec-brdWd) + var(--ec-uiPadInl) / 2)}@media (scripting: none){.expressive-code .copy{display:none}}.expressive-code .copy{direction:ltr;unicode-bidi:isolate}.expressive-code .copy button{position:relative;align-self:flex-end;margin:0;padding:0;border:none;border-radius:0.2rem;z-index:1;cursor:pointer;transition-property:opacity, background, border-color;transition-duration:0.2s;transition-timing-function:cubic-bezier(0.25, 0.46, 0.45, 0.94);width:2.5rem;height:2.5rem;background:var(--code-background);opacity:0.75}.expressive-code .copy button div{position:absolute;inset:0;border-radius:inherit;background:var(--ec-frm-inlBtnBg);opacity:var(--ec-frm-inlBtnBgIdleOpa);transition-property:inherit;transition-duration:inherit;transition-timing-function:inherit}.expressive-code .copy button::before{content:&apos;&apos;;position:absolute;pointer-events:none;inset:0;border-radius:inherit;border:var(--ec-brdWd) solid var(--ec-frm-inlBtnBrd);opacity:var(--ec-frm-inlBtnBrdOpa)}.expressive-code .copy button::after{content:&apos;&apos;;position:absolute;pointer-events:none;inset:0;background-color:var(--ec-frm-inlBtnFg);-webkit-mask-image:var(--ec-frm-copyIcon);-webkit-mask-repeat:no-repeat;mask-image:var(--ec-frm-copyIcon);mask-repeat:no-repeat;margin:0.475rem;line-height:0}.expressive-code .copy button:hover,.expressive-code .copy button:focus:focus-visible{opacity:1}.expressive-code .copy button:hover div,.expressive-code .copy button:focus:focus-visible div{opacity:var(--ec-frm-inlBtnBgHoverOrFocusOpa)}.expressive-code .copy button:active{opacity:1}.expressive-code .copy button:active div{opacity:var(--ec-frm-inlBtnBgActOpa)}.expressive-code .copy .feedback{--tooltip-arrow-size:0.35rem;--tooltip-bg:var(--ec-frm-tooltipSuccessBg);color:var(--ec-frm-tooltipSuccessFg);pointer-events:none;user-select:none;-webkit-user-select:none;position:relative;align-self:center;background-color:var(--tooltip-bg);z-index:99;padding:0.125rem 0.75rem;border-radius:0.2rem;margin-inline-end:var(--tooltip-arrow-size);opacity:0;transition-property:opacity, transform;transition-duration:0.2s;transition-timing-function:ease-in-out;transform:translate3d(0, 0.25rem, 0)}.expressive-code .copy .feedback::after{content:&apos;&apos;;position:absolute;pointer-events:none;top:calc(50% - var(--tooltip-arrow-size));inset-inline-end:calc(-2 * (var(--tooltip-arrow-size) - 0.5px));border:var(--tooltip-arrow-size) solid transparent;border-inline-start-color:var(--tooltip-bg)}.expressive-code .copy .feedback.show{opacity:1;transform:translate3d(0, 0, 0)}@media (hover: hover){.expressive-code{}.expressive-code .copy button{opacity:0;width:2rem;height:2rem}.expressive-code .frame:hover .copy button:not(:hover),.expressive-code .frame:focus-within :focus-visible ~ .copy button:not(:hover),.expressive-code .frame .copy .feedback.show ~ button:not(:hover){opacity:0.75}}.expressive-code :nth-child(1 of .ec-line) .code{padding-inline-end:calc(2rem + var(--ec-codePadInl))}:root{--ec-brdRad:0.75rem;--ec-brdWd:1.5px;--ec-brdCol:var(--code-line);--ec-codeFontFml:var(--font-code);--ec-codeFontSize:0.875rem;--ec-codeFontWg:400;--ec-codeLineHt:1.75;--ec-codePadBlk:1rem;--ec-codePadInl:1.125rem;--ec-codeBg:var(--code-bg);--ec-codeFg:#e6edf3;--ec-codeSelBg:#264f78;--ec-gtrFg:#6e7681;--ec-gtrBrdCol:#6e768133;--ec-gtrBrdWd:1.5px;--ec-gtrHlFg:#e6edf3;--ec-uiFontFml:var(--font-mono);--ec-uiFontSize:0.75rem;--ec-uiFontWg:400;--ec-uiLineHt:1.65;--ec-uiPadBlk:0.25rem;--ec-uiPadInl:1rem;--ec-uiSelBg:#6e768166;--ec-uiSelFg:#e6edf3;--ec-focusBrd:#1f6feb;--ec-sbThumbCol:#8b949e33;--ec-sbThumbHoverCol:#8b949e3d;--ec-tm-lineMarkerAccentMarg:0rem;--ec-tm-lineMarkerAccentWd:0.15rem;--ec-tm-lineMarkerLabelPadInl:0.2rem;--ec-tm-lineMarkerLabelCol:white;--ec-tm-lineDiffIndMargLeft:0.3rem;--ec-tm-inlMarkerBrdWd:1.5px;--ec-tm-inlMarkerBrdRad:0.2rem;--ec-tm-inlMarkerPad:0.15rem;--ec-tm-insDiffIndContent:&apos;+&apos;;--ec-tm-delDiffIndContent:&apos;-&apos;;--ec-tm-markBg:#264a8980;--ec-tm-markBrdCol:#5570b3d0;--ec-tm-insBg:#26561c80;--ec-tm-insBrdCol:#4e7e41d0;--ec-tm-insDiffIndCol:#7eb070d0;--ec-tm-delBg:#81322b80;--ec-tm-delBrdCol:#ae594fd0;--ec-tm-delDiffIndCol:#e68a7ed0;--ec-frm-shdCol:#0000005b;--ec-frm-frameBoxShdCssVal:none;--ec-frm-edActTabBg:var(--code-bg);--ec-frm-edActTabFg:var(--code-muted);--ec-frm-edActTabBrdCol:transparent;--ec-frm-edActTabIndHt:1.5px;--ec-frm-edActTabIndTopCol:transparent;--ec-frm-edActTabIndBtmCol:#0d1117;--ec-frm-edTabsMargInlStart:0;--ec-frm-edTabsMargBlkStart:0;--ec-frm-edTabBrdRad:0.75rem;--ec-frm-edTabBarBg:var(--code-bg);--ec-frm-edTabBarBrdCol:var(--code-line);--ec-frm-edTabBarBrdBtmCol:var(--code-line);--ec-frm-edBg:var(--code-bg);--ec-frm-trmTtbFg:var(--code-muted);--ec-frm-trmTtbDotsFg:var(--code-muted);--ec-frm-trmTtbDotsOpa:0.15;--ec-frm-trmTtbBg:var(--code-bg);--ec-frm-trmTtbBrdBtmCol:var(--code-line);--ec-frm-trmBg:var(--code-bg);--ec-frm-inlBtnBg:var(--code-ink);--ec-frm-inlBtnBgIdleOpa:0;--ec-frm-inlBtnBgHoverOrFocusOpa:0.2;--ec-frm-inlBtnBgActOpa:0.3;--ec-frm-inlBtnFg:var(--code-ink);--ec-frm-inlBtnBrd:var(--code-line);--ec-frm-inlBtnBrdOpa:0.4;--ec-frm-tooltipSuccessBg:var(--color-emerald);--ec-frm-tooltipSuccessFg:var(--color-bg);--ec-frm-copyIcon:url(&quot;data:image/svg+xml,%3Csvg%20xmlns%3D&apos;http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg&apos;%20viewBox%3D&apos;0%200%2024%2024&apos;%20fill%3D&apos;none&apos;%20stroke%3D&apos;black&apos;%20stroke-width%3D&apos;1.75&apos;%3E%3Cpath%20d%3D&apos;M3%2019a2%202%200%200%201-1-2V2a2%202%200%200%201%201-1h13a2%202%200%200%201%202%201&apos;%2F%3E%3Crect%20x%3D&apos;6&apos;%20y%3D&apos;5&apos;%20width%3D&apos;16&apos;%20height%3D&apos;18&apos;%20rx%3D&apos;1.5&apos;%20ry%3D&apos;1.5&apos;%2F%3E%3C%2Fsvg%3E&quot;);--ec-frm-trmIcon:url(&quot;data:image/svg+xml,%3Csvg%20xmlns%3D&apos;http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg&apos;%20viewBox%3D&apos;0%200%2060%2016&apos;%20preserveAspectRatio%3D&apos;xMidYMid%20meet&apos;%3E%3Ccircle%20cx%3D&apos;8&apos;%20cy%3D&apos;8&apos;%20r%3D&apos;8&apos;%2F%3E%3Ccircle%20cx%3D&apos;30&apos;%20cy%3D&apos;8&apos;%20r%3D&apos;8&apos;%2F%3E%3Ccircle%20cx%3D&apos;52&apos;%20cy%3D&apos;8&apos;%20r%3D&apos;8&apos;%2F%3E%3C%2Fsvg%3E&quot;)}.expressive-code .ec-line :where(span[style^=&apos;--&apos;]:not([class])){color:var(--0, inherit);background-color:var(--0bg, transparent);font-style:var(--0fs, inherit);font-weight:var(--0fw, inherit);text-decoration:var(--0td, inherit)}&lt;/style&gt;&lt;script type=&quot;module&quot; src=&quot;/_astro/ec.0vx5m.js&quot;&gt;&lt;/script&gt;&lt;figure class=&quot;frame has-title&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;JavaScript&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;javascript&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#8B949E&quot;&gt;// মারাত্মক Anti-Pattern: Check-Then-Insert Race Condition&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;existing&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;await&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; db.&lt;/span&gt;&lt;span style=&quot;--0:#D2A8FF&quot;&gt;query&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;&apos;SELECT * FROM payments WHERE idempotency_key = $1&apos;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;, [key]);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;if&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;!&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;existing.rows.&lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;length&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;) {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#8B949E&quot;&gt;// দুটি রিকোয়েস্ট একই মিলিসেকেন্ডে এলে দুজনেই এই লাইনে ঢুকে যাবে!&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;await&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D2A8FF&quot;&gt;chargeCard&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;(amount);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;await&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; db.&lt;/span&gt;&lt;span style=&quot;--0:#D2A8FF&quot;&gt;query&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;&apos;INSERT INTO payments (idempotency_key, status) VALUES ($1, $2)&apos;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;, [key, &lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;&apos;DONE&apos;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;]);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;// মারাত্মক Anti-Pattern: Check-Then-Insert Race Conditionconst existing = await db.query(&amp;#x27;SELECT * FROM payments WHERE idempotency_key = $1&amp;#x27;, [key]);if (!existing.rows.length) {  // দুটি রিকোয়েস্ট একই মিলিসেকেন্ডে এলে দুজনেই এই লাইনে ঢুকে যাবে!  await chargeCard(amount);  await db.query(&amp;#x27;INSERT INTO payments (idempotency_key, status) VALUES ($1, $2)&amp;#x27;, [key, &amp;#x27;DONE&amp;#x27;]);}&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;যদি দুটি ডুপ্লিকেট রিকোয়েস্ট একদম একই মিলিসেকেন্ডে দুটি আলাদা সার্ভার থ্রেডে পৌঁছায়, তবে Thread A এবং Thread B দুজনেই ডাটাবেজে চেক করে দেখবে &lt;code&gt;existing&lt;/code&gt; শূন্য। এরপর দুজনেই কার্ড চার্জ করবে। একে বলা হয় &lt;strong&gt;Check-Then-Insert Race Condition&lt;/strong&gt;।&lt;/p&gt;
&lt;figure&gt;&lt;img src=&quot;https://raw.githubusercontent.com/rafeuddaraj/rafes-blog-assets/refs/heads/exactly-once-delivery-myth-distributed-systems/assets/db-unique-constraint.svg&quot; alt=&quot;Database Level Unique Constraint&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;800&quot; height=&quot;400&quot;&gt;&lt;figcaption&gt;Database Level Unique Constraint&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;অ্যাপ্লিকেশন মেমোরির চেকের ওপর কখনোই কনকারেন্সি নির্ভর করা যায় না। ডাটাবেজের &lt;strong&gt;Unique Constraint&lt;/strong&gt; হলো ডিস্ট্রিবিউটেড সিস্টেমের একমাত্র অথরিটেটিভ গার্ড।&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame has-title&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;SQL&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;sql&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;CREATE&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;TABLE&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D2A8FF&quot;&gt;idempotency_keys&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; (&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;key&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;VARCHAR&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;255&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;PRIMARY KEY&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;status&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;VARCHAR&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;50&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;NOT NULL&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#8B949E&quot;&gt;-- IN_PROGRESS, COMPLETED, FAILED&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;response_body JSONB,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;created_at &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;TIMESTAMP WITH TIME ZONE&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;DEFAULT&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;NOW&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;()&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;CREATE TABLE idempotency_keys (    key VARCHAR(255) PRIMARY KEY,    status VARCHAR(50) NOT NULL, -- IN_PROGRESS, COMPLETED, FAILED    response_body JSONB,    created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW());&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;ডাটাবেজের B-Tree ইনডেক্স গ্যারান্টি দেয় যে, দশটি থ্রেড একই সঙ্গে ইনসার্ট করার চেষ্টা করলেও ঠিক একটি থ্রেড সফল হবে এবং বাকি নয়টি থ্রেডে ডাটাবেজ লেভেলে &lt;code&gt;Unique Violation Error (Postgres Code 23505)&lt;/code&gt; থ্রো হবে।&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;consumer-crash-ও-inbox-pattern&quot;&gt;Consumer Crash ও Inbox Pattern&lt;/h2&gt;
&lt;p&gt;মেসেজ ব্রোকার (Kafka, RabbitMQ, SQS) ব্যবহার করার সময় আরেকটি বড় ক্র্যাশ সিনারিও তৈরি হয়:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Consumer সার্ভিস ব্রোকার থেকে একটি মেসেজ রিসিভ করল।&lt;/li&gt;
&lt;li&gt;Consumer ইউজারের একাউন্টে &lt;code&gt;$100&lt;/code&gt; যোগ করল।&lt;/li&gt;
&lt;li&gt;ব্রোকারকে &lt;code&gt;ACK&lt;/code&gt; পাঠানোর ঠিক এক মিলি-সেকেন্ড আগে কনজিউমার সার্ভিসটি OOM (Out of Memory) হয়ে ক্র্যাশ করল।&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;যেহেতু ব্রোকার কোনো ACK পায়নি, সে মনে করবে মেসেজটি প্রসেস হয়নি। কনজিউমার পড যখন রিস্টার্ট নেবে, ব্রোকার একই মেসেজ আবার ডেলিভার করবে। কনজিউমার আবার &lt;code&gt;$100&lt;/code&gt; যোগ করবে!&lt;/p&gt;
&lt;figure&gt;&lt;img src=&quot;https://raw.githubusercontent.com/rafeuddaraj/rafes-blog-assets/refs/heads/exactly-once-delivery-myth-distributed-systems/assets/inbox-pattern.svg&quot; alt=&quot;Inbox Pattern for Consumer Crashes&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;800&quot; height=&quot;400&quot;&gt;&lt;figcaption&gt;Inbox Pattern for Consumer Crashes&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;এই ক্র্যাশ সিনারিও আটকানোর জন্য ব্যবহার করা হয় &lt;strong&gt;Inbox Pattern&lt;/strong&gt;।&lt;/p&gt;
&lt;p&gt;Inbox Pattern-এর মূল নিয়ম হলো: &lt;strong&gt;মেসেজ আইডি সেভ করা এবং বিজনেস ডাটা আপডেট করাকে আলাদা আলাদা অপারেশনে না চালিয়ে একটি সিঙ্গেল ACID Database Transaction-এর মধ্যে চালাতে হবে।&lt;/strong&gt;&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame has-title&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;SQL&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;sql&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;BEGIN&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#8B949E&quot;&gt;-- ১. মেসেজ আইডি ইনবক্স টেবিলে ইনসার্ট করার চেষ্টা করুন (message_id কলামে UNIQUE constraint আছে)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#8B949E&quot;&gt;-- ডুপ্লিকেট মেসেজ হলে ডাটাবেজ সাথে সাথে Unique Constraint Error দিয়ে পুরো ট্রানজেকশন আটকে দেবে&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;INSERT INTO&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; message_inbox (message_id, received_at)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;VALUES&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;&apos;msg-ord-98765&apos;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;NOW&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;());&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#8B949E&quot;&gt;-- ২. বিজনেস ডাটা আপডেট করুন (শুধুমাত্র যদি উপরের ইনসার্ট সফল হয়)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;UPDATE&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; user_wallets&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;SET&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; balance &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; balance &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;+&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;100&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;WHERE&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; user_id &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;&apos;usr-001&apos;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#8B949E&quot;&gt;-- ৩. অডিট লগ লিখুন&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;INSERT INTO&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; wallet_transactions (user_id, amount, &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;type&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;VALUES&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;&apos;usr-001&apos;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;100&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;&apos;CREDIT&apos;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#8B949E&quot;&gt;-- ৪. পারমাণবিকভাবে ট্রানজেকশন কমিট করুন&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;COMMIT&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;BEGIN;-- ১. মেসেজ আইডি ইনবক্স টেবিলে ইনসার্ট করার চেষ্টা করুন (message_id কলামে UNIQUE constraint আছে)-- ডুপ্লিকেট মেসেজ হলে ডাটাবেজ সাথে সাথে Unique Constraint Error দিয়ে পুরো ট্রানজেকশন আটকে দেবেINSERT INTO message_inbox (message_id, received_at)VALUES (&amp;#x27;msg-ord-98765&amp;#x27;, NOW());-- ২. বিজনেস ডাটা আপডেট করুন (শুধুমাত্র যদি উপরের ইনসার্ট সফল হয়)UPDATE user_walletsSET balance = balance + 100WHERE user_id = &amp;#x27;usr-001&amp;#x27;;-- ৩. অডিট লগ লিখুনINSERT INTO wallet_transactions (user_id, amount, type)VALUES (&amp;#x27;usr-001&amp;#x27;, 100, &amp;#x27;CREDIT&amp;#x27;);-- ৪. পারমাণবিকভাবে ট্রানজেকশন কমিট করুনCOMMIT;&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;যদি সার্ভার &lt;code&gt;COMMIT&lt;/code&gt;-এর আগে যেকোনো মুহূর্তে ক্র্যাশ করে, ডাটাবেজ পুরো অপারেশন রোলব্যাক করবে। মেসেজ আইডিও সেভ হবে না, ব্যালেন্সও বাড়বে না। আবার যদি &lt;code&gt;COMMIT&lt;/code&gt;-এর পর ক্র্যাশ করে, তবে মেসেজ আইডি অলরেডি সেভ আছে, তাই রিট্রাই এলে ডাটাবেজ ইউনিক এরর দিয়ে ডুপ্লিকেট ব্যালেন্স আপডেট আটকে দেবে।&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;dual-write-problem-ও-transactional-outbox-pattern&quot;&gt;Dual-Write Problem ও Transactional Outbox Pattern&lt;/h2&gt;
&lt;p&gt;Inbox দিয়ে আমরা মেসেজ কনজিউম করার সমস্যা সমাধান করলাম। কিন্তু ডাটা প্রডিউস করার সময় কী হবে?&lt;/p&gt;
&lt;p&gt;ধরা যাক, Order Service ডাটাবেজে অর্ডার সেভ করার পর Kafka-তে একটি &lt;code&gt;OrderCreated&lt;/code&gt; ইভেন্ট পাঠাবে যাতে Inventory Service স্টক কমাতে পারে।&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame has-title&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;JavaScript&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;javascript&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#8B949E&quot;&gt;// মারাত্মক Anti-Pattern: The Dual-Write Problem&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;await&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; db.&lt;/span&gt;&lt;span style=&quot;--0:#D2A8FF&quot;&gt;query&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;&apos;INSERT INTO orders ...&apos;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;); &lt;/span&gt;&lt;span style=&quot;--0:#8B949E&quot;&gt;// ধাপ ১: সফল&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;await&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; kafkaProducer.&lt;/span&gt;&lt;span style=&quot;--0:#D2A8FF&quot;&gt;send&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;&apos;OrderCreated&apos;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;...&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;); &lt;/span&gt;&lt;span style=&quot;--0:#8B949E&quot;&gt;// ধাপ ২: নেটওয়ার্ক ফেইলরে ক্র্যাশ!&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;// মারাত্মক Anti-Pattern: The Dual-Write Problemawait db.query(&amp;#x27;INSERT INTO orders ...&amp;#x27;); // ধাপ ১: সফলawait kafkaProducer.send(&amp;#x27;OrderCreated&amp;#x27;, ...); // ধাপ ২: নেটওয়ার্ক ফেইলরে ক্র্যাশ!&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;ধাপ ১ সফল হওয়ার পর যদি ব্রোকারে ইভেন্ট পাঠানো ফেইল করে, তবে ডাটাবেজে অর্ডার থেকে যাবে কিন্তু ইনভেন্টরি সার্ভিস জানতেই পারবে না অর্ডার হয়েছে। একে বলা হয় &lt;strong&gt;Dual-Write Problem&lt;/strong&gt;। দুটি ভিন্ন স্টোরেজ সিস্টেমে একই সাথে পারমাণবিকভাবে রাইট করা যায় না।&lt;/p&gt;
&lt;figure&gt;&lt;img src=&quot;https://raw.githubusercontent.com/rafeuddaraj/rafes-blog-assets/refs/heads/exactly-once-delivery-myth-distributed-systems/assets/transactional-outbox.svg&quot; alt=&quot;Transactional Outbox Architecture&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;800&quot; height=&quot;400&quot;&gt;&lt;figcaption&gt;Transactional Outbox Architecture&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;এই সমস্যার সমাধান হলো &lt;strong&gt;Transactional Outbox Pattern&lt;/strong&gt;:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;আমরা সরাসরি মেসেজ ব্রোকারে ইভেন্ট পাঠাব না।&lt;/li&gt;
&lt;li&gt;মূল বিজনেস টেবিল (&lt;code&gt;orders&lt;/code&gt;) এবং একটি বিশেষ &lt;code&gt;outbox_events&lt;/code&gt; টেবিলে একই লোকাল ডাটাবেজ ট্রানজেকশনের মধ্যে ইভেন্টটি সেভ করব।&lt;/li&gt;
&lt;li&gt;যেহেতু দুটি টেবিল একই ডাটাবেজের ভেতরে আছে, ডাটাবেজের ACID প্রোপার্টি গ্যারান্টি দেয় যে দুটি টেবিলেই ডাটা সেভ হবে, নতুবা কোনোটিতেই হবে না।&lt;/li&gt;
&lt;li&gt;একটি আলাদা ব্যাকগ্রাউন্ড রিলে ওয়ার্কার (বা Debezium CDC) &lt;code&gt;outbox_events&lt;/code&gt; টেবিল থেকে ডাটা রিড করে ব্রোকারে পাবলিশ করবে।&lt;/li&gt;
&lt;/ol&gt;
&lt;div class=&quot;callout&quot; role=&quot;note&quot; data-type=&quot;warning&quot;&gt;
&lt;p class=&quot;callout-title&quot;&gt;Outbox-এর ডেলিভারি গ্যারান্টি&lt;/p&gt;
&lt;p&gt;মনে রাখবেন, Transactional Outbox প্যাটার্ন কিন্তু &lt;strong&gt;At-Least-Once&lt;/strong&gt; ডেলিভারি নিশ্চিত করে, Exactly-Once নয়। রিলে ওয়ার্কার ব্রোকারে মেসেজ পাঠিয়ে ACK পাওয়ার আগে ক্র্যাশ করলে একই ইভেন্ট আবার ব্রোকারে যেতে পারে। তাই কনজিউমার সাইডে আমরা যে &lt;strong&gt;Inbox Pattern&lt;/strong&gt; শিখেছি, তার উপস্থিতি বাধ্যতামূলক।&lt;/p&gt;
&lt;/div&gt;
&lt;hr&gt;
&lt;h2 id=&quot;retry-storm-exponential-backoff-এবং-jitter&quot;&gt;Retry Storm, Exponential Backoff এবং Jitter&lt;/h2&gt;
&lt;p&gt;ডিস্ট্রিবিউটেড সিস্টেমে যখন কোনো ডাউনস্ট্রিম সার্ভিস সাময়িকভাবে স্লো বা আনঅ্যাভেইলেবল হয়ে যায়, তখন At-Least-Once মডেলে ক্লায়েন্টরা ঘন ঘন রিট্রাই পাঠাতে শুরু করে।&lt;/p&gt;
&lt;p&gt;ডাউন থাকা সার্ভিসটি যখনই রিকভার করার চেষ্টা করে, হাজার হাজার ক্লায়েন্টের জমে থাকা রিট্রাই রিকোয়েস্ট একযোগে সার্ভারে আঘাত হানে। ফলে সার্ভারটি সাথে সাথেই আবার ক্র্যাশ করে। এই ধ্বংসাত্মক চক্রকে বলা হয় &lt;strong&gt;Retry Storm&lt;/strong&gt; বা &lt;strong&gt;Thundering Herd Problem&lt;/strong&gt;।&lt;/p&gt;
&lt;figure&gt;&lt;img src=&quot;https://raw.githubusercontent.com/rafeuddaraj/rafes-blog-assets/refs/heads/exactly-once-delivery-myth-distributed-systems/assets/retry-storm-backoff.svg&quot; alt=&quot;Retry Storms vs Exponential Backoff with Jitter&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;800&quot; height=&quot;400&quot;&gt;&lt;figcaption&gt;Retry Storms vs Exponential Backoff with Jitter&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;রিট্রাই স্টর্ম থেকে বাঁচতে দুটি মেকানিজম একসাথে ব্যবহার করতে হয়:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Exponential Backoff:&lt;/strong&gt; প্রতিবার ফেইলরের পর রিট্রাইয়ের ব্যবধান দ্বিগুণ করা (&lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:1.0085em;vertical-align:-0.1944em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.8141em;&quot;&gt;&lt;span style=&quot;top:-3.063em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mtight&quot;&gt;0&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mpunct&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.1667em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.8141em;&quot;&gt;&lt;span style=&quot;top:-3.063em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mtight&quot;&gt;1&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mpunct&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.1667em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.8141em;&quot;&gt;&lt;span style=&quot;top:-3.063em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mtight&quot;&gt;2&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mpunct&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.1667em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.8141em;&quot;&gt;&lt;span style=&quot;top:-3.063em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mtight&quot;&gt;3&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;...&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; সেকেন্ড)।&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Jitter (র‍্যান্ডম ভ্যারিয়েশন):&lt;/strong&gt; ব্যাকঅফ টাইমের সাথে একটি র‍্যান্ডম মিলিসেকেন্ড যোগ করা যাতে সব ক্লায়েন্ট একদম একই মুহূর্তে একসাথে রিট্রাই না পাঠিয়ে ট্রাফিককে স্মুথভাবে ছড়িয়ে দেয়।&lt;/li&gt;
&lt;/ol&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame has-title&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;JavaScript&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;javascript&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#8B949E&quot;&gt;// প্রোডাকশন গ্রেড Exponential Backoff + Full Jitter অ্যালগরিদম&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;async&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;function&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D2A8FF&quot;&gt;fetchWithResilience&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#FFA657&quot;&gt;url&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#FFA657&quot;&gt;options&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#FFA657&quot;&gt;maxRetries&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;5&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;) {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;for&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;let&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; attempt &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;; attempt &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; maxRetries; attempt&lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;++&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;) {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;try&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;response&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;await&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D2A8FF&quot;&gt;fetch&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;(url, options);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;if&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; (response.ok) &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; response;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;--0:#8B949E&quot;&gt;// 4xx ক্লায়েন্ট এররে রিট্রাই করবেন না (429 Rate Limit ছাড়া)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;if&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; (response.status &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;!==&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;429&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;&amp;#x26;&amp;#x26;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; response.status &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;500&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;) {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;throw&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D2A8FF&quot;&gt;Error&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;`Client Error: ${&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;response&lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;status&lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;}`&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;} &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;catch&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; (error) {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;if&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; (attempt &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;===&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; maxRetries &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;throw&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; error;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;--0:#8B949E&quot;&gt;// ১. Exponential Base Delay: 1s, 2s, 4s, 8s, 16s...&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;baseDelay&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; Math.&lt;/span&gt;&lt;span style=&quot;--0:#D2A8FF&quot;&gt;pow&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;2&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;, attempt) &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;*&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;1000&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;--0:#8B949E&quot;&gt;// ২. Full Jitter: 0 থেকে baseDelay-র মধ্যে র‍্যান্ডম সময় নির্বাচন&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;delay&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; Math.&lt;/span&gt;&lt;span style=&quot;--0:#D2A8FF&quot;&gt;random&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;() &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;*&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; baseDelay;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;console.&lt;/span&gt;&lt;span style=&quot;--0:#D2A8FF&quot;&gt;warn&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;`Attempt ${&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;attempt&lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;+&lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;} failed. Retrying in ${&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;Math&lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#D2A8FF&quot;&gt;round&lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;delay&lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;}ms...`&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;await&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;Promise&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#FFA657&quot;&gt;resolve&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;=&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D2A8FF&quot;&gt;setTimeout&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;(resolve, delay));&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;// প্রোডাকশন গ্রেড Exponential Backoff + Full Jitter অ্যালগরিদমasync function fetchWithResilience(url, options, maxRetries = 5) {  for (let attempt = 0; attempt &lt; maxRetries; attempt++) {    try {      const response = await fetch(url, options);      if (response.ok) return response;      // 4xx ক্লায়েন্ট এররে রিট্রাই করবেন না (429 Rate Limit ছাড়া)      if (response.status !== 429 &amp;#x26;&amp;#x26; response.status &lt; 500) {        throw new Error(&amp;#x60;Client Error: ${response.status}&amp;#x60;);      }    } catch (error) {      if (attempt === maxRetries - 1) throw error;      // ১. Exponential Base Delay: 1s, 2s, 4s, 8s, 16s...      const baseDelay = Math.pow(2, attempt) * 1000;      // ২. Full Jitter: 0 থেকে baseDelay-র মধ্যে র‍্যান্ডম সময় নির্বাচন      const delay = Math.random() * baseDelay;      console.warn(&amp;#x60;Attempt ${attempt + 1} failed. Retrying in ${Math.round(delay)}ms...&amp;#x60;);      await new Promise(resolve =&gt; setTimeout(resolve, delay));    }  }}&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;hr&gt;
&lt;h2 id=&quot;apache-kafka-র-exactly-once-মিথ-বনাম-বাস্তবতা&quot;&gt;Apache Kafka-র &apos;Exactly-Once&apos; মিথ বনাম বাস্তবতা&lt;/h2&gt;
&lt;p&gt;ইঞ্জিনিয়ারদের মাঝে একটি বহুল প্রচলিত ভুল ধারণা আছে যে, Apache Kafka-তে &lt;code&gt;processing.guarantee=&quot;exactly_once&quot;&lt;/code&gt; অন করে দিলেই পুরো এন্ড-টু-এন্ড সিস্টেম ম্যাজিক্যালি Exactly-Once হয়ে যায়।&lt;/p&gt;
&lt;p&gt;বাস্তবতা হলো, Kafka EOS (Exactly-Once Semantics)-এর একটি নির্দিষ্ট &lt;strong&gt;আর্কিটেকচারাল বাউন্ডারি&lt;/strong&gt; আছে:&lt;/p&gt;
&lt;figure&gt;&lt;img src=&quot;https://raw.githubusercontent.com/rafeuddaraj/rafes-blog-assets/refs/heads/exactly-once-delivery-myth-distributed-systems/assets/kafka-eos-boundary.svg&quot; alt=&quot;Kafka EOS Boundary Limitations&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;800&quot; height=&quot;400&quot;&gt;&lt;figcaption&gt;Kafka EOS Boundary Limitations&lt;/figcaption&gt;&lt;/figure&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Kafka EOS যেখানে কাজ করে:&lt;/strong&gt; আপনি Kafka-র একটি Topic A থেকে ডাটা পড়লেন, Kafka Streams দিয়ে ট্রান্সফর্ম করলেন, এবং Kafka-র Topic B-তে রাইট করলেন (&lt;code&gt;Consume-Transform-Produce Cycle&lt;/code&gt;)। এই ক্লোজড লুপের ভেতরে Kafka Transaction Coordinator গ্যারান্টি দেয় যে ডাটা ঠিক একবারই প্রসেস হবে।&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Kafka EOS যেখানে ব্যর্থ হয়:&lt;/strong&gt; আপনার কনজিউমার যখন মেসেজ পড়ে কোনো এক্সটার্নাল সিস্টেম যেমন Stripe API, SendGrid ইমেইল গেটওয়ে, বা থার্ড-পার্টি ডাটাবেজে কল করে, তখন Kafka EOS কোনো সাহায্য করতে পারে না। এক্সটার্নাল নেটওয়ার্ক কলের মুহূর্তে ক্র্যাশ হলে রিস্টার্টের পর Kafka মেসেজটি আবার দেবে এবং আপনি এক্সটার্নাল গেটওয়েতে ডুপ্লিকেট কল করবেন।&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id=&quot;end-to-end-limitations-ডাটাবেজ-ট্রানজেকশন-বনাম-এক্সটার্নাল-api&quot;&gt;End-to-End Limitations: ডাটাবেজ ট্রানজেকশন বনাম এক্সটার্নাল API&lt;/h2&gt;
&lt;p&gt;ডিস্ট্রিবিউটেড সিস্টেমের সবচেয়ে বড় হার্ড রিয়ালিটি হলো: &lt;strong&gt;আপনি কখনোই একটি রিলেশনাল ডাটাবেজ ট্রানজেকশনের ভেতরে এক্সটার্নাল HTTP API কলকে পারমাণবিকভাবে বান্ডেল করতে পারবেন না।&lt;/strong&gt;&lt;/p&gt;
&lt;figure&gt;&lt;img src=&quot;https://raw.githubusercontent.com/rafeuddaraj/rafes-blog-assets/refs/heads/exactly-once-delivery-myth-distributed-systems/assets/end-to-end-failure.svg&quot; alt=&quot;End-to-End Failure Matrix&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;800&quot; height=&quot;250&quot;&gt;&lt;figcaption&gt;End-to-End Failure Matrix&lt;/figcaption&gt;&lt;/figure&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame has-title&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;JavaScript&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;javascript&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#8B949E&quot;&gt;// চরম বিপজ্জনক Anti-Pattern: DB Transaction-এর ভেতর External API কল&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;await&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; db.&lt;/span&gt;&lt;span style=&quot;--0:#D2A8FF&quot;&gt;query&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;&apos;BEGIN&apos;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;await&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; db.&lt;/span&gt;&lt;span style=&quot;--0:#D2A8FF&quot;&gt;query&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;&apos;UPDATE accounts SET balance = balance - 100 WHERE id = $1&apos;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;, [userId]);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#8B949E&quot;&gt;// এই API কল যদি নেটওয়ার্কের কারণে ১৫ সেকেন্ড আটকে থাকে, তবে ডাটাবেজ রো ১৫ সেকেন্ড লক থাকবে!&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#8B949E&quot;&gt;// আর যদি API সফল হওয়ার পর ডাটাবেজ COMMIT ফেইল করে, তবে টাকা কাটা হবে না কিন্তু পেমেন্ট হয়ে যাবে!&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;paymentRes&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;await&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; stripe.charges.&lt;/span&gt;&lt;span style=&quot;--0:#D2A8FF&quot;&gt;create&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;({ amount: &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;10000&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; });&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;await&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; db.&lt;/span&gt;&lt;span style=&quot;--0:#D2A8FF&quot;&gt;query&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;&apos;COMMIT&apos;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;// চরম বিপজ্জনক Anti-Pattern: DB Transaction-এর ভেতর External API কলawait db.query(&amp;#x27;BEGIN&amp;#x27;);await db.query(&amp;#x27;UPDATE accounts SET balance = balance - 100 WHERE id = $1&amp;#x27;, [userId]);// এই API কল যদি নেটওয়ার্কের কারণে ১৫ সেকেন্ড আটকে থাকে, তবে ডাটাবেজ রো ১৫ সেকেন্ড লক থাকবে!// আর যদি API সফল হওয়ার পর ডাটাবেজ COMMIT ফেইল করে, তবে টাকা কাটা হবে না কিন্তু পেমেন্ট হয়ে যাবে!const paymentRes = await stripe.charges.create({ amount: 10000 });await db.query(&amp;#x27;COMMIT&amp;#x27;);&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;div class=&quot;callout&quot; role=&quot;note&quot; data-type=&quot;danger&quot;&gt;
&lt;p class=&quot;callout-title&quot;&gt;Golden Rule of Database Transactions&lt;/p&gt;
&lt;p&gt;ডাটাবেজ ট্রানজেকশন ব্লক (&lt;code&gt;BEGIN&lt;/code&gt; ... &lt;code&gt;COMMIT&lt;/code&gt;)-এর ভেতরে কখনোই কোনো নেটওয়ার্ক কল, HTTP রিকোয়েস্ট বা থার্ড-পার্টি সার্ভিস কল রাখবেন না। নেটওয়ার্ক ল্যাটেন্সি ডাটাবেজের কানেকশন পুল নষ্ট করে দেবে এবং ডিসট্রিবিউটেড স্টেটকে আনরিকভারেবল করে তুলবে।&lt;/p&gt;
&lt;/div&gt;
&lt;hr&gt;
&lt;h2 id=&quot;real-world-architecture-payment-processing-pipeline&quot;&gt;Real-World Architecture: Payment Processing Pipeline&lt;/h2&gt;
&lt;p&gt;একটি ইন্ডাস্ট্রি-স্ট্যান্ডার্ড, হাই-স্কেল পেমেন্ট প্রসেসিং পাইপলাইন কীভাবে মাল্টিপল লেয়ারে ফল্ট-টল্যারেন্স হ্যান্ডেল করে তা লক্ষ্য করুন:&lt;/p&gt;
&lt;figure&gt;&lt;img src=&quot;https://raw.githubusercontent.com/rafeuddaraj/rafes-blog-assets/refs/heads/exactly-once-delivery-myth-distributed-systems/assets/payment-architecture.svg&quot; alt=&quot;Production Payment System Architecture&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;800&quot; height=&quot;450&quot;&gt;&lt;figcaption&gt;Production Payment System Architecture&lt;/figcaption&gt;&lt;/figure&gt;
&lt;h3 id=&quot;এন্ড-টু-এন্ড-রিকোয়েস্ট-ফ্লো&quot;&gt;এন্ড-টু-এন্ড রিকোয়েস্ট ফ্লো:&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Client Layer:&lt;/strong&gt; ব্রাউজার বা মোবাইল অ্যাপ একটি &lt;code&gt;client_request_id&lt;/code&gt; সহ পেমেন্ট সার্ভিসে কল করে।&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Ingress &amp;#x26; DB Guard:&lt;/strong&gt; পেমেন্ট সার্ভিস ডাটাবেজে Unique Constraint দিয়ে চেক করে যে এই &lt;code&gt;client_request_id&lt;/code&gt; আগে প্রসেস হয়েছে কি না। ডাটাবেজে ইভেন্টটি Outbox টেবিলে সেভ করে ক্লায়েন্টকে &lt;code&gt;202 Accepted&lt;/code&gt; রিটার্ন করে।&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Async Worker Layer:&lt;/strong&gt; ব্যাকগ্রাউন্ড ওয়ার্কার আউটবক্স থেকে ইভেন্ট তুলে নিয়ে পেমেন্ট গেটওয়ের জন্য একটি নিজস্ব &lt;code&gt;provider_idempotency_key&lt;/code&gt; জেনারেট করে।&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Gateway Call:&lt;/strong&gt; পেমেন্ট গেটওয়েতে (Stripe) সেই কি সহ কল পাঠানো হয়। নেটওয়ার্ক ড্রপ হলে ওয়ার্কার নিরাপদে একই কি দিয়ে রিট্রাই করে। Stripe তার নিজস্ব লেয়ারে ডুপ্লিকেট চার্জ আটকে দেয়।&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Webhook Deduplication:&lt;/strong&gt; পেমেন্ট সম্পন্ন হলে গেটওয়ে থেকে Webhook আসে। পেমেন্ট সার্ভিস Webhook-এর &lt;code&gt;event_id&lt;/code&gt; ইনবক্স টেবিলে যাচাই করে ডুপ্লিকেট ওয়েবহুক ফিল্টার করে এবং ইউজারের অর্ডার ফাইনাল কনফার্ম করে।&lt;/li&gt;
&lt;/ol&gt;
&lt;hr&gt;
&lt;h2 id=&quot;effectively-once-system-architecture&quot;&gt;Effectively-Once System Architecture&lt;/h2&gt;
&lt;p&gt;একটি পূর্ণাঙ্গ প্রোডাকশন সিস্টেমে রিলায়েবিলিটি কোনো সিঙ্গেল ম্যাজিক টুলের ওপর দাঁড়িয়ে থাকে না, বরং এটি একাধিক আর্কিটেকচারাল লেয়ারের সমন্বয়ে গড়ে ওঠে:&lt;/p&gt;
&lt;figure&gt;&lt;img src=&quot;https://raw.githubusercontent.com/rafeuddaraj/rafes-blog-assets/refs/heads/exactly-once-delivery-myth-distributed-systems/assets/reliability-layers.svg&quot; alt=&quot;Distributed Reliability Layers&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;800&quot; height=&quot;450&quot;&gt;&lt;figcaption&gt;Distributed Reliability Layers&lt;/figcaption&gt;&lt;/figure&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Delivery Layer (At-Least-Once):&lt;/strong&gt; নেটওয়ার্ক ড্রপে ডাটা লস রোধ করতে রিট্রাই মেকানিজম নিশ্চিত করা।&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Traffic Smoothing (Backoff + Jitter):&lt;/strong&gt; সিস্টেম রিকভারির সময় রিট্রাই স্টর্ম প্রতিহত করা।&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Consumer Guard (Inbox + DB Unique Constraints):&lt;/strong&gt; ডুপ্লিকেট মেসেজ ডেলিভারি হলেও ডাটাবেজ লেভেলে রেস কন্ডিশন ও ডুপ্লিকেট স্টেট আপডেট ব্লক করা।&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Publisher Guard (Transactional Outbox):&lt;/strong&gt; ডাটাবেজ রাইট ও মেসেজ পাবলিশিংয়ের মধ্যে Dual-Write সমস্যা দূর করা।&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Distributed Workflow (Saga &amp;#x26; Compensation):&lt;/strong&gt; মাল্টি-সার্ভিস অপারেশনে কোনো ধাপ ফেইল করলে কমপেনসেটিং ট্রানজেকশন চালিয়ে পূর্বের স্টেট নিরাপদে রিভার্স করা।&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;এই পাঁচটি লেয়ার একসাথে কাজ করলে এন্ড-ইউজারের কাছে পুরো সিস্টেমটি একটি ত্রুটিহীন &lt;strong&gt;Effectively-Once Business Outcome&lt;/strong&gt; প্রদান করে।&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;recap-ও-production-readiness-checklist&quot;&gt;Recap ও Production Readiness Checklist&lt;/h2&gt;
&lt;p&gt;ডিস্ট্রিবিউটেড সিস্টেম ফেইলর ম্যাট্রিক্সটি মনে রাখুন:&lt;/p&gt;
&lt;figure&gt;&lt;img src=&quot;https://raw.githubusercontent.com/rafeuddaraj/rafes-blog-assets/refs/heads/exactly-once-delivery-myth-distributed-systems/assets/failure-matrix.svg&quot; alt=&quot;Distributed System Failure Matrix&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;800&quot; height=&quot;300&quot;&gt;&lt;figcaption&gt;Distributed System Failure Matrix&lt;/figcaption&gt;&lt;/figure&gt;
&lt;h3 id=&quot;আপনার-production-readiness-checklist&quot;&gt;আপনার Production Readiness Checklist&lt;/h3&gt;
&lt;ul class=&quot;contains-task-list&quot;&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; disabled aria-label=&quot;Define Boundaries: সিস্টেমে &amp;#x22;Exactly-Once&amp;#x22; শব্দ ব্যবহার বন্ধ করুন। Delivery Semantics (At-Least-Once) এবং Processing Sem&quot;&gt; &lt;strong&gt;Define Boundaries:&lt;/strong&gt; সিস্টেমে &quot;Exactly-Once&quot; শব্দ ব্যবহার বন্ধ করুন। Delivery Semantics (At-Least-Once) এবং Processing Semantics (Idempotency)-কে টিমের সাথে আলাদাভাবে ডিফাইন করুন।&lt;/li&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; disabled aria-label=&quot;Enforce DB Uniqueness: মেমোরিতে if (!exists) চেক বাদ দিয়ে ডাটাবেজ লেভেলের UNIQUE কনস্ট্রেইন্ট ব্যবহার করুন।&quot;&gt; &lt;strong&gt;Enforce DB Uniqueness:&lt;/strong&gt; মেমোরিতে &lt;code&gt;if (!exists)&lt;/code&gt; চেক বাদ দিয়ে ডাটাবেজ লেভেলের &lt;code&gt;UNIQUE&lt;/code&gt; কনস্ট্রেইন্ট ব্যবহার করুন।&lt;/li&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; disabled aria-label=&quot;Implement Idempotency Keys: সমস্ত স্টেট-মডিফাইং POST API-তে বাধ্যতামূলক Idempotency-Key হেডার যুক্ত করুন।&quot;&gt; &lt;strong&gt;Implement Idempotency Keys:&lt;/strong&gt; সমস্ত স্টেট-মডিফাইং &lt;code&gt;POST&lt;/code&gt; API-তে বাধ্যতামূলক &lt;code&gt;Idempotency-Key&lt;/code&gt; হেডার যুক্ত করুন।&lt;/li&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; disabled aria-label=&quot;Adopt Inbox Pattern: মেসেজ কনজিউমার সার্ভিসে মেসেজ আইডি এবং বিজনেস স্টেট আপডেটকে একই ডাটাবেজ ট্রানজেকশনের ভেতরে কমিট করু&quot;&gt; &lt;strong&gt;Adopt Inbox Pattern:&lt;/strong&gt; মেসেজ কনজিউমার সার্ভিসে মেসেজ আইডি এবং বিজনেস স্টেট আপডেটকে একই ডাটাবেজ ট্রানজেকশনের ভেতরে কমিট করুন।&lt;/li&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; disabled aria-label=&quot;Adopt Outbox Pattern: ডাটাবেজ সেভ এবং মেসেজ পাবলিশিংয়ের ক্ষেত্রে ডিরেক্ট নেটওয়ার্ক কল বাদ দিয়ে Transactional Outbox প্যা&quot;&gt; &lt;strong&gt;Adopt Outbox Pattern:&lt;/strong&gt; ডাটাবেজ সেভ এবং মেসেজ পাবলিশিংয়ের ক্ষেত্রে ডিরেক্ট নেটওয়ার্ক কল বাদ দিয়ে Transactional Outbox প্যাটার্ন ব্যবহার করুন।&lt;/li&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; disabled aria-label=&quot;Isolate DB Transactions: ডাটাবেজ ট্রানজেকশন ব্লকের ভেতর যেকোনো ধরনের External HTTP API বা নেটওয়ার্ক কল পুরোপুরি নিষিদ্ধ &quot;&gt; &lt;strong&gt;Isolate DB Transactions:&lt;/strong&gt; ডাটাবেজ ট্রানজেকশন ব্লকের ভেতর যেকোনো ধরনের External HTTP API বা নেটওয়ার্ক কল পুরোপুরি নিষিদ্ধ করুন।&lt;/li&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; disabled aria-label=&quot;Resilient Retries: সমস্ত রিট্রাই লজিকে Exponential Backoff-এর সাথে Full Jitter যুক্ত করুন।&quot;&gt; &lt;strong&gt;Resilient Retries:&lt;/strong&gt; সমস্ত রিট্রাই লজিকে Exponential Backoff-এর সাথে Full Jitter যুক্ত করুন।&lt;/li&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; disabled aria-label=&quot;Deduplicate Webhooks: থার্ড-পার্টি পেমেন্ট গেটওয়ের প্রতিটি Webhook ইভেন্টকে event_id দিয়ে ইনবক্সে ডিডুপ্লিকেট করুন।&quot;&gt; &lt;strong&gt;Deduplicate Webhooks:&lt;/strong&gt; থার্ড-পার্টি পেমেন্ট গেটওয়ের প্রতিটি Webhook ইভেন্টকে &lt;code&gt;event_id&lt;/code&gt; দিয়ে ইনবক্সে ডিডুপ্লিকেট করুন।&lt;/li&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; disabled aria-label=&quot;Observability &amp;#x26; Tracing: প্রতিটি রিকোয়েস্টে trace_id, idempotency_key, এবং message_id স্ট্রাকচার্ড লগে রাখুন।&quot;&gt; &lt;strong&gt;Observability &amp;#x26; Tracing:&lt;/strong&gt; প্রতিটি রিকোয়েস্টে &lt;code&gt;trace_id&lt;/code&gt;, &lt;code&gt;idempotency_key&lt;/code&gt;, এবং &lt;code&gt;message_id&lt;/code&gt; স্ট্রাকচার্ড লগে রাখুন।&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;ডিস্ট্রিবিউটেড সিস্টেমে নেটওয়ার্ক ফেইলর কোনো ব্যতিক্রমী ঘটনা নয়, এটিই প্রতিদিনের রূঢ় বাস্তবতা। সিস্টেমকে এমনভাবে ডিজাইন করুন যেন নেটওয়ার্ক যেকোনো মুহূর্তে ড্রপ করলেও আপনার ডাটাবেজ ও বিজনেস স্টেট সর্বদা নিরাপদ ও অভ্রান্ত থাকে।&lt;/p&gt;</content:encoded><category>System Design</category><category>Distributed Systems</category><category>System Design</category><category>Backend Architecture</category><category>Kafka</category><category>Idempotency</category><category>Microservices</category><category>Node.js</category><category>PostgreSQL</category></item><item><title>How Cursor Pagination Actually Works Under the Hood</title><link>https://www.rafeuddaraj.me/bn/blog/cursor-pagination-under-the-hood/</link><guid isPermaLink="true">https://www.rafeuddaraj.me/bn/blog/cursor-pagination-under-the-hood/</guid><description>ডাটাবেজ এক্সিকিউশন প্ল্যান, বি-ট্রি ইনডেক্স রেঞ্জ স্ক্যান, ডিপ অফসেটের ও(এন) বোটলনেক এবং প্রোডাকশন গ্রেড ওপেক কার্সরের আর্কিটেকচার নিয়ে একটি ইন-ডেপথ টেকনিক্যাল গাইড।</description><pubDate>Sun, 06 Sep 2026 02:30:00 GMT</pubDate><content:encoded>&lt;p&gt;প্রথমেই এমন একটি পরিচিত Engineering scenario চিন্তা করুন যেখানে আপনার API ডিজাইন এবং Database query একদম নিখুঁত মনে হচ্ছে। আপনার &lt;code&gt;posts&lt;/code&gt; টেবিলে ৫০ মিলিয়ন (50,000,000) records আছে। আপনি যখন প্রথম পেজ লোড করছেন, তখন Database খুব দ্রুত মাত্র ২ মিলি-সেকেন্ডে ২০টি row রিটার্ন করছে।&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;style&gt;.expressive-code{font-family:var(--ec-uiFontFml);font-size:var(--ec-uiFontSize);font-weight:var(--ec-uiFontWg);line-height:var(--ec-uiLineHt);text-size-adjust:none;-webkit-text-size-adjust:none}.expressive-code *:not(:is(svg, svg *)){all:revert;box-sizing:border-box}.expressive-code pre{display:flex;margin:0;padding:0;border:var(--ec-brdWd) solid var(--ec-brdCol);border-radius:calc(var(--ec-brdRad) + var(--ec-brdWd));background:var(--ec-codeBg)}.expressive-code pre:focus-visible{outline:3px solid var(--ec-focusBrd);outline-offset:-3px}.expressive-code pre &gt; code{all:unset;display:block;flex:1 0 100%;padding:var(--ec-codePadBlk) 0;color:var(--ec-codeFg);font-family:var(--ec-codeFontFml);font-size:var(--ec-codeFontSize);font-weight:var(--ec-codeFontWg);line-height:var(--ec-codeLineHt)}.expressive-code pre{overflow-x:auto}.expressive-code pre.wrap .ec-line .code{white-space:pre-wrap;overflow-wrap:break-word;min-width:min(20ch, var(--ecMaxLine, 20ch))}.expressive-code pre.wrap .ec-line .code span.indent{white-space:pre}.expressive-code pre::-webkit-scrollbar,.expressive-code pre::-webkit-scrollbar-track{background-color:inherit;border-radius:calc(var(--ec-brdRad) + var(--ec-brdWd));border-top-left-radius:0;border-top-right-radius:0}.expressive-code pre::-webkit-scrollbar-thumb{background-color:var(--ec-sbThumbCol);border:4px solid transparent;background-clip:content-box;border-radius:10px}.expressive-code pre::-webkit-scrollbar-thumb:hover{background-color:var(--ec-sbThumbHoverCol)}.expressive-code pre::-webkit-scrollbar-corner{background:transparent}.expressive-code .ec-line{direction:ltr;unicode-bidi:isolate;display:grid;grid-template-areas:&apos;gutter code&apos;;grid-template-columns:auto 1fr;position:relative}.expressive-code .ec-line .gutter{grid-area:gutter;color:var(--ec-gtrFg)}.expressive-code .ec-line .gutter &gt; *{pointer-events:none;user-select:none;-webkit-user-select:none}.expressive-code .ec-line .gutter ~ .code{--ecLineBrdCol:var(--ec-gtrBrdCol)}.expressive-code .ec-line.highlight .gutter{color:var(--ec-gtrHlFg)}.expressive-code .ec-line .code{grid-area:code;position:relative;box-sizing:content-box;padding-inline-start:calc(var(--ecIndent, 0ch) + var(--ec-codePadInl) - var(--ecGtrBrdWd));padding-inline-end:var(--ec-codePadInl);text-indent:calc(var(--ecIndent, 0ch) * -1)}.expressive-code .ec-line .code::before,.expressive-code .ec-line .code::after,.expressive-code .ec-line .code :where(*){text-indent:0}.expressive-code .ec-line .code{--ecGtrBrdWd:var(--ec-gtrBrdWd);border-inline-start:var(--ecGtrBrdWd) solid var(--ecLineBrdCol, transparent)}.expressive-code .sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0, 0, 0, 0);white-space:nowrap;border-width:0}.expressive-code .ec-line.mark{--tmLineBgCol:var(--ec-tm-markBg)}.expressive-code .ec-line.mark .code{--ecLineBrdCol:var(--ec-tm-markBrdCol)}.expressive-code .ec-line.ins{--tmLineBgCol:var(--ec-tm-insBg);--tmLabel:var(--ec-tm-insDiffIndContent)}.expressive-code .ec-line.ins .code{--ecLineBrdCol:var(--ec-tm-insBrdCol)}.expressive-code .ec-line.ins .code::before{color:var(--ec-tm-insDiffIndCol)}.expressive-code .ec-line.del{--tmLineBgCol:var(--ec-tm-delBg);--tmLabel:var(--ec-tm-delDiffIndContent)}.expressive-code .ec-line.del .code{--ecLineBrdCol:var(--ec-tm-delBrdCol)}.expressive-code .ec-line.del .code::before{color:var(--ec-tm-delDiffIndCol)}.expressive-code .ec-line.mark,.expressive-code .ec-line.ins,.expressive-code .ec-line.del{background:var(--tmLineBgCol)}.expressive-code .ec-line.mark .code,.expressive-code .ec-line.ins .code,.expressive-code .ec-line.del .code{--ecGtrBrdWd:var(--ec-tm-lineMarkerAccentWd)}.expressive-code .ec-line.mark .code::before,.expressive-code .ec-line.ins .code::before,.expressive-code .ec-line.del .code::before{display:block;position:absolute;left:0;box-sizing:border-box;content:var(--tmLabel, &apos; &apos;);padding-inline-start:var(--ec-tm-lineDiffIndMargLeft);text-align:center;white-space:pre}.expressive-code .ec-line.mark.tm-label .code::before,.expressive-code .ec-line.ins.tm-label .code::before,.expressive-code .ec-line.del.tm-label .code::before{background:var(--ecLineBrdCol);padding:0 calc(var(--ec-tm-lineMarkerLabelPadInl) + var(--ec-tm-lineMarkerAccentWd)) 0 var(--ec-tm-lineMarkerLabelPadInl);color:var(--ec-tm-lineMarkerLabelCol)}.expressive-code .ec-line mark{--tmInlineBgCol:var(--ec-tm-markBg);--tmInlineBrdCol:var(--ec-tm-markBrdCol)}.expressive-code .ec-line ins{--tmInlineBgCol:var(--ec-tm-insBg);--tmInlineBrdCol:var(--ec-tm-insBrdCol)}.expressive-code .ec-line del{--tmInlineBgCol:var(--ec-tm-delBg);--tmInlineBrdCol:var(--ec-tm-delBrdCol)}.expressive-code .ec-line mark,.expressive-code .ec-line ins,.expressive-code .ec-line del{all:unset;display:inline-block;position:relative;--tmBrdL:var(--ec-tm-inlMarkerBrdWd);--tmBrdR:var(--ec-tm-inlMarkerBrdWd);--tmRadL:var(--ec-tm-inlMarkerBrdRad);--tmRadR:var(--ec-tm-inlMarkerBrdRad);margin-inline:0.025rem;padding-inline:var(--ec-tm-inlMarkerPad);border-radius:var(--tmRadL) var(--tmRadR) var(--tmRadR) var(--tmRadL);background:var(--tmInlineBgCol);background-clip:padding-box}.expressive-code .ec-line mark.open-start,.expressive-code .ec-line ins.open-start,.expressive-code .ec-line del.open-start{margin-inline-start:0;padding-inline-start:0;--tmBrdL:0px;--tmRadL:0}.expressive-code .ec-line mark.open-end,.expressive-code .ec-line ins.open-end,.expressive-code .ec-line del.open-end{margin-inline-end:0;padding-inline-end:0;--tmBrdR:0px;--tmRadR:0}.expressive-code .ec-line mark::before,.expressive-code .ec-line ins::before,.expressive-code .ec-line del::before{content:&apos;&apos;;position:absolute;pointer-events:none;display:inline-block;inset:0;border-radius:var(--tmRadL) var(--tmRadR) var(--tmRadR) var(--tmRadL);border:var(--ec-tm-inlMarkerBrdWd) solid var(--tmInlineBrdCol);border-inline-width:var(--tmBrdL) var(--tmBrdR)}.expressive-code .frame{all:unset;position:relative;display:block;--header-border-radius:calc(var(--ec-brdRad) + var(--ec-brdWd));--tab-border-radius:calc(var(--ec-frm-edTabBrdRad) + var(--ec-brdWd));--button-spacing:0.4rem;--code-background:var(--ec-frm-edBg);border-radius:var(--header-border-radius);box-shadow:var(--ec-frm-frameBoxShdCssVal)}.expressive-code .frame .header{display:none;z-index:1;position:relative;border-radius:var(--header-border-radius) var(--header-border-radius) 0 0}.expressive-code .frame.has-title pre,.expressive-code .frame.has-title code,.expressive-code .frame.is-terminal pre,.expressive-code .frame.is-terminal code{border-top:none;border-top-left-radius:0;border-top-right-radius:0}.expressive-code .frame .title:empty:before{content:&apos;\a0&apos;}.expressive-code .frame.has-title:not(.is-terminal){--button-spacing:calc(1.9rem + 2 * (var(--ec-uiPadBlk) + var(--ec-frm-edActTabIndHt)))}.expressive-code .frame.has-title:not(.is-terminal) .title{position:relative;color:var(--ec-frm-edActTabFg);background:var(--ec-frm-edActTabBg);background-clip:padding-box;margin-block-start:var(--ec-frm-edTabsMargBlkStart);padding:calc(var(--ec-uiPadBlk) + var(--ec-frm-edActTabIndHt)) var(--ec-uiPadInl);border:var(--ec-brdWd) solid var(--ec-frm-edActTabBrdCol);border-radius:var(--tab-border-radius) var(--tab-border-radius) 0 0;border-bottom:none;overflow:hidden}.expressive-code .frame.has-title:not(.is-terminal) .title::after{content:&apos;&apos;;position:absolute;pointer-events:none;inset:0;border-top:var(--ec-frm-edActTabIndHt) solid var(--ec-frm-edActTabIndTopCol);border-bottom:var(--ec-frm-edActTabIndHt) solid var(--ec-frm-edActTabIndBtmCol)}.expressive-code .frame.has-title:not(.is-terminal) .header{display:flex;background:linear-gradient(to top, var(--ec-frm-edTabBarBrdBtmCol) var(--ec-brdWd), transparent var(--ec-brdWd)),linear-gradient(var(--ec-frm-edTabBarBg), var(--ec-frm-edTabBarBg));background-repeat:no-repeat;padding-inline-start:var(--ec-frm-edTabsMargInlStart)}.expressive-code .frame.has-title:not(.is-terminal) .header::before{content:&apos;&apos;;position:absolute;pointer-events:none;inset:0;border:var(--ec-brdWd) solid var(--ec-frm-edTabBarBrdCol);border-radius:inherit;border-bottom:none}.expressive-code .frame.is-terminal{--button-spacing:calc(1.9rem + var(--ec-brdWd) + 2 * var(--ec-uiPadBlk));--code-background:var(--ec-frm-trmBg)}.expressive-code .frame.is-terminal .header{display:flex;align-items:center;justify-content:center;padding-block:var(--ec-uiPadBlk);padding-block-end:calc(var(--ec-uiPadBlk) + var(--ec-brdWd));position:relative;font-weight:500;letter-spacing:0.025ch;color:var(--ec-frm-trmTtbFg);background:var(--ec-frm-trmTtbBg);border:var(--ec-brdWd) solid var(--ec-brdCol);border-bottom:none}.expressive-code .frame.is-terminal .header::before{content:&apos;&apos;;position:absolute;pointer-events:none;left:var(--ec-uiPadInl);width:2.1rem;height:0.56rem;line-height:0;background-color:var(--ec-frm-trmTtbDotsFg);opacity:var(--ec-frm-trmTtbDotsOpa);-webkit-mask-image:var(--ec-frm-trmIcon);-webkit-mask-repeat:no-repeat;mask-image:var(--ec-frm-trmIcon);mask-repeat:no-repeat}.expressive-code .frame.is-terminal .header::after{content:&apos;&apos;;position:absolute;pointer-events:none;inset:0;border-bottom:var(--ec-brdWd) solid var(--ec-frm-trmTtbBrdBtmCol)}.expressive-code .frame pre{background:var(--code-background)}.expressive-code .copy{display:flex;gap:0.25rem;flex-direction:row;position:absolute;inset-block-start:calc(var(--ec-brdWd) + var(--button-spacing));inset-inline-end:calc(var(--ec-brdWd) + var(--ec-uiPadInl) / 2)}@media (scripting: none){.expressive-code .copy{display:none}}.expressive-code .copy{direction:ltr;unicode-bidi:isolate}.expressive-code .copy button{position:relative;align-self:flex-end;margin:0;padding:0;border:none;border-radius:0.2rem;z-index:1;cursor:pointer;transition-property:opacity, background, border-color;transition-duration:0.2s;transition-timing-function:cubic-bezier(0.25, 0.46, 0.45, 0.94);width:2.5rem;height:2.5rem;background:var(--code-background);opacity:0.75}.expressive-code .copy button div{position:absolute;inset:0;border-radius:inherit;background:var(--ec-frm-inlBtnBg);opacity:var(--ec-frm-inlBtnBgIdleOpa);transition-property:inherit;transition-duration:inherit;transition-timing-function:inherit}.expressive-code .copy button::before{content:&apos;&apos;;position:absolute;pointer-events:none;inset:0;border-radius:inherit;border:var(--ec-brdWd) solid var(--ec-frm-inlBtnBrd);opacity:var(--ec-frm-inlBtnBrdOpa)}.expressive-code .copy button::after{content:&apos;&apos;;position:absolute;pointer-events:none;inset:0;background-color:var(--ec-frm-inlBtnFg);-webkit-mask-image:var(--ec-frm-copyIcon);-webkit-mask-repeat:no-repeat;mask-image:var(--ec-frm-copyIcon);mask-repeat:no-repeat;margin:0.475rem;line-height:0}.expressive-code .copy button:hover,.expressive-code .copy button:focus:focus-visible{opacity:1}.expressive-code .copy button:hover div,.expressive-code .copy button:focus:focus-visible div{opacity:var(--ec-frm-inlBtnBgHoverOrFocusOpa)}.expressive-code .copy button:active{opacity:1}.expressive-code .copy button:active div{opacity:var(--ec-frm-inlBtnBgActOpa)}.expressive-code .copy .feedback{--tooltip-arrow-size:0.35rem;--tooltip-bg:var(--ec-frm-tooltipSuccessBg);color:var(--ec-frm-tooltipSuccessFg);pointer-events:none;user-select:none;-webkit-user-select:none;position:relative;align-self:center;background-color:var(--tooltip-bg);z-index:99;padding:0.125rem 0.75rem;border-radius:0.2rem;margin-inline-end:var(--tooltip-arrow-size);opacity:0;transition-property:opacity, transform;transition-duration:0.2s;transition-timing-function:ease-in-out;transform:translate3d(0, 0.25rem, 0)}.expressive-code .copy .feedback::after{content:&apos;&apos;;position:absolute;pointer-events:none;top:calc(50% - var(--tooltip-arrow-size));inset-inline-end:calc(-2 * (var(--tooltip-arrow-size) - 0.5px));border:var(--tooltip-arrow-size) solid transparent;border-inline-start-color:var(--tooltip-bg)}.expressive-code .copy .feedback.show{opacity:1;transform:translate3d(0, 0, 0)}@media (hover: hover){.expressive-code{}.expressive-code .copy button{opacity:0;width:2rem;height:2rem}.expressive-code .frame:hover .copy button:not(:hover),.expressive-code .frame:focus-within :focus-visible ~ .copy button:not(:hover),.expressive-code .frame .copy .feedback.show ~ button:not(:hover){opacity:0.75}}.expressive-code :nth-child(1 of .ec-line) .code{padding-inline-end:calc(2rem + var(--ec-codePadInl))}:root{--ec-brdRad:0.75rem;--ec-brdWd:1.5px;--ec-brdCol:var(--code-line);--ec-codeFontFml:var(--font-code);--ec-codeFontSize:0.875rem;--ec-codeFontWg:400;--ec-codeLineHt:1.75;--ec-codePadBlk:1rem;--ec-codePadInl:1.125rem;--ec-codeBg:var(--code-bg);--ec-codeFg:#e6edf3;--ec-codeSelBg:#264f78;--ec-gtrFg:#6e7681;--ec-gtrBrdCol:#6e768133;--ec-gtrBrdWd:1.5px;--ec-gtrHlFg:#e6edf3;--ec-uiFontFml:var(--font-mono);--ec-uiFontSize:0.75rem;--ec-uiFontWg:400;--ec-uiLineHt:1.65;--ec-uiPadBlk:0.25rem;--ec-uiPadInl:1rem;--ec-uiSelBg:#6e768166;--ec-uiSelFg:#e6edf3;--ec-focusBrd:#1f6feb;--ec-sbThumbCol:#8b949e33;--ec-sbThumbHoverCol:#8b949e3d;--ec-tm-lineMarkerAccentMarg:0rem;--ec-tm-lineMarkerAccentWd:0.15rem;--ec-tm-lineMarkerLabelPadInl:0.2rem;--ec-tm-lineMarkerLabelCol:white;--ec-tm-lineDiffIndMargLeft:0.3rem;--ec-tm-inlMarkerBrdWd:1.5px;--ec-tm-inlMarkerBrdRad:0.2rem;--ec-tm-inlMarkerPad:0.15rem;--ec-tm-insDiffIndContent:&apos;+&apos;;--ec-tm-delDiffIndContent:&apos;-&apos;;--ec-tm-markBg:#264a8980;--ec-tm-markBrdCol:#5570b3d0;--ec-tm-insBg:#26561c80;--ec-tm-insBrdCol:#4e7e41d0;--ec-tm-insDiffIndCol:#7eb070d0;--ec-tm-delBg:#81322b80;--ec-tm-delBrdCol:#ae594fd0;--ec-tm-delDiffIndCol:#e68a7ed0;--ec-frm-shdCol:#0000005b;--ec-frm-frameBoxShdCssVal:none;--ec-frm-edActTabBg:var(--code-bg);--ec-frm-edActTabFg:var(--code-muted);--ec-frm-edActTabBrdCol:transparent;--ec-frm-edActTabIndHt:1.5px;--ec-frm-edActTabIndTopCol:transparent;--ec-frm-edActTabIndBtmCol:#0d1117;--ec-frm-edTabsMargInlStart:0;--ec-frm-edTabsMargBlkStart:0;--ec-frm-edTabBrdRad:0.75rem;--ec-frm-edTabBarBg:var(--code-bg);--ec-frm-edTabBarBrdCol:var(--code-line);--ec-frm-edTabBarBrdBtmCol:var(--code-line);--ec-frm-edBg:var(--code-bg);--ec-frm-trmTtbFg:var(--code-muted);--ec-frm-trmTtbDotsFg:var(--code-muted);--ec-frm-trmTtbDotsOpa:0.15;--ec-frm-trmTtbBg:var(--code-bg);--ec-frm-trmTtbBrdBtmCol:var(--code-line);--ec-frm-trmBg:var(--code-bg);--ec-frm-inlBtnBg:var(--code-ink);--ec-frm-inlBtnBgIdleOpa:0;--ec-frm-inlBtnBgHoverOrFocusOpa:0.2;--ec-frm-inlBtnBgActOpa:0.3;--ec-frm-inlBtnFg:var(--code-ink);--ec-frm-inlBtnBrd:var(--code-line);--ec-frm-inlBtnBrdOpa:0.4;--ec-frm-tooltipSuccessBg:var(--color-emerald);--ec-frm-tooltipSuccessFg:var(--color-bg);--ec-frm-copyIcon:url(&quot;data:image/svg+xml,%3Csvg%20xmlns%3D&apos;http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg&apos;%20viewBox%3D&apos;0%200%2024%2024&apos;%20fill%3D&apos;none&apos;%20stroke%3D&apos;black&apos;%20stroke-width%3D&apos;1.75&apos;%3E%3Cpath%20d%3D&apos;M3%2019a2%202%200%200%201-1-2V2a2%202%200%200%201%201-1h13a2%202%200%200%201%202%201&apos;%2F%3E%3Crect%20x%3D&apos;6&apos;%20y%3D&apos;5&apos;%20width%3D&apos;16&apos;%20height%3D&apos;18&apos;%20rx%3D&apos;1.5&apos;%20ry%3D&apos;1.5&apos;%2F%3E%3C%2Fsvg%3E&quot;);--ec-frm-trmIcon:url(&quot;data:image/svg+xml,%3Csvg%20xmlns%3D&apos;http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg&apos;%20viewBox%3D&apos;0%200%2060%2016&apos;%20preserveAspectRatio%3D&apos;xMidYMid%20meet&apos;%3E%3Ccircle%20cx%3D&apos;8&apos;%20cy%3D&apos;8&apos;%20r%3D&apos;8&apos;%2F%3E%3Ccircle%20cx%3D&apos;30&apos;%20cy%3D&apos;8&apos;%20r%3D&apos;8&apos;%2F%3E%3Ccircle%20cx%3D&apos;52&apos;%20cy%3D&apos;8&apos;%20r%3D&apos;8&apos;%2F%3E%3C%2Fsvg%3E&quot;)}.expressive-code .ec-line :where(span[style^=&apos;--&apos;]:not([class])){color:var(--0, inherit);background-color:var(--0bg, transparent);font-style:var(--0fs, inherit);font-weight:var(--0fw, inherit);text-decoration:var(--0td, inherit)}&lt;/style&gt;&lt;script type=&quot;module&quot; src=&quot;/_astro/ec.0vx5m.js&quot;&gt;&lt;/script&gt;&lt;figure class=&quot;frame has-title&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;SQL&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;sql&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;SELECT&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;*&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;FROM&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; posts&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;ORDER BY&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; created_at &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;DESC&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;LIMIT&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;20&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; OFFSET &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;SELECT *FROM postsORDER BY created_at DESCLIMIT 20 OFFSET 0;&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;এই query প্রথম দিকে দুর্দান্ত পারফর্ম করে। কিন্তু সমস্যা শুরু হয় যখন আপনার কোনো User বা Automated Crawler অনেক দূরের কোনো পেজে যাওয়ার চেষ্টা করে।&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame has-title&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;SQL&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;sql&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;SELECT&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;*&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;FROM&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; posts&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;ORDER BY&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; created_at &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;DESC&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;LIMIT&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;20&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; OFFSET &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;1000000&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;SELECT *FROM postsORDER BY created_at DESCLIMIT 20 OFFSET 1000000;&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;হঠাৎ করেই API-এর latency হু হু করে বাড়তে শুরু করে। Database CPU usage ১০০%-এ পৌঁছে যায় এবং একের পর এক রিকোয়েস্ট timeout হতে থাকে। আপনার মনে স্বাভাবিকভাবেই প্রশ্ন আসতে পারে, API তো মাত্র ২০টি row রিটার্ন করছে, তাহলে পেজ নাম্বার বাড়ার সঙ্গে সঙ্গে query এত slow হচ্ছে কেন? এখানে &lt;code&gt;LIMIT 20&lt;/code&gt; হওয়া সত্ত্বেও Database কেন এত বেশি কাজ করছে এবং Index থাকার পরেও কেন deep pagination এত expensive হতে পারে, সেটি বোঝা অত্যন্ত জরুরি।&lt;/p&gt;
&lt;figure&gt;&lt;img src=&quot;https://raw.githubusercontent.com/rafeuddaraj/rafes-blog-assets/refs/heads/cursor-pagination-under-the-hood/assets/offset-vs-cursor-workload.svg&quot; alt=&quot;Page 1 vs Page 50,000 DB Workload&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;800&quot; height=&quot;400&quot;&gt;&lt;figcaption&gt;Page 1 vs Page 50,000 DB Workload&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;এই পারফরম্যান্স ইনসিডেন্ট থেকেই আমরা Database-এর ভেতরে ঢুকে investigate করব এবং দেখব Cursor Pagination কীভাবে এই সমস্যার সমাধান করে।&lt;/p&gt;
&lt;h2 id=&quot;pagination-আসলে-কোন-problem-solve-করছে&quot;&gt;Pagination আসলে কোন Problem Solve করছে&lt;/h2&gt;
&lt;p&gt;Pagination-কে শুধুমাত্র একটি Frontend UI feature হিসেবে দেখলে এর মূল Engineering গুরুত্বটি হারিয়ে যায়। এটিকে মূলত Database এবং API scalability boundary হিসেবে দেখতে হবে। ধরুন আপনার সিস্টেমে ৫০,০০০,০০০ রেকর্ডস আছে। আপনি যদি একবারে সব data রিটার্ন করতে চান, তবে তিনটি বড় সংকট তৈরি হবে:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Database Memory ও I/O Saturation:&lt;/strong&gt; সম্পূর্ণ টেবিল মেমোরিতে লোড করতে গিয়ে Database-এর buffer pool নিঃশেষ হয়ে যাবে।&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Network Bandwidth Choke:&lt;/strong&gt; গিগাবাইট সাইজের JSON payload ট্রান্সফার করতে গিয়ে নেটওয়ার্ক পাইপলাইন জ্যাম হয়ে যাবে।&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Client-side Browser Crash:&lt;/strong&gt; ক্লায়েন্টের ব্রাউজার বা মোবাইল অ্যাপ এত বড় DOM/মেমোরি হ্যান্ডেল করতে না পেরে ফ্রিজ হয়ে যাবে।&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;এর বদলে আমরা পুরো dataset-কে ছোট ছোট ভাগে ভাগ করে রিটার্ন করি। Pagination-এর আসল লক্ষ্য হচ্ছে Database-এর bounded amount of work এবং API response-এর bounded size নিশ্চিত করা। যখন আমরা ২০টি রেকর্ডস রিটার্ন করার সিদ্ধান্ত নিই, তখন প্রশ্ন আসে &quot;কোন ২০টি রেকর্ডস?&quot;। এই প্রশ্নের উত্তর থেকেই Offset এবং Cursor-এর মতো স্ট্র্যাটেজি তৈরি হয়।&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;offset-pagination-এর-mental-model&quot;&gt;Offset Pagination-এর Mental Model&lt;/h2&gt;
&lt;p&gt;প্রথমে আমরা সেই মডেল নিয়ে কথা বলব যার সঙ্গে আমরা সবাই সবচেয়ে বেশি পরিচিত। Offset pagination-এর ক্ষেত্রে আমরা Database-কে বলি ঠিক কতগুলো row skip করতে হবে।&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame has-title&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;SQL&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;sql&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;SELECT&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;*&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;FROM&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; posts&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;ORDER BY&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; created_at &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;DESC&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;LIMIT&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;20&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; OFFSET &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;10000&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;SELECT *FROM postsORDER BY created_at DESCLIMIT 20 OFFSET 10000;&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;অনেকেই ভাবেন &lt;code&gt;OFFSET 10000&lt;/code&gt; মানে হচ্ছে Database সরাসরি ১০,০০০ নম্বর row-তে জাম্প বা teleport করে চলে যায়। কিন্তু বাস্তবে রিলেশনাল ডাটাবেজ এভাবে কাজ করে না।&lt;/p&gt;
&lt;figure&gt;&lt;img src=&quot;https://raw.githubusercontent.com/rafeuddaraj/rafes-blog-assets/refs/heads/cursor-pagination-under-the-hood/assets/offset-skipping-model.svg&quot; alt=&quot;The Offset Skipping Mental Model&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;800&quot; height=&quot;300&quot;&gt;&lt;figcaption&gt;The Offset Skipping Mental Model&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;বাস্তবে Database-কে ordered result-এর মধ্যে আগের ১০,০০০টি row একটি একটি করে স্ক্যান করতে হয়, মেমোরিতে এনে কাউন্ট করতে হয় এবং ফেলে দিতে হয় (discard)। এরপর ১০,০০১ নম্বর row থেকে শুরু করে &lt;code&gt;LIMIT 20&lt;/code&gt; অনুযায়ী পরবর্তী ২০টি রেকর্ডস রিটার্ন করতে হয়। অর্থাৎ ২০টি row পাওয়ার জন্য Database-কে আসলে ১০,০২০টি row প্রসেস করতে হয়েছে।&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;limit-আর-offset-আসলে-কীভাবে-আলাদা&quot;&gt;LIMIT আর OFFSET আসলে কীভাবে আলাদা&lt;/h2&gt;
&lt;p&gt;এই জায়গায় একটি অত্যন্ত গুরুত্বপূর্ণ mental model তৈরি করা প্রয়োজন। &lt;code&gt;LIMIT&lt;/code&gt; এবং &lt;code&gt;OFFSET&lt;/code&gt; সম্পূর্ণ ভিন্ন দুটি নির্দেশ দেয়।&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;LIMIT&lt;/code&gt; Database-কে বলে: &quot;সর্বোচ্চ কতগুলো row ক্লায়েন্টকে রিটার্ন করব?&quot;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;OFFSET&lt;/code&gt; Database-কে বলে: &quot;শুরুর আগে কতগুলো valid row পার হয়ে আসতে হবে?&quot;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;যখন আপনি &lt;code&gt;OFFSET 0&lt;/code&gt;, &lt;code&gt;OFFSET 100&lt;/code&gt;, এবং &lt;code&gt;OFFSET 1,000,000&lt;/code&gt; ব্যবহার করেন, তখন returned row count প্রতিবারই ২০ হলেও Database-এর কাজের পরিমাণ একদমই এক থাকে না। OFFSET যত বাড়বে, Database-কে তত বেশি row স্ক্যান করে মেমোরি থেকে ফেলে দিতে হবে, যা query-কে progressively slow করে দেয়।&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;database-execution-plan-এর-ভিতরে-ঢোকা&quot;&gt;Database Execution Plan-এর ভিতরে ঢোকা&lt;/h2&gt;
&lt;p&gt;SQL query শুধু একটি ডিক্লারেটিভ সিনট্যাক্স। Database ইঞ্জিন এটিকে ইন্টারনাল execution plan-এ রূপান্তর করে। PostgreSQL-এ &lt;code&gt;EXPLAIN ANALYZE&lt;/code&gt; দিয়ে এর আসল আচরণ লক্ষ্য করা যায়।&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame has-title&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;SQL&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;sql&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;EXPLAIN ANALYZE&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;SELECT&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;*&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;FROM&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; posts&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;ORDER BY&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; created_at &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;DESC&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;LIMIT&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;20&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; OFFSET &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;100000&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;EXPLAIN ANALYZESELECT *FROM postsORDER BY created_at DESCLIMIT 20 OFFSET 100000;&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;এই execution plan-এ Query Planner নিচের পাইপলাইন অনুযায়ী কাজ সম্পন্ন করে:&lt;/p&gt;
&lt;figure&gt;&lt;img src=&quot;https://raw.githubusercontent.com/rafeuddaraj/rafes-blog-assets/refs/heads/cursor-pagination-under-the-hood/assets/db-execution-pipeline.svg&quot; alt=&quot;Database Execution Pipeline&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;800&quot; height=&quot;400&quot;&gt;&lt;figcaption&gt;Database Execution Pipeline&lt;/figcaption&gt;&lt;/figure&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Access Path Selection:&lt;/strong&gt; Planner ঠিক করে সে Index Scan করবে নাকি Table Scan করবে।&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Tuple Retrieval:&lt;/strong&gt; ইন্ডেক্স ধরে ডিস্ক বা বাফার ক্যাশ থেকে ১,০০,০২০টি tuple পড়ে আনে।&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Traverse and Discard:&lt;/strong&gt; প্রথম ১,০০,০০০টি tuple মেমোরিতে কাউন্ট করে ডিসকার্ড করে দেয়।&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;LIMIT Slice:&lt;/strong&gt; অবশিষ্ট ২০টি tuple সংগ্রহ করে Final Output তৈরি করে।&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;আমরা যখন &lt;code&gt;EXPLAIN ANALYZE&lt;/code&gt; দেখি, তখন পরিষ্কার ধরা পড়ে যে Database বিপুল পরিমাণ ডিস্ক পেজ মেমোরিতে এনে CPU সাইকেল খরচ করেছে শুধুমাত্র অপ্রয়োজনীয় ডাটা ফেলে দেওয়ার জন্য।&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;index-থাকলে-কি-offset-problem-শেষ-হয়ে-যায়&quot;&gt;Index থাকলে কি OFFSET Problem শেষ হয়ে যায়&lt;/h2&gt;
&lt;p&gt;এটি Backend Engineering-এর একটি বহুল প্রচলিত misconception। অনেকেই ভাবেন &lt;code&gt;created_at&lt;/code&gt;-এর ওপর Index তৈরি করলেই deep pagination-এর সমস্যা চিরতরে সমাধান হয়ে যাবে।&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame has-title&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;SQL&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;sql&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;CREATE&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;INDEX&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D2A8FF&quot;&gt;idx_posts_created_at&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;ON&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; posts(created_at &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;DESC&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;CREATE INDEX idx_posts_created_atON posts(created_at DESC);&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Index ব্যবহারের ফলে Database-কে হয়তো পুরো Table sequential scan করতে হয় না, সে সরাসরি Index tree থেকে ordered entries পায়। কিন্তু &lt;code&gt;OFFSET&lt;/code&gt;-এর logical requirement কিন্তু শেষ হয়ে যায় না।&lt;/p&gt;
&lt;p&gt;Database-কে target position-এ পৌঁছানোর জন্য ইন্ডেক্স লিফ পেজগুলোর মধ্য দিয়ে আগের সবকটি এন্ট্রি traversal করতেই হয়। ফলে Index থাকার পরেও deep OFFSET-এর query execution time লিনিয়ারলি (Linearly) বাড়তে থাকে।&lt;/p&gt;
&lt;div class=&quot;callout&quot; role=&quot;note&quot; data-type=&quot;warning&quot;&gt;
&lt;p class=&quot;callout-title&quot;&gt;The O(N) Pagination Trap&lt;/p&gt;
&lt;p&gt;Index স্ক্যান দ্রুত হলেও Database-কে &lt;code&gt;OFFSET N&lt;/code&gt; পৌঁছানোর জন্য N সংখ্যক ইন্ডেক্স এন্ট্রি রিড করতে হয়। তাই Offset-based pagination মূলত O(N) complexity তৈরি করে, যা large dataset-এ catastrophic latency ডেকে আনে।&lt;/p&gt;
&lt;/div&gt;
&lt;hr&gt;
&lt;h2 id=&quot;deep-offset-কেন-production-problem-হয়ে-যায়&quot;&gt;Deep OFFSET কেন Production Problem হয়ে যায়&lt;/h2&gt;
&lt;p&gt;এখন একটি realistic production traffic scenario চিন্তা করুন। একজন সাধারণ ব্যবহারকারীর জন্য deep pagination হয়তো কদাচিৎ ঘটবে। কিন্তু যখন Search Engine Bots, Scrapers অথবা হাজার হাজার concurrent users deep page-গুলোতে রিকোয়েস্ট পাঠায়, তখন পরিস্থিতি নিয়ন্ত্রণের বাইরে চলে যায়।&lt;/p&gt;
&lt;figure&gt;&lt;img src=&quot;https://raw.githubusercontent.com/rafeuddaraj/rafes-blog-assets/refs/heads/cursor-pagination-under-the-hood/assets/concurrent-deep-offset.svg&quot; alt=&quot;Concurrent Deep Offset Workload&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;800&quot; height=&quot;400&quot;&gt;&lt;figcaption&gt;Concurrent Deep Offset Workload&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;একাধিক ব্যবহারকারীর deep OFFSET রিকোয়েস্ট Database Engine-এর ওপর ক্রমাগত heavy workload তৈরি করে। এর ফলে:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Database CPU usage ১০০%-এ পৌঁছায়।&lt;/li&gt;
&lt;li&gt;Connection Pool exhausted হয়ে যায়।&lt;/li&gt;
&lt;li&gt;নতুন lightweight রিকোয়েস্টগুলোও কিউতে আটকে যায় (Cascading Latency)।&lt;/li&gt;
&lt;li&gt;ক্লায়েন্ট টাইমআউট ফেস করে অটোমেটিক retry পাঠাতে থাকে, যা সিস্টেমে আরও বেশি লোড তৈরি করে ডেথ স্পাইরাল সৃষ্টি করে।&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id=&quot;cursor-pagination-এর-entry-point&quot;&gt;Cursor Pagination-এর Entry Point&lt;/h2&gt;
&lt;p&gt;Offset-এর এই fundamental limitation থেকেই জন্ম নেয় Cursor Pagination-এর ধারণা। আমরা যদি Database-কে না বলি কতগুলো row skip করতে হবে, বরং বলি &quot;আমি শেষবার কোথায় ছিলাম&quot;, তাহলে ডাটাবেজের কাজের ধরণ সম্পূর্ণ বদলে যায়।&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Offset Approach:&lt;/strong&gt; &quot;১০,০০০ rows পার হয়ে পরের ২০টা row দিন।&quot; (Database-কে ১০,০২০টা row দেখতে হয়)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Cursor Approach:&lt;/strong&gt; &quot;আমি এই নির্দিষ্ট record পর্যন্ত দেখেছি। এর পরের ২০টা row দিন।&quot; (Database সরাসরি সেই পয়েন্ট থেকে শুরু করে মাত্র ২০টি row রিড করে)&lt;/li&gt;
&lt;/ul&gt;
&lt;figure&gt;&lt;img src=&quot;https://raw.githubusercontent.com/rafeuddaraj/rafes-blog-assets/refs/heads/cursor-pagination-under-the-hood/assets/cursor-boundary-scan.svg&quot; alt=&quot;Cursor Boundary Range Scan&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;800&quot; height=&quot;300&quot;&gt;&lt;figcaption&gt;Cursor Boundary Range Scan&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;এটাই হচ্ছে Cursor Pagination-এর core architectural transition। ডাটাবেজকে হাজার হাজার রেকর্ডস স্ক্যান ও ডিসকার্ড করানোর বদলে আমরা একটি known boundary বা starting point ধরিয়ে দিই।&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;cursor-বনাম-database-cursor&quot;&gt;Cursor বনাম Database Cursor&lt;/h2&gt;
&lt;p&gt;এখানে পরিভাষাগত বিভ্রান্তি দূর করা অত্যন্ত গুরুত্বপূর্ণ। API Pagination-এর Cursor আর Database Engine-এর Internal Cursor এক জিনিস নয়।&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;API Cursor:&lt;/strong&gt; এটি একটি stateless token বা state representation, যা পেজিনেশনের বর্তমান পজিশন ধারণ করে ক্লায়েন্ট ও সার্ভারের মধ্যে আদান-প্রদান হয়।&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Database Cursor (PL/pgSQL / SQL Cursor):&lt;/strong&gt; এটি ডাটাবেজ সার্ভারের মেমোরিতে ওপেন থাকা একটি stateful connection-bound pointer, যা মেমোরি ধরে রাখে এবং দীর্ঘ সময় ওপেন রাখলে কানেকশন পুল নিঃশেষ হয়ে যায়।&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;আমরা যখন Web Application বা Distributed API ডিজাইন করি, তখন আমরা সবসময় &lt;strong&gt;Stateless API Cursor&lt;/strong&gt; ব্যবহার করি।&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;keyset-pagination-আসলে-কোথায়-আসে&quot;&gt;Keyset Pagination আসলে কোথায় আসে&lt;/h2&gt;
&lt;p&gt;Keyset Pagination এবং Cursor Pagination শব্দ দুটি অনেক সময় সমার্থকভাবে ব্যবহৃত হলেও এদের মধ্যে সূক্ষ্ম কাঠামোগত পার্থক্য রয়েছে।&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame has-title&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;SQL&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;sql&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;SELECT&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;*&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;FROM&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; posts&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;WHERE&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; id &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; :lastId&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;ORDER BY&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; id &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;DESC&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;LIMIT&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;20&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;SELECT *FROM postsWHERE id &lt; :lastIdORDER BY id DESCLIMIT 20;&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Keyset Pagination হলো Database লেভেলের query filtering স্ট্র্যাটেজি, যেখানে ordering column-এর মানকে &lt;code&gt;WHERE&lt;/code&gt; ক্লজে বাউন্ডারি হিসেবে ব্যবহার করা হয়। আর Cursor Pagination হলো API লেভেলের ট্রান্সপোর্ট মেকানিজম, যা এই Keyset ভ্যালুগুলোকে একটি সিকিউর এবং এনকোডেড টোকেন হিসেবে ক্লায়েন্টের কাছে পাঠায়।&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;stable-ordering-কেন-cursor-pagination-এর-core-requirement&quot;&gt;Stable Ordering কেন Cursor Pagination-এর Core Requirement&lt;/h2&gt;
&lt;p&gt;Cursor Pagination সফলভাবে কাজ করার জন্য সবচেয়ে মৌলিক শর্ত হলো Deterministic ও Stable Ordering। শুধু একটি non-unique কলাম দিয়ে &lt;code&gt;ORDER BY&lt;/code&gt; করলে বিপর্যয় ঘটতে পারে।&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame has-title&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;SQL&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;sql&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;ORDER BY&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; created_at &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;DESC&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;ORDER BY created_at DESC;&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;ধরুন তিনটি আলাদা পোস্ট একই সেকেন্ডে (১০:০০:০০) ডাটাবেজে ইনসার্ট হয়েছে। যেহেতু তাদের &lt;code&gt;created_at&lt;/code&gt; অভিন্ন, ডাটাবেজ ইঞ্জিনের কাছে এদের অভ্যন্তরীণ কোনো নির্দিষ্ট ক্রম নেই।&lt;/p&gt;
&lt;figure&gt;&lt;img src=&quot;https://raw.githubusercontent.com/rafeuddaraj/rafes-blog-assets/refs/heads/cursor-pagination-under-the-hood/assets/ambiguous-vs-deterministic-ordering.svg&quot; alt=&quot;Ambiguous vs Deterministic Ordering&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;800&quot; height=&quot;350&quot;&gt;&lt;figcaption&gt;Ambiguous vs Deterministic Ordering&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;ডাটাবেজ প্রথম পেজে কোন দুটি দেখাবে আর দ্বিতীয় পেজে কোনটি দেখাবে তার কোনো নিশ্চয়তা থাকে না। ফলে কিছু রেকর্ড ডুপ্লিকেট হিসেবে আসতে পারে অথবা চিরতরে বাদ পড়তে পারে। এই সমস্যা সমাধানের জন্য সবসময় একটি Unique কলামকে Tie-Breaker হিসেবে ব্যবহার করতে হয়।&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame has-title&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;SQL&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;sql&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;ORDER BY&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; created_at &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;DESC&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;, id &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;DESC&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;ORDER BY created_at DESC, id DESC;&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;এখানে &lt;code&gt;id&lt;/code&gt; গ্যারান্টি দেয় যে প্রতিটি row-এর পজিশন সম্পূর্ণ ইউনিক এবং ডিটারমিনিস্টিক।&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;composite-cursor-এবং-row-value-comparison&quot;&gt;Composite Cursor এবং Row Value Comparison&lt;/h2&gt;
&lt;p&gt;যখন পেজিনেশনে একাধিক কলামের ওপর সর্টিং করা হয় (যেমন &lt;code&gt;created_at&lt;/code&gt; এবং &lt;code&gt;id&lt;/code&gt;), তখন কার্সরে দুটি মানই অন্তর্ভুক্ত করতে হয়। একে &lt;strong&gt;Composite Cursor&lt;/strong&gt; বলা হয়।&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame has-title&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;SQL&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;sql&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;SELECT&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;*&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;FROM&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; posts&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;WHERE&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; (created_at, id) &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; (:createdAt, :id)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;ORDER BY&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; created_at &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;DESC&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;, id &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;DESC&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;LIMIT&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;20&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;SELECT *FROM postsWHERE (created_at, id) &lt; (:createdAt, :id)ORDER BY created_at DESC, id DESCLIMIT 20;&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;আধুনিক রিলেশনাল ডাটাবেজ (PostgreSQL, MySQL 8+) Row Value Comparison বা Tuple Comparison খুব চমৎকারভাবে সমর্থন করে। ডাটাবেজ প্রথমে &lt;code&gt;created_at&lt;/code&gt; তুলনা করে। যদি দুটি রো-এর &lt;code&gt;created_at&lt;/code&gt; সমান হয়, শুধুমাত্র তখনই সে &lt;code&gt;id&lt;/code&gt; তুলনা করে পরবর্তী রেকর্ডস ফিল্টার করে।&lt;/p&gt;
&lt;p&gt;যেসব ডাটাবেজ ইঞ্জিনে Tuple Syntax সাপোর্ট নেই, সেখানে সমতুল্য লজিক এভাবে লেখা হয়:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame has-title&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;SQL&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;sql&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;SELECT&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;*&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;FROM&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; posts&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;WHERE&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; created_at &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; :createdAt&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;   &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;OR&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; (created_at &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; :createdAt &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;AND&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; id &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; :id)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;ORDER BY&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; created_at &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;DESC&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;, id &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;DESC&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;LIMIT&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;20&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;SELECT *FROM postsWHERE created_at &lt; :createdAt   OR (created_at = :createdAt AND id &lt; :id)ORDER BY created_at DESC, id DESCLIMIT 20;&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;div class=&quot;callout&quot; role=&quot;note&quot; data-type=&quot;tip&quot;&gt;
&lt;p class=&quot;callout-title&quot;&gt;Row Value Syntax Support&lt;/p&gt;
&lt;p&gt;Row value comparison &lt;code&gt;(A, B) &amp;#x3C; (X, Y)&lt;/code&gt; কোডকে পরিষ্কার রাখে এবং SQL Query Optimizer-কে কম্পোজিট ইন্ডেক্স নিখুঁতভাবে ব্যবহার করার সুযোগ দেয়।&lt;/p&gt;
&lt;/div&gt;
&lt;hr&gt;
&lt;h2 id=&quot;composite-index-কেন-এখানে-critical&quot;&gt;Composite Index কেন এখানে Critical&lt;/h2&gt;
&lt;p&gt;সঠিক Index ছাড়া Keyset Query চালালে পারফরম্যান্স সুবিধার বদলে টেবিল স্ক্যান শুরু হয়ে যাবে। Cursor Query-এর filtering এবং ordering-এর সঙ্গে সামঞ্জস্য রেখে Composite Index তৈরি করা আবশ্যক।&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame has-title&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;SQL&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;sql&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;CREATE&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;INDEX&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D2A8FF&quot;&gt;idx_posts_cursor&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;ON&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; posts(created_at &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;DESC&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;, id &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;DESC&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;CREATE INDEX idx_posts_cursorON posts(created_at DESC, id DESC);&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;এই Index থাকার ফলে ডাটাবেজ ইঞ্জিনকে কোনো ডাটা সর্ট করতে হয় না এবং কোনো রো ডিসকার্ড করতে হয় না। ইঞ্জিন সরাসরি ইন্ডেক্স ট্রি থেকে কার্সরের exact boundary পয়েন্টে গিয়ে পরবর্তী ২০টি এন্ট্রি পিক করে নিয়ে আসে।&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;b-tree-এর-সঙ্গে-cursor-pagination-এর-connection&quot;&gt;B-Tree-এর সঙ্গে Cursor Pagination-এর Connection&lt;/h2&gt;
&lt;p&gt;রিলেশনাল ডাটাবেজের B-Tree ইন্ডেক্স মূলত একটি ব্যালান্সড ট্রি স্ট্রাকচার, যা ডাটাকে সর্বদা সর্টেড অবস্থায় সংরক্ষণ করে।&lt;/p&gt;
&lt;figure&gt;&lt;img src=&quot;https://raw.githubusercontent.com/rafeuddaraj/rafes-blog-assets/refs/heads/cursor-pagination-under-the-hood/assets/composite-btree-index.svg&quot; alt=&quot;Composite B-Tree Traversal&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;800&quot; height=&quot;400&quot;&gt;&lt;figcaption&gt;Composite B-Tree Traversal&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;B-Tree ইন্ডেক্সে কার্সর কুয়েরি কীভাবে এক্সিকিউট হয় লক্ষ্য করুন:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Tree Seek (O(log N)):&lt;/strong&gt; ডাটাবেজ রুট নোড থেকে বাইনারি সার্চের মতো নেমে কার্সর ভ্যালুর exact Leaf Node খুঁজে বের করে।&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Sequential Leaf Scan (O(K)):&lt;/strong&gt; লিফ নোডগুলো পরস্পরের সঙ্গে ডাবলি লিঙ্কড লিস্টের মতো যুক্ত থাকে। ডাটাবেজ শুধু সামনের দিকে পয়েন্টার ধরে ঠিক K সংখ্যক (LIMIT) রো পড়ে নেয়।&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;যেহেতু K এর মান নির্দিষ্ট (যেমন ২০), তাই টেবিলের সাইজ ১০ হাজার হোক বা ১০ কোটি হোক, এই কুয়েরির পারফরম্যান্স সর্বদা ফ্ল্যাট বা O(1) থাকে।&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;concurrent-insert-এবং-pagination-drift&quot;&gt;Concurrent INSERT এবং Pagination Drift&lt;/h2&gt;
&lt;p&gt;Offset Pagination-এর সবচেয়ে মারাত্মক ডাটা কনসিস্টেন্সি সমস্যা হলো &lt;strong&gt;Pagination Drift&lt;/strong&gt; বা Data Shifting।&lt;/p&gt;
&lt;figure&gt;&lt;img src=&quot;https://raw.githubusercontent.com/rafeuddaraj/rafes-blog-assets/refs/heads/cursor-pagination-under-the-hood/assets/pagination-drift-insert.svg&quot; alt=&quot;Pagination Drift from Concurrent Insert&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;800&quot; height=&quot;350&quot;&gt;&lt;figcaption&gt;Pagination Drift from Concurrent Insert&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;ধরুন একজন ইউজার পেজ ১ লোড করেছেন যেখানে Post A এবং Post B প্রদর্শিত হয়েছে। ঠিক এই মুহূর্তে আরেকজন ইউজার একটি নতুন পোস্ট ইনসার্ট করলেন (Post NEW)।&lt;/p&gt;
&lt;p&gt;এখন প্রথম ইউজার যখন পেজ ২ দেখার জন্য &lt;code&gt;LIMIT 2 OFFSET 2&lt;/code&gt; রিকোয়েস্ট পাঠাবেন, ডাটাবেজ নতুন রো যুক্ত হওয়ার কারণে পুরো ডেটাসেট এক ঘর পিছিয়ে দেবে। ফলে ইউজার পেজ ২-এ আবার Post B দেখতে পাবেন (Duplicate Record)। একইভাবে কোনো রো ডিলিট হলে একটি রেকর্ড পুরোপুরি মিস হয়ে যেতে পারে।&lt;/p&gt;
&lt;p&gt;Cursor Pagination এই ড্রিফট সমস্যা থেকে সম্পূর্ণ মুক্ত। কারণ এটি কোনো কাল্পনিক রো নাম্বারের ওপর নির্ভর করে না, বরং নির্দিষ্ট ডাটা ভ্যালুর বাউন্ডারি পয়েন্টকে লক করে ডাটা রিড করে।&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;immutable-বনাম-mutable-ordering&quot;&gt;Immutable বনাম Mutable Ordering&lt;/h2&gt;
&lt;p&gt;কার্সর পেজিনেশনের জন্য এমন কলাম বাছাই করা উচিত যার মান পরিবর্তনের সম্ভাবনা নেই (যেমন &lt;code&gt;id&lt;/code&gt; বা &lt;code&gt;created_at&lt;/code&gt;)। কিন্তু আপনি যদি পরিবর্তনশীল কলাম যেমন &lt;code&gt;updated_at&lt;/code&gt; দিয়ে সর্ট করেন:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame has-title&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;SQL&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;sql&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;ORDER BY&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; updated_at &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;DESC&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;, id &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;DESC&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;ORDER BY updated_at DESC, id DESC;&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;তখন একটি বিশেষ কনকারেন্সি ফাঁদ তৈরি হতে পারে:&lt;/p&gt;
&lt;figure&gt;&lt;img src=&quot;https://raw.githubusercontent.com/rafeuddaraj/rafes-blog-assets/refs/heads/cursor-pagination-under-the-hood/assets/mutable-ordering-shift.svg&quot; alt=&quot;Mutable Ordering Shift&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;800&quot; height=&quot;350&quot;&gt;&lt;figcaption&gt;Mutable Ordering Shift&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;ধরুন ইউজার পেজ ১ রিড করে Record B পর্যন্ত এসেছেন। এই অবস্থায় পেজ ৩-এ থাকা Record C আপডেট হয়ে গেল এবং তার &lt;code&gt;updated_at&lt;/code&gt; বেড়ে পেজ ১-এর ওপরে চলে গেল। এখন ইউজার যখন Record B থেকে পরবর্তী পেজ রিড করবেন, ডাটাবেজ B-এর পরবর্তী রেকর্ডস (Record D) রিটার্ন করবে। এর ফলে Record C চিরতরে স্কিপ হয়ে যাবে।&lt;/p&gt;
&lt;div class=&quot;callout&quot; role=&quot;note&quot; data-type=&quot;note&quot;&gt;
&lt;p class=&quot;callout-title&quot;&gt;Mutable Column Strategy&lt;/p&gt;
&lt;p&gt;পরিবর্তনশীল কলামে পেজিনেশন করতে হলে ক্লায়েন্টকে রিয়েল-টাইম ডাটা সিঙ্ক স্ট্র্যাটেজি অথবা স্ন্যাপশট আইসোলেশন বিবেচনা করতে হবে।&lt;/p&gt;
&lt;/div&gt;
&lt;hr&gt;
&lt;h2 id=&quot;api-তে-cursor-কীভাবে-কাজ-করে-opaque-cursors&quot;&gt;API-তে Cursor কীভাবে কাজ করে (Opaque Cursors)&lt;/h2&gt;
&lt;p&gt;প্রোডাকশন গ্রেড সিস্টেমে ক্লায়েন্টের কাছে ডাটাবেজের ইন্টারনাল স্কিমা ও কলামের মান সরাসরি প্রকাশ করা অনুচিত।&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame has-title&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;JSON&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;json&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#7EE787&quot;&gt;&quot;created_at&quot;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;&quot;2026-09-06T01:30:00Z&quot;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#7EE787&quot;&gt;&quot;id&quot;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;9842&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;{  &amp;#x22;created_at&amp;#x22;: &amp;#x22;2026-09-06T01:30:00Z&amp;#x22;,  &amp;#x22;id&amp;#x22;: 9842}&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;ক্লায়েন্টকে এই র ডাটা না পাঠিয়ে সার্ভার এটিকে একটি Opaque Token হিসেবে এনকোড করে পাঠায়:&lt;/p&gt;
&lt;figure&gt;&lt;img src=&quot;https://raw.githubusercontent.com/rafeuddaraj/rafes-blog-assets/refs/heads/cursor-pagination-under-the-hood/assets/opaque-cursor-architecture.svg&quot; alt=&quot;Opaque Cursor Architecture&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;800&quot; height=&quot;250&quot;&gt;&lt;figcaption&gt;Opaque Cursor Architecture&lt;/figcaption&gt;&lt;/figure&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame has-title&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;Text&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;text&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#e6edf3&quot;&gt;GET /api/v1/posts?cursor=eyJjcmVhdGVkX2F0IjoiMjAyNi0wOS0wNlQwMTozMDowMFoiLCJpZCI6OTg0Mn0=&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;GET /api/v1/posts?cursor=eyJjcmVhdGVkX2F0IjoiMjAyNi0wOS0wNlQwMTozMDowMFoiLCJpZCI6OTg0Mn0=&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;API সার্ভার রিকোয়েস্ট পাওয়ার পর টোকেনটি ডিকোড ও ভ্যালিডেট করে ইন্টারনাল SQL কুয়েরি তৈরি করে। এর ফলে পরবর্তীতে ডাটাবেজ স্কিমা বা পেজিনেশন লজিক পরিবর্তন করলেও পাবলিক API কন্ট্রাক্ট ভেঙে যায় না।&lt;/p&gt;
&lt;div class=&quot;callout&quot; role=&quot;note&quot; data-type=&quot;note&quot;&gt;
&lt;p class=&quot;callout-title&quot;&gt;Security Note&lt;/p&gt;
&lt;p&gt;Base64 হলো একটি এনকোডিং মেকানিজম, কোনো এনক্রিপশন নয়। টোকেন ডিকোড করলে এর ভেতরের মান যে কেউ দেখতে পারে। টোকেন টেম্পারিং বা সিকিউরিটি রিস্ক এড়াতে HMAC দিয়ে কার্সর সাইন করা অথবা এনক্রিপ্ট করা সর্বোত্তম অভ্যাস।&lt;/p&gt;
&lt;/div&gt;
&lt;hr&gt;
&lt;h2 id=&quot;hasnextpage-কীভাবে-বের-করবেন&quot;&gt;hasNextPage কীভাবে বের করবেন&lt;/h2&gt;
&lt;p&gt;ক্লায়েন্টকে জানানোর জন্য যে পরবর্তী পেজ আছে কি না, অনেকে আলাদাভাবে &lt;code&gt;COUNT(*)&lt;/code&gt; কুয়েরি চালান। কিন্তু বড় টেবিলে &lt;code&gt;COUNT(*)&lt;/code&gt; চালানো অত্যন্ত এক্সপেনসিভ। এর সবচেয়ে স্মার্ট সমাধান হলো &lt;strong&gt;LIMIT + 1 Trick&lt;/strong&gt;।&lt;/p&gt;
&lt;figure&gt;&lt;img src=&quot;https://raw.githubusercontent.com/rafeuddaraj/rafes-blog-assets/refs/heads/cursor-pagination-under-the-hood/assets/limit-plus-one-hasnextpage.svg&quot; alt=&quot;LIMIT Plus One Trick for hasNextPage&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;800&quot; height=&quot;350&quot;&gt;&lt;figcaption&gt;LIMIT Plus One Trick for hasNextPage&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;যদি পেজ সাইজ ২০ হয়, তবে ডাটাবেজ থেকে ২১টি রেকর্ডস কুয়েরি করুন (&lt;code&gt;LIMIT 21&lt;/code&gt;)।&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;যদি ডাটাবেজ ঠিক ২১টি রেকর্ডস রিটার্ন করে, তার মানে এখনও অতিরিক্ত ডাটা অবশিষ্ট আছে (&lt;code&gt;hasNextPage = true&lt;/code&gt;)। সার্ভার ২১তম রেকর্ডটি রেসপন্স থেকে বাদ দিয়ে প্রথম ২০টি রেকর্ড ক্লায়েন্টকে পাঠাবে এবং ২০তম রেকর্ডের ডাটা দিয়ে &lt;code&gt;next_cursor&lt;/code&gt; তৈরি করবে।&lt;/li&gt;
&lt;li&gt;যদি ডাটাবেজ ২০ বা তার কম রেকর্ডস রিটার্ন করে, তবে &lt;code&gt;hasNextPage = false&lt;/code&gt; এবং &lt;code&gt;next_cursor = null&lt;/code&gt;।&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id=&quot;forward-এবং-backward-pagination&quot;&gt;Forward এবং Backward Pagination&lt;/h2&gt;
&lt;p&gt;একটি পূর্ণাঙ্গ API-তে ব্যবহারকারীকে শুধু সামনের দিকে নয়, পেছনের পেজেও ফিরে যাওয়ার সুযোগ দিতে হয়।&lt;/p&gt;
&lt;figure&gt;&lt;img src=&quot;https://raw.githubusercontent.com/rafeuddaraj/rafes-blog-assets/refs/heads/cursor-pagination-under-the-hood/assets/forward-backward-pagination.svg&quot; alt=&quot;Forward and Backward Traversal&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;800&quot; height=&quot;250&quot;&gt;&lt;figcaption&gt;Forward and Backward Traversal&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;এর জন্য API রেসপন্সে দুটি কার্সর প্রদান করা হয়: &lt;code&gt;next_cursor&lt;/code&gt; এবং &lt;code&gt;prev_cursor&lt;/code&gt;।&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Forward Query:&lt;/strong&gt;&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame has-title&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;SQL&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;sql&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;WHERE&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; (created_at, id) &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; (:createdAt, :id)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;ORDER BY&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; created_at &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;DESC&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;, id &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;DESC&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;LIMIT&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;21&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;WHERE (created_at, id) &lt; (:createdAt, :id)ORDER BY created_at DESC, id DESCLIMIT 21;&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Backward Query:&lt;/strong&gt;&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame has-title&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;SQL&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;sql&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;WHERE&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; (created_at, id) &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; (:createdAt, :id)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;ORDER BY&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; created_at &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;ASC&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;, id &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;ASC&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;LIMIT&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;21&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;WHERE (created_at, id) &gt; (:createdAt, :id)ORDER BY created_at ASC, id ASCLIMIT 21;&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;ব্যাকওয়ার্ড কুয়েরির ক্ষেত্রে ডাটাবেজ থেকে এসেন্ডিং অর্ডারে ডাটা তুলে আনার পর অ্যাপ্লিকেশন লেয়ারে অ্যারেটিকে আবার রিভার্স করে ক্লায়েন্টের প্রত্যাশিত ক্রমে পাঠানো হয়।&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;filtering-এবং-sorting-এর-সঙ্গে-cursor&quot;&gt;Filtering এবং Sorting-এর সঙ্গে Cursor&lt;/h2&gt;
&lt;p&gt;বাস্তব জীবনের প্রোডাকশন API-তে ফিল্টারিং এবং ডাইনামিক সর্টিং থাকে:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame has-title&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;Text&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;text&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#e6edf3&quot;&gt;GET /api/v1/posts?author_id=42&amp;#x26;status=published&amp;#x26;sort=views&amp;#x26;cursor=...&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;GET /api/v1/posts?author_id=42&amp;#x26;status=published&amp;#x26;sort=views&amp;#x26;cursor=...&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;এখানে তিনটি বিষয় লক্ষ্য রাখতে হবে:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Composite Index Alignment:&lt;/strong&gt; ফিল্টার এবং সর্ট কলামের ওপর কম্পোজিট ইন্ডেক্স থাকতে হবে: &lt;code&gt;(author_id, status, views DESC, id DESC)&lt;/code&gt;।&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Context Binding:&lt;/strong&gt; ব্যবহারকারী যদি সর্ট অপশন পরিবর্তন করেন, তবে পূর্বের কার্সর আর কাজ করবে না। কার্সর টোকেনের ভেতরে কুয়েরি প্যারামিটার বা ফিল্টার হ্যাশ বাইন্ড করে রাখতে হয় যাতে ভুল সর্টে পুরনো কার্সর ব্যবহার করলে ভ্যালিডেশন এরর দেওয়া যায়।&lt;/li&gt;
&lt;/ol&gt;
&lt;hr&gt;
&lt;h2 id=&quot;distributed-system-এ-cursor-pagination&quot;&gt;Distributed System-এ Cursor Pagination&lt;/h2&gt;
&lt;p&gt;ডাটাবেজ যখন একাধিক Shard বা পার্টিশনে বিভক্ত থাকে (যেমন CockroachDB, Citus, বা Sharded MySQL), তখন গ্লোবাল পেজিনেশন পরিচালনা করা একটি চ্যালেঞ্জ।&lt;/p&gt;
&lt;figure&gt;&lt;img src=&quot;https://raw.githubusercontent.com/rafeuddaraj/rafes-blog-assets/refs/heads/cursor-pagination-under-the-hood/assets/distributed-cursor-merge.svg&quot; alt=&quot;Distributed Cursor Merge Sort&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;800&quot; height=&quot;350&quot;&gt;&lt;figcaption&gt;Distributed Cursor Merge Sort&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;প্রতিটি ডাটাবেজ শার্ড নিজস্ব লোকাল ইনডেক্স অনুযায়ী ordered ডাটা রিটার্ন করে। API গেটওয়ে বা মার্জ নোড একটি K-Way Merge Sort অ্যালগরিদম চালিয়ে শীর্ষ ২০টি রেকর্ডস নির্বাচন করে এবং একটি সমন্বিত &lt;strong&gt;Global Cursor&lt;/strong&gt; তৈরি করে ক্লায়েন্টকে পাঠায়।&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;performance-benchmark-এবং-production-architecture&quot;&gt;Performance Benchmark এবং Production Architecture&lt;/h2&gt;
&lt;p&gt;প্রোডাকশন ইনসিডেন্টে যখন একটি হাই-ট্রাফিক সিস্টেমকে Deep OFFSET থেকে Indexed Cursor Pagination-এ মাইগ্রেট করা হয়, তখন তার ফলাফল হয় অভাবনীয়।&lt;/p&gt;
&lt;figure&gt;&lt;img src=&quot;https://raw.githubusercontent.com/rafeuddaraj/rafes-blog-assets/refs/heads/cursor-pagination-under-the-hood/assets/incident-before-after.svg&quot; alt=&quot;Incident Architecture: Before vs After&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;800&quot; height=&quot;350&quot;&gt;&lt;figcaption&gt;Incident Architecture: Before vs After&lt;/figcaption&gt;&lt;/figure&gt;
&lt;figure&gt;&lt;img src=&quot;https://raw.githubusercontent.com/rafeuddaraj/rafes-blog-assets/refs/heads/cursor-pagination-under-the-hood/assets/latency-benchmark-graph.svg&quot; alt=&quot;Latency vs Pagination Depth&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;800&quot; height=&quot;400&quot;&gt;&lt;figcaption&gt;Latency vs Pagination Depth&lt;/figcaption&gt;&lt;/figure&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Offset Approach (O(N)):&lt;/strong&gt; পেজ গভীরতা বাড়ার সঙ্গে সঙ্গে p95 এবং p99 latency খাড়াভাবে উপরে উঠতে থাকে।&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Cursor Approach (O(1)):&lt;/strong&gt; প্রথম পেজ এবং দশ লাখ নম্বর পেজের রেসপন্স টাইম সম্পূর্ণ সমান এবং ৫০ms-এর নিচে ফ্ল্যাট থাকে।&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&quot;callout&quot; role=&quot;note&quot; data-type=&quot;note&quot;&gt;
&lt;p class=&quot;callout-title&quot;&gt;Random Page Access Trade-off&lt;/p&gt;
&lt;p&gt;Cursor Pagination-এর একমাত্র সীমাবদ্ধতা হলো এটি সরাসরি &quot;Jump to page 5000&quot;-এর মতো র্যান্ডম অ্যাক্সেস সমর্থন করে না। ছোট ডেটাসেট বা ব্যাকঅফিস অ্যাডমিন প্যানেলে যেখানে পেজ নাম্বারে জাম্প করার প্রয়োজন হয়, সেখানে অফসেট ব্যবহার করা যৌক্তিক। কিন্তু ইনফিনিট স্ক্রল, ফিড বা হাই-স্কেল পাবলিক API-তে কার্সর পেজিনেশনই একমাত্র স্ট্যান্ডার্ড সমাধান।&lt;/p&gt;
&lt;/div&gt;
&lt;hr&gt;
&lt;h2 id=&quot;final-mental-model-ও-production-checklist&quot;&gt;Final Mental Model ও Production Checklist&lt;/h2&gt;
&lt;p&gt;পুরো আর্কিটেকচারের মূল সূত্রটি মনে রাখুন:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The Scalability Equation:&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Deterministic Order + Matching Composite Index + Keyset Boundary + Bounded LIMIT = O(1) Scalable Pagination।&lt;/p&gt;
&lt;figure&gt;&lt;img src=&quot;https://raw.githubusercontent.com/rafeuddaraj/rafes-blog-assets/refs/heads/cursor-pagination-under-the-hood/assets/production-api-lifecycle.svg&quot; alt=&quot;Production API Request Lifecycle&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;800&quot; height=&quot;500&quot;&gt;&lt;figcaption&gt;Production API Request Lifecycle&lt;/figcaption&gt;&lt;/figure&gt;
&lt;h3 id=&quot;আপনার-production-readiness-checklist&quot;&gt;আপনার Production Readiness Checklist&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Deterministic Tie-Breaker:&lt;/strong&gt; &lt;code&gt;ORDER BY&lt;/code&gt; ক্লজে সবসময় একটি ইউনিক কলাম (যেমন &lt;code&gt;id&lt;/code&gt; বা &lt;code&gt;uuid_v7&lt;/code&gt;) যুক্ত করুন।&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Matching Index:&lt;/strong&gt; কুয়েরির &lt;code&gt;WHERE&lt;/code&gt; এবং &lt;code&gt;ORDER BY&lt;/code&gt; ক্লজের কলাম ক্রমানুসারে কম্পোজিট ইন্ডেক্স তৈরি করুন।&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Opaque Tokens:&lt;/strong&gt; ইন্টারনাল ডাটাবেজ স্টেট হাইড করে Base64/HMAC সাইনড কার্সর টোকেন ব্যবহার করুন।&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;LIMIT + 1 Pattern:&lt;/strong&gt; আলাদা &lt;code&gt;COUNT(*)&lt;/code&gt; কুয়েরি পরিহার করে &lt;code&gt;LIMIT + 1&lt;/code&gt; দিয়ে &lt;code&gt;hasNextPage&lt;/code&gt; নির্ধারণ করুন।&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Context Validation:&lt;/strong&gt; ক্লায়েন্ট ফিল্টার বা সর্ট পরিবর্তন করলে পুরনো কার্সর রিজেক্ট করার লজিক রাখুন।&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Immutable Sort Fields:&lt;/strong&gt; সম্ভব হলে অপরিবর্তনশীল কলাম দিয়ে পেজিনেশন সর্ট করুন।&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;EXPLAIN Verification:&lt;/strong&gt; কুয়েরি প্রোডাকশনে দেওয়ার আগে &lt;code&gt;EXPLAIN ANALYZE&lt;/code&gt; চালিয়ে নিশ্চিত করুন যে এটি Index Scan করছে এবং কোনো অপ্রয়োজনীয় রো ডিসকার্ড করছে না।&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Cursor Pagination শুধুমাত্র একটি API প্যাটার্ন নয়। এটি ডাটাবেজ ইঞ্জিনকে বাউন্ডেড এবং ইন্ডেক্স-ফ্রেন্ডলি উপায়ে ব্যবহার করার একটি শক্তিশালী সিস্টেম আর্কিটেকচার।&lt;/p&gt;</content:encoded><category>Software Architecture</category><category>Database</category><category>PostgreSQL</category><category>System Design</category><category>Backend</category><category>API Architecture</category><category>Performance Optimization</category></item><item><title>How Database Connection Pools Actually Work Under the Hood (A Deep Dive)</title><link>https://www.rafeuddaraj.me/bn/blog/how-database-connection-pools-work-under-the-hood/</link><guid isPermaLink="true">https://www.rafeuddaraj.me/bn/blog/how-database-connection-pools-work-under-the-hood/</guid><description>ডাটাবেজ কানেকশন পুল কীভাবে কাজ করে, কেন ট্রাফিক বাড়লে সিস্টেম ক্র্যাশ করে এবং প্রোডাকশন স্কেলে কানেকশন ম্যানেজমেন্টের আর্কিটেকচার নিয়ে একটি কমপ্লিট ডিপ-ডাইভ গাইড।</description><pubDate>Fri, 04 Sep 2026 03:22:00 GMT</pubDate><content:encoded>&lt;p&gt;ধরুন আপনার একটি হাই-ট্রাফিক production application চলছে। হঠাৎ করে আপনি দেখলেন API response time 50ms থেকে লাফ দিয়ে 3 বা 4 seconds হয়ে গেছে। সিস্টেমের অ্যালার্ট বাজতে শুরু করেছে। আপনার প্রথম চিন্তা হতে পারে, &quot;নিশ্চয়ই Database slow হয়ে গেছে।&quot;&lt;/p&gt;
&lt;p&gt;আপনি দ্রুত Database-এর ড্যাশবোর্ড চেক করলেন। কিন্তু দেখলেন Database-এর CPU usage স্বাভাবিক, Memory-ও ঠিক আছে, এবং Disk I/O-তে কোনো অস্বাভাবিকতা নেই। এরপর আপনি Application server-এর দিকে তাকালেন, সেখানেও CPU বা Memory-তে কোনো বড় স্পাইক নেই।&lt;/p&gt;
&lt;p&gt;তাহলে request আসলে কোথায় আটকে আছে?&lt;/p&gt;
&lt;figure&gt;&lt;img src=&quot;https://raw.githubusercontent.com/rafeuddaraj/rafes-blog-assets/refs/heads/how-database-connection-pools-work-under-the-hood/assets/production-bottleneck.svg&quot; alt=&quot;The Hidden Production Bottleneck&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;800&quot; height=&quot;400&quot;&gt;&lt;figcaption&gt;The Hidden Production Bottleneck&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;এখান থেকেই আমাদের আজকের deep dive শুরু হবে। অনেক সময় application-এর আসল bottleneck Database-এর query execution টাইম নয়, বরং Database Connection পাওয়ার জন্য request-এর waiting টাইম। আজ আমরা ধাপে ধাপে দেখব Database Connection Pool আসলে কীভাবে কাজ করে, কেন এটি scale করা কঠিন, এবং কীভাবে আপনি আপনার সিস্টেমের এই hidden bottleneck খুঁজে বের করবেন।&lt;/p&gt;
&lt;h2 id=&quot;mental-model-database-connection-আসলে-কী&quot;&gt;Mental Model: Database Connection আসলে কী?&lt;/h2&gt;
&lt;p&gt;Database Connection-কে শুধু একটি সাধারণ TCP socket ভাবলে পুরো বিষয়টি পরিষ্কার হবে না। Application যখন Database-এর সঙ্গে নতুন একটি Connection তৈরি করে, তখন পর্দার আড়ালে অনেকগুলো expensive operation ঘটে।&lt;/p&gt;
&lt;p&gt;প্রথমে একটি TCP 3-way handshake সম্পন্ন হয়। সিকিউরিটির জন্য এরপর TLS handshake সম্পন্ন হয় যেখানে সার্টিফিকেট ভ্যালিডেশন এবং সিমেট্রিক কি নেগোসিয়েশন ঘটে। তারপর Database-লেভেলে authentication এবং authorization চলে। Authentication সফল হলে Database নিজের মেমোরিতে এই সেশনের জন্য dedicated memory context allocate করে।&lt;/p&gt;
&lt;figure&gt;&lt;img src=&quot;https://raw.githubusercontent.com/rafeuddaraj/rafes-blog-assets/refs/heads/how-database-connection-pools-work-under-the-hood/assets/connection-lifecycle.svg&quot; alt=&quot;Database Connection Creation Lifecycle&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;800&quot; height=&quot;300&quot;&gt;&lt;figcaption&gt;Database Connection Creation Lifecycle&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;এই পুরো প্রক্রিয়াটি অত্যন্ত সময়সাপেক্ষ এবং resource-intensive। প্রতিটি request-এর জন্য যদি অ্যাপ্লিকেশনকে এই পুরো সাইকেলটি পার হতে হয়, তবে application-এর latency মারাত্মক হারে বেড়ে যাবে।&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;pool-ছাড়া-architecture-এর-সমস্যা&quot;&gt;Pool ছাড়া Architecture-এর সমস্যা&lt;/h2&gt;
&lt;p&gt;প্রথমে কল্পনা করুন একটি naive architecture, যেখানে কোনো Connection Pool নেই। প্রতিটি incoming request ডাটাবেজে কথা বলার জন্য সম্পূর্ণ নতুন একটি Connection তৈরি করছে।&lt;/p&gt;
&lt;figure&gt;&lt;img src=&quot;https://raw.githubusercontent.com/rafeuddaraj/rafes-blog-assets/refs/heads/how-database-connection-pools-work-under-the-hood/assets/no-pool-architecture.svg&quot; alt=&quot;Architecture Without Connection Pool&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;800&quot; height=&quot;400&quot;&gt;&lt;figcaption&gt;Architecture Without Connection Pool&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;যখন ট্রাফিক কম থাকে, তখন এটি ঠিকঠাক কাজ করে। কিন্তু ট্রাফিক বাড়ার সঙ্গে সঙ্গে Connection তৈরির সংখ্যাও জ্যামিতিক হারে বাড়তে থাকে। কয়েকশ বা কয়েক হাজার concurrent request এলে Database-এর ওপর query execution-এর চেয়ে Connection creation-এর pressure অনেক বেশি পড়ে যায়। একপর্যায়ে ডাটাবেজ নতুন Connection নেওয়া বন্ধ করে দেয় এবং application crash করে।&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;connection-pool-এর-মূল-idea&quot;&gt;Connection Pool-এর মূল Idea&lt;/h2&gt;
&lt;p&gt;উপরের সমস্যাটি সমাধানের জন্যই Connection Pool-এর জন্ম। Connection Pool মূলত আগে থেকে কিছু Database Connection তৈরি করে রাখে। এটি একটি shared reusable resource manager হিসেবে কাজ করে।&lt;/p&gt;
&lt;figure&gt;&lt;img src=&quot;https://raw.githubusercontent.com/rafeuddaraj/rafes-blog-assets/refs/heads/how-database-connection-pools-work-under-the-hood/assets/pool-concept.svg&quot; alt=&quot;Connection Pool Reusability Concept&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;800&quot; height=&quot;350&quot;&gt;&lt;figcaption&gt;Connection Pool Reusability Concept&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;কোনো request-এর যখন Database access প্রয়োজন হয়, তখন সে নতুন Connection তৈরি না করে Pool থেকে একটি existing Connection ধার নেয়। ডাটাবেজের কাজ শেষ হলে request সেই Connection-টি destroy না করে আবার Pool-এ ফেরত দেয়। ফলে একটিমাত্র Connection সারাদিনে হাজার হাজার request sequentially প্রসেস করতে পারে।&lt;/p&gt;
&lt;p&gt;এখানে একটি চমৎকার Analogy দেওয়া যেতে পারে। ধরুন আপনি একটি লাইব্রেরিতে গেছেন। লাইব্রেরিতে পড়ার জন্য ১০টি চেয়ার আছে। আপনি একটি চেয়ারে বসে পড়লেন। পড়া শেষ হলে আপনি চেয়ারটি ভেঙে ফেলেন না, বরং চেয়ারটি ছেড়ে দেন যাতে অন্য কেউ বসতে পারে। Connection Pool ঠিক এভাবেই কাজ করে।&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;pool-এর-ভিতরের-architecture&quot;&gt;Pool-এর ভিতরের Architecture&lt;/h2&gt;
&lt;p&gt;একটি real-world Connection Pool-এর internal state বেশ জটিল হতে পারে। Pool মূলত চার ধরনের state manage করে: &lt;code&gt;min connections&lt;/code&gt;, &lt;code&gt;max connections&lt;/code&gt;, &lt;code&gt;idle connections&lt;/code&gt;, এবং &lt;code&gt;active connections&lt;/code&gt;।&lt;/p&gt;
&lt;figure&gt;&lt;img src=&quot;https://raw.githubusercontent.com/rafeuddaraj/rafes-blog-assets/refs/heads/how-database-connection-pools-work-under-the-hood/assets/pool-internal-state.svg&quot; alt=&quot;Connection Pool Internal State&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;800&quot; height=&quot;400&quot;&gt;&lt;figcaption&gt;Connection Pool Internal State&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;Pool শুধু Connection জমিয়ে রাখে না, এটি Connection allocation এবং release-এর lifecycle নিঁখুতভাবে পরিচালনা করে। এর মধ্যে সবচেয়ে গুরুত্বপূর্ণ parameter হচ্ছে &lt;code&gt;max connections&lt;/code&gt;, যা নির্ধারণ করে আপনার application একই সঙ্গে সর্বোচ্চ কতগুলো ডাটাবেজ অপারেশন চালাতে পারবে।&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;connection-acquire-এবং-hidden-queue&quot;&gt;Connection Acquire এবং Hidden Queue&lt;/h2&gt;
&lt;p&gt;যখন কোনো request ডাটাবেজে কথা বলতে চায়, তখন সে প্রথমে Pool-এর কাছে Connection চায় (&lt;code&gt;pool.acquire()&lt;/code&gt;)। Pool চেক করে তার কাছে কোনো Idle Connection আছে কি না। থাকলে সেটি সাথে সাথে request-কে দিয়ে দেওয়া হয়।&lt;/p&gt;
&lt;p&gt;যদি কোনো Idle Connection না থাকে, তখন Pool দেখে নতুন Connection তৈরি করার capacity (অর্থাৎ &lt;code&gt;max connections&lt;/code&gt; লিমিট ক্রস করেছে কি না) আছে কি না। Capacity থাকলে নতুন Connection তৈরি হয়। কিন্তু যদি Capacity শেষ হয়ে যায়, তখন request-টি একটি hidden waiting queue-তে চলে যায়।&lt;/p&gt;
&lt;figure&gt;&lt;img src=&quot;https://raw.githubusercontent.com/rafeuddaraj/rafes-blog-assets/refs/heads/how-database-connection-pools-work-under-the-hood/assets/connection-acquire-flow.svg&quot; alt=&quot;Connection Acquire Flowchart&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;800&quot; height=&quot;500&quot;&gt;&lt;figcaption&gt;Connection Acquire Flowchart&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;এই queue-টিই হাই-ট্রাফিক সিস্টেমে latency-এর মূল কারণ হয়ে দাঁড়ায়। যখন ১০০টি রিকোয়েস্ট একই সঙ্গে আসে এবং পুলের সাইজ মাত্র ১০, তখন ৯০টি রিকোয়েস্ট লাইনে দাঁড়িয়ে থাকে।&lt;/p&gt;
&lt;figure&gt;&lt;img src=&quot;https://raw.githubusercontent.com/rafeuddaraj/rafes-blog-assets/refs/heads/how-database-connection-pools-work-under-the-hood/assets/pool-hidden-queue.svg&quot; alt=&quot;Connection Pool Hidden Queue Under High Load&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;800&quot; height=&quot;400&quot;&gt;&lt;figcaption&gt;Connection Pool Hidden Queue Under High Load&lt;/figcaption&gt;&lt;/figure&gt;
&lt;div class=&quot;callout&quot; role=&quot;note&quot; data-type=&quot;tip&quot;&gt;
&lt;p class=&quot;callout-title&quot;&gt;Tip&lt;/p&gt;
&lt;p&gt;Queue-তে request বেশিক্ষণ আটকে থাকলে API response slow হয়ে যায়। তাই observability টুলে সব সময় Pool-এর waiting queue সাইজ এবং acquisition latency মনিটর করবেন।&lt;/p&gt;
&lt;/div&gt;
&lt;hr&gt;
&lt;h2 id=&quot;connection-release-বনাম-close&quot;&gt;Connection Release বনাম Close&lt;/h2&gt;
&lt;p&gt;Query শেষ হওয়ার পর Connection সাধারণত &lt;code&gt;close()&lt;/code&gt; করা হয় না, বরং &lt;code&gt;release()&lt;/code&gt; করা হয়। এর মানে হলো Connection-টি ডাটাবেজ থেকে সম্পূর্ণ বিচ্ছিন্ন না হয়ে আবার Pool-এর Idle state-এ ফিরে যায়।&lt;/p&gt;
&lt;p&gt;ডেভেলপারদের জন্য এটি একটি অত্যন্ত গুরুত্বপূর্ণ কনসেপ্ট। কোডে কোনো exception ঘটলে Connection যদি ঠিকমতো release না হয়, তবে সেটি Pool থেকে চিরতরে হারিয়ে যায় (যাকে আমরা Connection Leak বলি)।&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;style&gt;.expressive-code{font-family:var(--ec-uiFontFml);font-size:var(--ec-uiFontSize);font-weight:var(--ec-uiFontWg);line-height:var(--ec-uiLineHt);text-size-adjust:none;-webkit-text-size-adjust:none}.expressive-code *:not(:is(svg, svg *)){all:revert;box-sizing:border-box}.expressive-code pre{display:flex;margin:0;padding:0;border:var(--ec-brdWd) solid var(--ec-brdCol);border-radius:calc(var(--ec-brdRad) + var(--ec-brdWd));background:var(--ec-codeBg)}.expressive-code pre:focus-visible{outline:3px solid var(--ec-focusBrd);outline-offset:-3px}.expressive-code pre &gt; code{all:unset;display:block;flex:1 0 100%;padding:var(--ec-codePadBlk) 0;color:var(--ec-codeFg);font-family:var(--ec-codeFontFml);font-size:var(--ec-codeFontSize);font-weight:var(--ec-codeFontWg);line-height:var(--ec-codeLineHt)}.expressive-code pre{overflow-x:auto}.expressive-code pre.wrap .ec-line .code{white-space:pre-wrap;overflow-wrap:break-word;min-width:min(20ch, var(--ecMaxLine, 20ch))}.expressive-code pre.wrap .ec-line .code span.indent{white-space:pre}.expressive-code pre::-webkit-scrollbar,.expressive-code pre::-webkit-scrollbar-track{background-color:inherit;border-radius:calc(var(--ec-brdRad) + var(--ec-brdWd));border-top-left-radius:0;border-top-right-radius:0}.expressive-code pre::-webkit-scrollbar-thumb{background-color:var(--ec-sbThumbCol);border:4px solid transparent;background-clip:content-box;border-radius:10px}.expressive-code pre::-webkit-scrollbar-thumb:hover{background-color:var(--ec-sbThumbHoverCol)}.expressive-code pre::-webkit-scrollbar-corner{background:transparent}.expressive-code .ec-line{direction:ltr;unicode-bidi:isolate;display:grid;grid-template-areas:&apos;gutter code&apos;;grid-template-columns:auto 1fr;position:relative}.expressive-code .ec-line .gutter{grid-area:gutter;color:var(--ec-gtrFg)}.expressive-code .ec-line .gutter &gt; *{pointer-events:none;user-select:none;-webkit-user-select:none}.expressive-code .ec-line .gutter ~ .code{--ecLineBrdCol:var(--ec-gtrBrdCol)}.expressive-code .ec-line.highlight .gutter{color:var(--ec-gtrHlFg)}.expressive-code .ec-line .code{grid-area:code;position:relative;box-sizing:content-box;padding-inline-start:calc(var(--ecIndent, 0ch) + var(--ec-codePadInl) - var(--ecGtrBrdWd));padding-inline-end:var(--ec-codePadInl);text-indent:calc(var(--ecIndent, 0ch) * -1)}.expressive-code .ec-line .code::before,.expressive-code .ec-line .code::after,.expressive-code .ec-line .code :where(*){text-indent:0}.expressive-code .ec-line .code{--ecGtrBrdWd:var(--ec-gtrBrdWd);border-inline-start:var(--ecGtrBrdWd) solid var(--ecLineBrdCol, transparent)}.expressive-code .sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0, 0, 0, 0);white-space:nowrap;border-width:0}.expressive-code .ec-line.mark{--tmLineBgCol:var(--ec-tm-markBg)}.expressive-code .ec-line.mark .code{--ecLineBrdCol:var(--ec-tm-markBrdCol)}.expressive-code .ec-line.ins{--tmLineBgCol:var(--ec-tm-insBg);--tmLabel:var(--ec-tm-insDiffIndContent)}.expressive-code .ec-line.ins .code{--ecLineBrdCol:var(--ec-tm-insBrdCol)}.expressive-code .ec-line.ins .code::before{color:var(--ec-tm-insDiffIndCol)}.expressive-code .ec-line.del{--tmLineBgCol:var(--ec-tm-delBg);--tmLabel:var(--ec-tm-delDiffIndContent)}.expressive-code .ec-line.del .code{--ecLineBrdCol:var(--ec-tm-delBrdCol)}.expressive-code .ec-line.del .code::before{color:var(--ec-tm-delDiffIndCol)}.expressive-code .ec-line.mark,.expressive-code .ec-line.ins,.expressive-code .ec-line.del{background:var(--tmLineBgCol)}.expressive-code .ec-line.mark .code,.expressive-code .ec-line.ins .code,.expressive-code .ec-line.del .code{--ecGtrBrdWd:var(--ec-tm-lineMarkerAccentWd)}.expressive-code .ec-line.mark .code::before,.expressive-code .ec-line.ins .code::before,.expressive-code .ec-line.del .code::before{display:block;position:absolute;left:0;box-sizing:border-box;content:var(--tmLabel, &apos; &apos;);padding-inline-start:var(--ec-tm-lineDiffIndMargLeft);text-align:center;white-space:pre}.expressive-code .ec-line.mark.tm-label .code::before,.expressive-code .ec-line.ins.tm-label .code::before,.expressive-code .ec-line.del.tm-label .code::before{background:var(--ecLineBrdCol);padding:0 calc(var(--ec-tm-lineMarkerLabelPadInl) + var(--ec-tm-lineMarkerAccentWd)) 0 var(--ec-tm-lineMarkerLabelPadInl);color:var(--ec-tm-lineMarkerLabelCol)}.expressive-code .ec-line mark{--tmInlineBgCol:var(--ec-tm-markBg);--tmInlineBrdCol:var(--ec-tm-markBrdCol)}.expressive-code .ec-line ins{--tmInlineBgCol:var(--ec-tm-insBg);--tmInlineBrdCol:var(--ec-tm-insBrdCol)}.expressive-code .ec-line del{--tmInlineBgCol:var(--ec-tm-delBg);--tmInlineBrdCol:var(--ec-tm-delBrdCol)}.expressive-code .ec-line mark,.expressive-code .ec-line ins,.expressive-code .ec-line del{all:unset;display:inline-block;position:relative;--tmBrdL:var(--ec-tm-inlMarkerBrdWd);--tmBrdR:var(--ec-tm-inlMarkerBrdWd);--tmRadL:var(--ec-tm-inlMarkerBrdRad);--tmRadR:var(--ec-tm-inlMarkerBrdRad);margin-inline:0.025rem;padding-inline:var(--ec-tm-inlMarkerPad);border-radius:var(--tmRadL) var(--tmRadR) var(--tmRadR) var(--tmRadL);background:var(--tmInlineBgCol);background-clip:padding-box}.expressive-code .ec-line mark.open-start,.expressive-code .ec-line ins.open-start,.expressive-code .ec-line del.open-start{margin-inline-start:0;padding-inline-start:0;--tmBrdL:0px;--tmRadL:0}.expressive-code .ec-line mark.open-end,.expressive-code .ec-line ins.open-end,.expressive-code .ec-line del.open-end{margin-inline-end:0;padding-inline-end:0;--tmBrdR:0px;--tmRadR:0}.expressive-code .ec-line mark::before,.expressive-code .ec-line ins::before,.expressive-code .ec-line del::before{content:&apos;&apos;;position:absolute;pointer-events:none;display:inline-block;inset:0;border-radius:var(--tmRadL) var(--tmRadR) var(--tmRadR) var(--tmRadL);border:var(--ec-tm-inlMarkerBrdWd) solid var(--tmInlineBrdCol);border-inline-width:var(--tmBrdL) var(--tmBrdR)}.expressive-code .frame{all:unset;position:relative;display:block;--header-border-radius:calc(var(--ec-brdRad) + var(--ec-brdWd));--tab-border-radius:calc(var(--ec-frm-edTabBrdRad) + var(--ec-brdWd));--button-spacing:0.4rem;--code-background:var(--ec-frm-edBg);border-radius:var(--header-border-radius);box-shadow:var(--ec-frm-frameBoxShdCssVal)}.expressive-code .frame .header{display:none;z-index:1;position:relative;border-radius:var(--header-border-radius) var(--header-border-radius) 0 0}.expressive-code .frame.has-title pre,.expressive-code .frame.has-title code,.expressive-code .frame.is-terminal pre,.expressive-code .frame.is-terminal code{border-top:none;border-top-left-radius:0;border-top-right-radius:0}.expressive-code .frame .title:empty:before{content:&apos;\a0&apos;}.expressive-code .frame.has-title:not(.is-terminal){--button-spacing:calc(1.9rem + 2 * (var(--ec-uiPadBlk) + var(--ec-frm-edActTabIndHt)))}.expressive-code .frame.has-title:not(.is-terminal) .title{position:relative;color:var(--ec-frm-edActTabFg);background:var(--ec-frm-edActTabBg);background-clip:padding-box;margin-block-start:var(--ec-frm-edTabsMargBlkStart);padding:calc(var(--ec-uiPadBlk) + var(--ec-frm-edActTabIndHt)) var(--ec-uiPadInl);border:var(--ec-brdWd) solid var(--ec-frm-edActTabBrdCol);border-radius:var(--tab-border-radius) var(--tab-border-radius) 0 0;border-bottom:none;overflow:hidden}.expressive-code .frame.has-title:not(.is-terminal) .title::after{content:&apos;&apos;;position:absolute;pointer-events:none;inset:0;border-top:var(--ec-frm-edActTabIndHt) solid var(--ec-frm-edActTabIndTopCol);border-bottom:var(--ec-frm-edActTabIndHt) solid var(--ec-frm-edActTabIndBtmCol)}.expressive-code .frame.has-title:not(.is-terminal) .header{display:flex;background:linear-gradient(to top, var(--ec-frm-edTabBarBrdBtmCol) var(--ec-brdWd), transparent var(--ec-brdWd)),linear-gradient(var(--ec-frm-edTabBarBg), var(--ec-frm-edTabBarBg));background-repeat:no-repeat;padding-inline-start:var(--ec-frm-edTabsMargInlStart)}.expressive-code .frame.has-title:not(.is-terminal) .header::before{content:&apos;&apos;;position:absolute;pointer-events:none;inset:0;border:var(--ec-brdWd) solid var(--ec-frm-edTabBarBrdCol);border-radius:inherit;border-bottom:none}.expressive-code .frame.is-terminal{--button-spacing:calc(1.9rem + var(--ec-brdWd) + 2 * var(--ec-uiPadBlk));--code-background:var(--ec-frm-trmBg)}.expressive-code .frame.is-terminal .header{display:flex;align-items:center;justify-content:center;padding-block:var(--ec-uiPadBlk);padding-block-end:calc(var(--ec-uiPadBlk) + var(--ec-brdWd));position:relative;font-weight:500;letter-spacing:0.025ch;color:var(--ec-frm-trmTtbFg);background:var(--ec-frm-trmTtbBg);border:var(--ec-brdWd) solid var(--ec-brdCol);border-bottom:none}.expressive-code .frame.is-terminal .header::before{content:&apos;&apos;;position:absolute;pointer-events:none;left:var(--ec-uiPadInl);width:2.1rem;height:0.56rem;line-height:0;background-color:var(--ec-frm-trmTtbDotsFg);opacity:var(--ec-frm-trmTtbDotsOpa);-webkit-mask-image:var(--ec-frm-trmIcon);-webkit-mask-repeat:no-repeat;mask-image:var(--ec-frm-trmIcon);mask-repeat:no-repeat}.expressive-code .frame.is-terminal .header::after{content:&apos;&apos;;position:absolute;pointer-events:none;inset:0;border-bottom:var(--ec-brdWd) solid var(--ec-frm-trmTtbBrdBtmCol)}.expressive-code .frame pre{background:var(--code-background)}.expressive-code .copy{display:flex;gap:0.25rem;flex-direction:row;position:absolute;inset-block-start:calc(var(--ec-brdWd) + var(--button-spacing));inset-inline-end:calc(var(--ec-brdWd) + var(--ec-uiPadInl) / 2)}@media (scripting: none){.expressive-code .copy{display:none}}.expressive-code .copy{direction:ltr;unicode-bidi:isolate}.expressive-code .copy button{position:relative;align-self:flex-end;margin:0;padding:0;border:none;border-radius:0.2rem;z-index:1;cursor:pointer;transition-property:opacity, background, border-color;transition-duration:0.2s;transition-timing-function:cubic-bezier(0.25, 0.46, 0.45, 0.94);width:2.5rem;height:2.5rem;background:var(--code-background);opacity:0.75}.expressive-code .copy button div{position:absolute;inset:0;border-radius:inherit;background:var(--ec-frm-inlBtnBg);opacity:var(--ec-frm-inlBtnBgIdleOpa);transition-property:inherit;transition-duration:inherit;transition-timing-function:inherit}.expressive-code .copy button::before{content:&apos;&apos;;position:absolute;pointer-events:none;inset:0;border-radius:inherit;border:var(--ec-brdWd) solid var(--ec-frm-inlBtnBrd);opacity:var(--ec-frm-inlBtnBrdOpa)}.expressive-code .copy button::after{content:&apos;&apos;;position:absolute;pointer-events:none;inset:0;background-color:var(--ec-frm-inlBtnFg);-webkit-mask-image:var(--ec-frm-copyIcon);-webkit-mask-repeat:no-repeat;mask-image:var(--ec-frm-copyIcon);mask-repeat:no-repeat;margin:0.475rem;line-height:0}.expressive-code .copy button:hover,.expressive-code .copy button:focus:focus-visible{opacity:1}.expressive-code .copy button:hover div,.expressive-code .copy button:focus:focus-visible div{opacity:var(--ec-frm-inlBtnBgHoverOrFocusOpa)}.expressive-code .copy button:active{opacity:1}.expressive-code .copy button:active div{opacity:var(--ec-frm-inlBtnBgActOpa)}.expressive-code .copy .feedback{--tooltip-arrow-size:0.35rem;--tooltip-bg:var(--ec-frm-tooltipSuccessBg);color:var(--ec-frm-tooltipSuccessFg);pointer-events:none;user-select:none;-webkit-user-select:none;position:relative;align-self:center;background-color:var(--tooltip-bg);z-index:99;padding:0.125rem 0.75rem;border-radius:0.2rem;margin-inline-end:var(--tooltip-arrow-size);opacity:0;transition-property:opacity, transform;transition-duration:0.2s;transition-timing-function:ease-in-out;transform:translate3d(0, 0.25rem, 0)}.expressive-code .copy .feedback::after{content:&apos;&apos;;position:absolute;pointer-events:none;top:calc(50% - var(--tooltip-arrow-size));inset-inline-end:calc(-2 * (var(--tooltip-arrow-size) - 0.5px));border:var(--tooltip-arrow-size) solid transparent;border-inline-start-color:var(--tooltip-bg)}.expressive-code .copy .feedback.show{opacity:1;transform:translate3d(0, 0, 0)}@media (hover: hover){.expressive-code{}.expressive-code .copy button{opacity:0;width:2rem;height:2rem}.expressive-code .frame:hover .copy button:not(:hover),.expressive-code .frame:focus-within :focus-visible ~ .copy button:not(:hover),.expressive-code .frame .copy .feedback.show ~ button:not(:hover){opacity:0.75}}.expressive-code :nth-child(1 of .ec-line) .code{padding-inline-end:calc(2rem + var(--ec-codePadInl))}:root{--ec-brdRad:0.75rem;--ec-brdWd:1.5px;--ec-brdCol:var(--code-line);--ec-codeFontFml:var(--font-code);--ec-codeFontSize:0.875rem;--ec-codeFontWg:400;--ec-codeLineHt:1.75;--ec-codePadBlk:1rem;--ec-codePadInl:1.125rem;--ec-codeBg:var(--code-bg);--ec-codeFg:#e6edf3;--ec-codeSelBg:#264f78;--ec-gtrFg:#6e7681;--ec-gtrBrdCol:#6e768133;--ec-gtrBrdWd:1.5px;--ec-gtrHlFg:#e6edf3;--ec-uiFontFml:var(--font-mono);--ec-uiFontSize:0.75rem;--ec-uiFontWg:400;--ec-uiLineHt:1.65;--ec-uiPadBlk:0.25rem;--ec-uiPadInl:1rem;--ec-uiSelBg:#6e768166;--ec-uiSelFg:#e6edf3;--ec-focusBrd:#1f6feb;--ec-sbThumbCol:#8b949e33;--ec-sbThumbHoverCol:#8b949e3d;--ec-tm-lineMarkerAccentMarg:0rem;--ec-tm-lineMarkerAccentWd:0.15rem;--ec-tm-lineMarkerLabelPadInl:0.2rem;--ec-tm-lineMarkerLabelCol:white;--ec-tm-lineDiffIndMargLeft:0.3rem;--ec-tm-inlMarkerBrdWd:1.5px;--ec-tm-inlMarkerBrdRad:0.2rem;--ec-tm-inlMarkerPad:0.15rem;--ec-tm-insDiffIndContent:&apos;+&apos;;--ec-tm-delDiffIndContent:&apos;-&apos;;--ec-tm-markBg:#264a8980;--ec-tm-markBrdCol:#5570b3d0;--ec-tm-insBg:#26561c80;--ec-tm-insBrdCol:#4e7e41d0;--ec-tm-insDiffIndCol:#7eb070d0;--ec-tm-delBg:#81322b80;--ec-tm-delBrdCol:#ae594fd0;--ec-tm-delDiffIndCol:#e68a7ed0;--ec-frm-shdCol:#0000005b;--ec-frm-frameBoxShdCssVal:none;--ec-frm-edActTabBg:var(--code-bg);--ec-frm-edActTabFg:var(--code-muted);--ec-frm-edActTabBrdCol:transparent;--ec-frm-edActTabIndHt:1.5px;--ec-frm-edActTabIndTopCol:transparent;--ec-frm-edActTabIndBtmCol:#0d1117;--ec-frm-edTabsMargInlStart:0;--ec-frm-edTabsMargBlkStart:0;--ec-frm-edTabBrdRad:0.75rem;--ec-frm-edTabBarBg:var(--code-bg);--ec-frm-edTabBarBrdCol:var(--code-line);--ec-frm-edTabBarBrdBtmCol:var(--code-line);--ec-frm-edBg:var(--code-bg);--ec-frm-trmTtbFg:var(--code-muted);--ec-frm-trmTtbDotsFg:var(--code-muted);--ec-frm-trmTtbDotsOpa:0.15;--ec-frm-trmTtbBg:var(--code-bg);--ec-frm-trmTtbBrdBtmCol:var(--code-line);--ec-frm-trmBg:var(--code-bg);--ec-frm-inlBtnBg:var(--code-ink);--ec-frm-inlBtnBgIdleOpa:0;--ec-frm-inlBtnBgHoverOrFocusOpa:0.2;--ec-frm-inlBtnBgActOpa:0.3;--ec-frm-inlBtnFg:var(--code-ink);--ec-frm-inlBtnBrd:var(--code-line);--ec-frm-inlBtnBrdOpa:0.4;--ec-frm-tooltipSuccessBg:var(--color-emerald);--ec-frm-tooltipSuccessFg:var(--color-bg);--ec-frm-copyIcon:url(&quot;data:image/svg+xml,%3Csvg%20xmlns%3D&apos;http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg&apos;%20viewBox%3D&apos;0%200%2024%2024&apos;%20fill%3D&apos;none&apos;%20stroke%3D&apos;black&apos;%20stroke-width%3D&apos;1.75&apos;%3E%3Cpath%20d%3D&apos;M3%2019a2%202%200%200%201-1-2V2a2%202%200%200%201%201-1h13a2%202%200%200%201%202%201&apos;%2F%3E%3Crect%20x%3D&apos;6&apos;%20y%3D&apos;5&apos;%20width%3D&apos;16&apos;%20height%3D&apos;18&apos;%20rx%3D&apos;1.5&apos;%20ry%3D&apos;1.5&apos;%2F%3E%3C%2Fsvg%3E&quot;);--ec-frm-trmIcon:url(&quot;data:image/svg+xml,%3Csvg%20xmlns%3D&apos;http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg&apos;%20viewBox%3D&apos;0%200%2060%2016&apos;%20preserveAspectRatio%3D&apos;xMidYMid%20meet&apos;%3E%3Ccircle%20cx%3D&apos;8&apos;%20cy%3D&apos;8&apos;%20r%3D&apos;8&apos;%2F%3E%3Ccircle%20cx%3D&apos;30&apos;%20cy%3D&apos;8&apos;%20r%3D&apos;8&apos;%2F%3E%3Ccircle%20cx%3D&apos;52&apos;%20cy%3D&apos;8&apos;%20r%3D&apos;8&apos;%2F%3E%3C%2Fsvg%3E&quot;)}.expressive-code .ec-line :where(span[style^=&apos;--&apos;]:not([class])){color:var(--0, inherit);background-color:var(--0bg, transparent);font-style:var(--0fs, inherit);font-weight:var(--0fw, inherit);text-decoration:var(--0td, inherit)}&lt;/style&gt;&lt;script type=&quot;module&quot; src=&quot;/_astro/ec.0vx5m.js&quot;&gt;&lt;/script&gt;&lt;figure class=&quot;frame has-title&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;JavaScript&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;javascript&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;connection&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;await&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; pool.&lt;/span&gt;&lt;span style=&quot;--0:#D2A8FF&quot;&gt;acquire&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;try&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;await&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; connection.&lt;/span&gt;&lt;span style=&quot;--0:#D2A8FF&quot;&gt;query&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;&apos;SELECT * FROM users&apos;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;} &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;finally&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#8B949E&quot;&gt;// Error ঘটলেও Connection অবশ্যই Pool-এ ফেরত যাবে&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;connection.&lt;/span&gt;&lt;span style=&quot;--0:#D2A8FF&quot;&gt;release&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;const connection = await pool.acquire();try {  await connection.query(&amp;#x27;SELECT * FROM users&amp;#x27;);} finally {  // Error ঘটলেও Connection অবশ্যই Pool-এ ফেরত যাবে  connection.release();}&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;hr&gt;
&lt;h2 id=&quot;wait-time-বনাম-query-time&quot;&gt;Wait Time বনাম Query Time&lt;/h2&gt;
&lt;p&gt;একটি request-এর total Database latency মূলত কয়েকটি অংশের যোগফল। ধরুন আপনার একটি request ডাটাবেজ থেকে ডেটা আনতে ৮৩০ মিলি সেকেন্ড সময় নিল। আপনি হয়তো ভাবছেন আপনার query খুব slow।&lt;/p&gt;
&lt;figure&gt;&lt;img src=&quot;https://raw.githubusercontent.com/rafeuddaraj/rafes-blog-assets/refs/heads/how-database-connection-pools-work-under-the-hood/assets/request-latency-timeline.svg&quot; alt=&quot;Request Latency Timeline Breakdown&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;800&quot; height=&quot;250&quot;&gt;&lt;figcaption&gt;Request Latency Timeline Breakdown&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;কিন্তু গভীরভাবে ব্রেকডাউন করলে দেখা যেতে পারে, Connection পাওয়ার জন্য request-টি Pool-এর queue-তে ৮০০ মিলি সেকেন্ড অপেক্ষা করেছে, আর query execute হতে সময় লেগেছে মাত্র ৩০ মিলি সেকেন্ড। ব্যবহারকারীর কাছে পুরো বিষয়টা slow মনে হলেও, ডাটাবেজ এখানে কোনোভাবেই স্লো নয়। সমস্যাটি হলো resource starvation।&lt;/p&gt;
&lt;div class=&quot;callout&quot; role=&quot;note&quot; data-type=&quot;warning&quot;&gt;
&lt;p class=&quot;callout-title&quot;&gt;Warning&lt;/p&gt;
&lt;p&gt;Production-এ শুধু query execution latency দেখলে আসল bottleneck মিস হওয়ার তীব্র সম্ভাবনা থাকে। সর্বদা Connection Wait Time আলাদাভাবে পরিমাপ করবেন।&lt;/p&gt;
&lt;/div&gt;
&lt;hr&gt;
&lt;h2 id=&quot;কেন-বড়-pool-মানেই-ভালো-performance-নয়&quot;&gt;কেন বড় Pool মানেই ভালো Performance নয়?&lt;/h2&gt;
&lt;p&gt;অনেকেই ভাবেন Pool size ১০ থেকে বাড়িয়ে ১০০ বা ৫০০ করে দিলে application স্বয়ংক্রিয়ভাবে অনেক ফাস্ট হয়ে যাবে। কিন্তু বাস্তবতা সম্পূর্ণ ভিন্ন।&lt;/p&gt;
&lt;figure&gt;&lt;img src=&quot;https://raw.githubusercontent.com/rafeuddaraj/rafes-blog-assets/refs/heads/how-database-connection-pools-work-under-the-hood/assets/pool-size-performance-curve.svg&quot; alt=&quot;Pool Size vs Performance Curve&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;800&quot; height=&quot;400&quot;&gt;&lt;figcaption&gt;Pool Size vs Performance Curve&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;বেশি Connection মানে ডাটাবেজে বেশি concurrent কাজ যাওয়া। প্রতিটি concurrent কাজের জন্য ডাটাবেজকে CPU time, Memory, Locks এবং Disk I/O শেয়ার করতে হয়। যখন concurrent কাজের সংখ্যা ডাটাবেজের প্রসেসিং ক্ষমতার (Saturation Point) বাইরে চলে যায়, তখন internal contention এবং context switching-এর কারণে সামগ্রিক পারফরম্যান্স মারাত্মকভাবে কমে যায়।&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;multi-instance-production-trap&quot;&gt;Multi-Instance Production Trap&lt;/h2&gt;
&lt;p&gt;Local development environment-এ একটি মাত্র application instance চলে এবং সেখানে Pool size ২০ থাকলে সবকিছু একদম পারফেক্ট মনে হয়। কিন্তু production-এ যখন আপনি application horizontally scale করেন, তখন সমীকরণ বদলে যায়।&lt;/p&gt;
&lt;figure&gt;&lt;img src=&quot;https://raw.githubusercontent.com/rafeuddaraj/rafes-blog-assets/refs/heads/how-database-connection-pools-work-under-the-hood/assets/multi-instance-connection-growth.svg&quot; alt=&quot;Multi-Instance Connection Growth&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;800&quot; height=&quot;400&quot;&gt;&lt;figcaption&gt;Multi-Instance Connection Growth&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;ধরুন production-এ আপনার ২০টি instance চলছে। প্রত্যেকটি instance-এর Pool size যদি ২০ হয়, তাহলে ডাটাবেজের দিকে theoretical maximum কানেকশন সংখ্যা দাঁড়ায় ৪০০ (২০ x ২০)। Kubernetes-এর মতো সিস্টেমে autoscaling চালু থাকলে ট্রাফিক বাড়ার সঙ্গে সঙ্গে instance সংখ্যা বাড়ে এবং ডাটাবেজ কানেকশন জ্যামিতিক হারে বাড়তে থাকে। Application খুব সহজে scale করা গেলেও Database সেভাবে scale হতে পারে না।&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;database-side-connection-এর-cost&quot;&gt;Database-side Connection-এর Cost&lt;/h2&gt;
&lt;p&gt;Application-side Pool বোঝার পর এবার ডাটাবেজের দৃষ্টিকোণ থেকে বিষয়টি দেখা যাক। PostgreSQL প্রতিটি Connection-এর জন্য আলাদা OS process fork করে এবং session-related memory context ও temporary tables মেইনটেইন করে।&lt;/p&gt;
&lt;figure&gt;&lt;img src=&quot;https://raw.githubusercontent.com/rafeuddaraj/rafes-blog-assets/refs/heads/how-database-connection-pools-work-under-the-hood/assets/db-side-connection-cost.svg&quot; alt=&quot;Database-Side Resource Cost per Connection&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;800&quot; height=&quot;400&quot;&gt;&lt;figcaption&gt;Database-Side Resource Cost per Connection&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;এর মানে হলো Connection count বাড়লে শুধু নেটওয়ার্ক ট্রাফিকই বাড়ে না, ডাটাবেজের নিজস্ব মেমোরি এবং প্রসেসিং পাওয়ারও খরচ হতে থাকে। কানেকশনের সংখ্যা খুব বেশি হলে ডাটাবেজ query প্রসেস করার চেয়ে কানেকশন হ্যান্ডেল করতেই বেশি ব্যস্ত হয়ে পড়ে।&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;pool-exhaustion-এবং-cascading-failure&quot;&gt;Pool Exhaustion এবং Cascading Failure&lt;/h2&gt;
&lt;p&gt;Pool exhaustion তখন ঘটে যখন Pool-এর সব Connection ব্যস্ত থাকে এবং নতুন request-এর জন্য কোনো Connection খালি থাকে না। এই অবস্থায় নতুন request-গুলো queue-তে জমা হতে শুরু করে।&lt;/p&gt;
&lt;figure&gt;&lt;img src=&quot;https://raw.githubusercontent.com/rafeuddaraj/rafes-blog-assets/refs/heads/how-database-connection-pools-work-under-the-hood/assets/pool-exhaustion-flow.svg&quot; alt=&quot;Pool Exhaustion to Cascading Failure Flow&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;800&quot; height=&quot;400&quot;&gt;&lt;figcaption&gt;Pool Exhaustion to Cascading Failure Flow&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;Queue যত বড় হয়, Connection পাওয়ার জন্য অপেক্ষার সময় তত বাড়তে থাকে। একপর্যায়ে Pool timeout হয়ে যায় এবং request ফেইল করে। যদি কোনো কারণে একটি স্লো কোয়েরি ডাটাবেজে চলতে থাকে, তবে সেটি কানেকশন ধরে রাখে। ফলে অন্য unrelated ফাস্ট কোয়েরিগুলোও কানেকশন না পেয়ে আটকে যায়।&lt;/p&gt;
&lt;figure&gt;&lt;img src=&quot;https://raw.githubusercontent.com/rafeuddaraj/rafes-blog-assets/refs/heads/how-database-connection-pools-work-under-the-hood/assets/slow-query-cascade.svg&quot; alt=&quot;Slow Query Cascading Failure&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;800&quot; height=&quot;350&quot;&gt;&lt;figcaption&gt;Slow Query Cascading Failure&lt;/figcaption&gt;&lt;/figure&gt;
&lt;div class=&quot;callout&quot; role=&quot;note&quot; data-type=&quot;danger&quot;&gt;
&lt;p class=&quot;callout-title&quot;&gt;Error&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Pool Leak ও Cascading Failure:&lt;/strong&gt; Connection acquire করার পর &lt;code&gt;finally&lt;/code&gt; ব্লকে release না করলে Pool ধীরে ধীরে মরে যায়। প্রথমদিকে সব ঠিক মনে হলেও কিছু সময় পর সিস্টেম পুরোপুরি স্তব্ধ হয়ে যেতে পারে।&lt;/p&gt;
&lt;/div&gt;
&lt;hr&gt;
&lt;h2 id=&quot;transactions-এবং-connection-affinity&quot;&gt;Transactions এবং Connection Affinity&lt;/h2&gt;
&lt;p&gt;সাধারণ query-এর চেয়ে Transaction ডাটাবেজ কানেকশনের ওপর অনেক বেশি চাপ তৈরি করে। Transaction শুরু হলে (&lt;code&gt;BEGIN&lt;/code&gt;) সেটি শেষ না হওয়া পর্যন্ত (&lt;code&gt;COMMIT&lt;/code&gt; বা &lt;code&gt;ROLLBACK&lt;/code&gt;) পুরো সময় একই Connection ধরে রাখতে হয়।&lt;/p&gt;
&lt;figure&gt;&lt;img src=&quot;https://raw.githubusercontent.com/rafeuddaraj/rafes-blog-assets/refs/heads/how-database-connection-pools-work-under-the-hood/assets/transaction-lifecycle.svg&quot; alt=&quot;Transaction Lifecycle on a Single Connection&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;800&quot; height=&quot;250&quot;&gt;&lt;figcaption&gt;Transaction Lifecycle on a Single Connection&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;Transaction যতক্ষণ ওপেন থাকে, সেই Connection-টি অন্য কোনো request-এর জন্য available থাকে না। একে বলা হয় Connection Affinity। আপনি যদি &lt;code&gt;BEGIN&lt;/code&gt; একটি কানেকশনে এবং &lt;code&gt;COMMIT&lt;/code&gt; অন্য একটি কানেকশনে পাঠান, তবে transaction semantics পুরোপুরি ভেঙে যাবে।&lt;/p&gt;
&lt;figure&gt;&lt;img src=&quot;https://raw.githubusercontent.com/rafeuddaraj/rafes-blog-assets/refs/heads/how-database-connection-pools-work-under-the-hood/assets/connection-affinity-semantics.svg&quot; alt=&quot;Connection Affinity Correct vs Wrong Semantics&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;800&quot; height=&quot;350&quot;&gt;&lt;figcaption&gt;Connection Affinity Correct vs Wrong Semantics&lt;/figcaption&gt;&lt;/figure&gt;
&lt;hr&gt;
&lt;h2 id=&quot;timeouts-এবং-connection-lifecycle&quot;&gt;Timeouts এবং Connection Lifecycle&lt;/h2&gt;
&lt;p&gt;প্রোডাকশন সিস্টেমে Timeout ম্যানেজমেন্ট অত্যন্ত ক্রিটিক্যাল একটি বিষয়। সবগুলো টাইমআউট এক জিনিস নয় এবং এদের মধ্যে একটি পরিষ্কার হায়ারার্কি থাকতে হবে।&lt;/p&gt;
&lt;figure&gt;&lt;img src=&quot;https://raw.githubusercontent.com/rafeuddaraj/rafes-blog-assets/refs/heads/how-database-connection-pools-work-under-the-hood/assets/timeout-hierarchy.svg&quot; alt=&quot;Production Timeout Hierarchy&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;800&quot; height=&quot;250&quot;&gt;&lt;figcaption&gt;Production Timeout Hierarchy&lt;/figcaption&gt;&lt;/figure&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Request Timeout:&lt;/strong&gt; ক্লায়েন্ট বা গেটওয়ে রিকোয়েস্টের জন্য সর্বোচ্চ কতক্ষণ অপেক্ষা করবে।&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Transaction Timeout:&lt;/strong&gt; একটি ডাটাবেজ ট্রানজ্যাকশন সর্বোচ্চ কতক্ষণ ওপেন থাকতে পারবে।&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Pool Wait Timeout:&lt;/strong&gt; একটি রিকোয়েস্ট পুল থেকে কানেকশন পাওয়ার জন্য সর্বোচ্চ কতক্ষণ অপেক্ষা করবে।&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Query Timeout:&lt;/strong&gt; একটি সিঙ্গেল কোয়েরি ডাটাবেজে সর্বোচ্চ কতক্ষণ চলতে পারবে।&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;তাছাড়া একটি কানেকশন চিরকাল বেঁচে থাকে না। নেটওয়ার্ক ফেইলিওর বা ডাটাবেজ রিস্টার্টের কারণে কানেকশন ড্রপ হতে পারে। Pool-কে নিয়মিত idle connection চেক করতে হয় (Health check যেমন &lt;code&gt;SELECT 1&lt;/code&gt;) এবং stale connection ডিসকার্ড করে নতুন কানেকশন তৈরি করতে হয়।&lt;/p&gt;
&lt;figure&gt;&lt;img src=&quot;https://raw.githubusercontent.com/rafeuddaraj/rafes-blog-assets/refs/heads/how-database-connection-pools-work-under-the-hood/assets/stale-connection-detection.svg&quot; alt=&quot;Stale Connection Detection and Recovery&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;800&quot; height=&quot;400&quot;&gt;&lt;figcaption&gt;Stale Connection Detection and Recovery&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;একটি Connection এক request থেকে অন্য request-এ reuse হওয়ার সময় আগের সেশনের স্টেট (যেমন &lt;code&gt;SET statement_timeout&lt;/code&gt; বা temporary tables) পরের request-কে প্রভাবিত করতে পারে, যা প্রোডাকশনে নীরব বাগ তৈরি করে।&lt;/p&gt;
&lt;figure&gt;&lt;img src=&quot;https://raw.githubusercontent.com/rafeuddaraj/rafes-blog-assets/refs/heads/how-database-connection-pools-work-under-the-hood/assets/session-state-reuse.svg&quot; alt=&quot;The Danger of Session State Reuse&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;800&quot; height=&quot;350&quot;&gt;&lt;figcaption&gt;The Danger of Session State Reuse&lt;/figcaption&gt;&lt;/figure&gt;
&lt;div class=&quot;callout&quot; role=&quot;note&quot; data-type=&quot;note&quot;&gt;
&lt;p class=&quot;callout-title&quot;&gt;Info&lt;/p&gt;
&lt;p&gt;কানেকশন পুনরায় ব্যবহারের আগে নিশ্চিত করুন যে সেশন ভ্যারিয়েবল এবং স্টেট সম্পূর্ণ রিসেট (DISCARD ALL / RESET ALL) করা হয়েছে।&lt;/p&gt;
&lt;/div&gt;
&lt;hr&gt;
&lt;h2 id=&quot;pgbouncer-এবং-serverless-architecture&quot;&gt;PgBouncer এবং Serverless Architecture&lt;/h2&gt;
&lt;p&gt;বড় স্কেলের প্রোডাকশন সিস্টেমে শুধু Application-side Pool যথেষ্ট নয়। PostgreSQL-এর ক্ষেত্রে PgBouncer-এর মতো এক্সটার্নাল কানেকশন পুলার ব্যবহার করা হয়। এটি ডাটাবেজের সামনে একটি সেন্ট্রাল প্রক্সি লেয়ার হিসেবে কাজ করে এবং হাজার হাজার অ্যাপ্লিকেশন কানেকশনকে অল্প কয়েকটি ডাটাবেজ কানেকশনে multiplex করে দেয়।&lt;/p&gt;
&lt;figure&gt;&lt;img src=&quot;https://raw.githubusercontent.com/rafeuddaraj/rafes-blog-assets/refs/heads/how-database-connection-pools-work-under-the-hood/assets/pgbouncer-architecture.svg&quot; alt=&quot;PgBouncer Architecture&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;800&quot; height=&quot;400&quot;&gt;&lt;figcaption&gt;PgBouncer Architecture&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;Serverless আর্কিটেকচারে (যেমন AWS Lambda) বিষয়টি আরও সংকটজনক। সেখানে ট্রাফিক স্পাইক হলে শত শত short-lived execution instance তৈরি হয়। প্রত্যেকে নিজস্ব কানেকশন তৈরি করতে চাইলে Database Connection সাথে সাথে explode করে ক্র্যাশ করে।&lt;/p&gt;
&lt;figure&gt;&lt;img src=&quot;https://raw.githubusercontent.com/rafeuddaraj/rafes-blog-assets/refs/heads/how-database-connection-pools-work-under-the-hood/assets/serverless-connection-explosion.svg&quot; alt=&quot;Serverless Connection Explosion Problem&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;800&quot; height=&quot;350&quot;&gt;&lt;figcaption&gt;Serverless Connection Explosion Problem&lt;/figcaption&gt;&lt;/figure&gt;
&lt;hr&gt;
&lt;h2 id=&quot;connection-storm-এবং-retries&quot;&gt;Connection Storm এবং Retries&lt;/h2&gt;
&lt;p&gt;ধরুন কোনো কারণে আপনার ডাটাবেজ ১০ সেকেন্ডের জন্য রিস্টার্ট নিল। অ্যাপ্লিকেশন ইনস্ট্যান্সগুলো কানেকশন হারায়। ডাটাবেজ ফিরে আসার সাথে সাথে সবগুলো ইনস্ট্যান্স যদি হুট করে রি-কানেক্ট করার চেষ্টা করে, তবে ডাটাবেজের ওপর যে বিশাল ধাক্কাটি আসে তাকে Connection Storm বলে।&lt;/p&gt;
&lt;p&gt;Exponential Backoff এবং Jitter ব্যবহার করে রিট্রাইগুলোকে সময়ের মধ্যে ছড়িয়ে দিলে ডাটাবেজ নিরাপদে রিকভার করতে পারে।&lt;/p&gt;
&lt;figure&gt;&lt;img src=&quot;https://raw.githubusercontent.com/rafeuddaraj/rafes-blog-assets/refs/heads/how-database-connection-pools-work-under-the-hood/assets/connection-storm-recovery.svg&quot; alt=&quot;Connection Storm Recovery with Jitter&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;800&quot; height=&quot;400&quot;&gt;&lt;figcaption&gt;Connection Storm Recovery with Jitter&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;তাছাড়া ডাটাবেজ স্লো থাকলে অ্যাপ্লিকেশন যদি ক্রমাগত আগ্রাসী রিট্রাই পাঠাতে থাকে, তবে ডাটাবেজে কাজের চাপ আরও বেড়ে যায় এবং সিস্টেম একটি মারাত্মক ফিডব্যাক লুপে আটকা পড়ে।&lt;/p&gt;
&lt;figure&gt;&lt;img src=&quot;https://raw.githubusercontent.com/rafeuddaraj/rafes-blog-assets/refs/heads/how-database-connection-pools-work-under-the-hood/assets/retry-cascading-failure.svg&quot; alt=&quot;Retry Cascading Failure Feedback Loop&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;800&quot; height=&quot;400&quot;&gt;&lt;figcaption&gt;Retry Cascading Failure Feedback Loop&lt;/figcaption&gt;&lt;/figure&gt;
&lt;hr&gt;
&lt;h2 id=&quot;production-observability-এবং-debugging&quot;&gt;Production Observability এবং Debugging&lt;/h2&gt;
&lt;p&gt;প্রোডাকশন সিস্টেমে সমস্যা খুঁজে বের করার জন্য শুধু query latency দেখলে চলবে না। আপনাকে পরিমাপ করতে হবে Pool কতটা ব্যস্ত, কতগুলো request কানেকশনের জন্য অপেক্ষা করছে এবং acquisition latency কত।&lt;/p&gt;
&lt;figure&gt;&lt;img src=&quot;https://raw.githubusercontent.com/rafeuddaraj/rafes-blog-assets/refs/heads/how-database-connection-pools-work-under-the-hood/assets/pool-metrics-dashboard.svg&quot; alt=&quot;Production Observability Metrics Dashboard&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;800&quot; height=&quot;400&quot;&gt;&lt;figcaption&gt;Production Observability Metrics Dashboard&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;ডিবাগিংয়ের সময় অনুমান না করে নিচের ট্রায়াজ ট্রি অনুযায়ী ইনভেস্টিগেশন করুন:&lt;/p&gt;
&lt;figure&gt;&lt;img src=&quot;https://raw.githubusercontent.com/rafeuddaraj/rafes-blog-assets/refs/heads/how-database-connection-pools-work-under-the-hood/assets/production-debugging-tree.svg&quot; alt=&quot;Production Debugging Decision Tree&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;800&quot; height=&quot;500&quot;&gt;&lt;figcaption&gt;Production Debugging Decision Tree&lt;/figcaption&gt;&lt;/figure&gt;
&lt;hr&gt;
&lt;h2 id=&quot;queueing-theory-দিয়ে-capacity-বোঝা&quot;&gt;Queueing Theory দিয়ে Capacity বোঝা&lt;/h2&gt;
&lt;p&gt;Connection Pool-এর সাইজ অনুমান করে নির্ধারণ করার বিষয় নয়। Little&apos;s Law ব্যবহার করে এর একটি গাণিতিক ধারণা পাওয়া যায়:&lt;/p&gt;
&lt;span class=&quot;katex-display&quot;&gt;&lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.8778em;vertical-align:-0.1944em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord text&quot;&gt;&lt;span class=&quot;mord&quot;&gt;Concurrency&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mrel&quot;&gt;≈&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.8889em;vertical-align:-0.1944em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord text&quot;&gt;&lt;span class=&quot;mord&quot;&gt;Throughput&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mbin&quot;&gt;×&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.8778em;vertical-align:-0.1944em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord text&quot;&gt;&lt;span class=&quot;mord&quot;&gt;Latency&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;p&gt;যদি আপনার সিস্টেমে সেকেন্ডে ৫০০ রিকোয়েস্ট আসে এবং প্রতিটি কানেকশন গড়ে ০.১ সেকেন্ড (১০০ মিলি সেকেন্ড) ব্যস্ত থাকে, তাহলে আপনার প্রয়োজনীয় কনকারেন্সি হবে: &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.7278em;vertical-align:-0.0833em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;500&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mbin&quot;&gt;×&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.6444em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;0.1&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mrel&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.6444em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;50&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; টি কানেকশন।&lt;/p&gt;
&lt;figure&gt;&lt;img src=&quot;https://raw.githubusercontent.com/rafeuddaraj/rafes-blog-assets/refs/heads/how-database-connection-pools-work-under-the-hood/assets/queueing-theory-concurrency.svg&quot; alt=&quot;Queueing Theory and Little&amp;#x27;s Law for Connection Pools&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;800&quot; height=&quot;350&quot;&gt;&lt;figcaption&gt;Queueing Theory and Little&apos;s Law for Connection Pools&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;কোয়েরি বা ট্রানজ্যাকশন ডিউরেশন বেড়ে গেলে একই ট্রাফিক হ্যান্ডেল করতে জ্যামিতিক হারে বেশি কানেকশন প্রয়োজন হয়।&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;balanced-production-architecture&quot;&gt;Balanced Production Architecture&lt;/h2&gt;
&lt;p&gt;সবগুলো কনসেপ্ট একত্রিত করলে আমরা একটি প্রোডাকশন-রেডি ব্যালেন্সড আর্কিটেকচার পাই। এখানে মাল্টিপল অ্যাপ্লিকেশন ইনস্ট্যান্স থাকবে, প্রত্যেকটির নিজস্ব বাউন্ডেড কানেকশন পুল থাকবে। মাঝখানে PgBouncer-এর মতো সেন্ট্রাল পুলার থাকবে, এবং ডাটাবেজের কানেকশন ক্যাপাসিটি কঠোরভাবে নিয়ন্ত্রিত থাকবে।&lt;/p&gt;
&lt;figure&gt;&lt;img src=&quot;https://raw.githubusercontent.com/rafeuddaraj/rafes-blog-assets/refs/heads/how-database-connection-pools-work-under-the-hood/assets/balanced-production-architecture.svg&quot; alt=&quot;Balanced Production Architecture&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;800&quot; height=&quot;500&quot;&gt;&lt;figcaption&gt;Balanced Production Architecture&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;ইনসিডেন্টের সময় যাতে পুরো সিস্টেম ক্র্যাশ না করে, সেজন্য প্রতিটি লেয়ারে টাইমআউট, রিট্রাই উইথ জিটার এবং সার্কিট ব্রেকার পলিসি কার্যকর থাকতে হয়।&lt;/p&gt;
&lt;figure&gt;&lt;img src=&quot;https://raw.githubusercontent.com/rafeuddaraj/rafes-blog-assets/refs/heads/how-database-connection-pools-work-under-the-hood/assets/full-incident-timeline.svg&quot; alt=&quot;Full Incident Timeline&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;800&quot; height=&quot;400&quot;&gt;&lt;figcaption&gt;Full Incident Timeline&lt;/figcaption&gt;&lt;/figure&gt;
&lt;hr&gt;
&lt;h2 id=&quot;final-developer-checklist&quot;&gt;Final Developer Checklist&lt;/h2&gt;
&lt;p&gt;পুলের সাইজ নির্ধারণ এবং সিস্টেম স্থিতিশীল রাখার জন্য একটি ফ্রেমওয়ার্ক এবং চেকলিস্ট মেনে চলা উচিত:&lt;/p&gt;
&lt;figure&gt;&lt;img src=&quot;https://raw.githubusercontent.com/rafeuddaraj/rafes-blog-assets/refs/heads/how-database-connection-pools-work-under-the-hood/assets/pool-sizing-framework.svg&quot; alt=&quot;Pool Sizing Decision Framework&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;800&quot; height=&quot;500&quot;&gt;&lt;figcaption&gt;Pool Sizing Decision Framework&lt;/figcaption&gt;&lt;/figure&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;pool.max&lt;/code&gt; নির্ধারণের আগে মোট Application Instance count হিসাব করুন।&lt;/li&gt;
&lt;li&gt;Connection acquisition latency এবং Pool waiting queue নিয়মিত ড্যাশবোর্ডে মনিটর করুন।&lt;/li&gt;
&lt;li&gt;ডাটাবেজের কাজ শেষ হওয়ামাত্র &lt;code&gt;finally&lt;/code&gt; ব্লকে কানেকশন &lt;code&gt;release()&lt;/code&gt; করা নিশ্চিত করুন।&lt;/li&gt;
&lt;li&gt;ট্রানজ্যাকশন যত ছোট রাখা যায় তত ভালো। এক্সটার্নাল API call কখনোই ডাটাবেজ ট্রানজ্যাকশনের ভেতরে রাখবেন না।&lt;/li&gt;
&lt;li&gt;Pool timeout, query timeout, এবং request timeout আলাদাভাবে কনফিগার করুন।&lt;/li&gt;
&lt;li&gt;Serverless ইনভায়রনমেন্ট হলে PgBouncer বা RDS Proxy ব্যবহার নিশ্চিত করুন।&lt;/li&gt;
&lt;li&gt;ডাটাবেজ রিস্টার্ট বা নেটওয়ার্ক ফেইলিওরের কথা মাথায় রেখে Exponential Backoff ও Jitter সহ Reconnect স্ট্র্যাটেজি রাখুন।&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;the-ultimate-mental-model&quot;&gt;The Ultimate Mental Model&lt;/h3&gt;
&lt;p&gt;Connection Pool-কে শুধু &quot;কানেকশন রিউজ করার টুল&quot; ভাবলে ভুল হবে। এটি মূলত আপনার অ্যাপ্লিকেশন এবং ডাটাবেজের মাঝখানে একটি &lt;strong&gt;Concurrency Control Layer&lt;/strong&gt;। এটি নিয়ন্ত্রণ করে ঠিক কতগুলো অপারেশন একই সঙ্গে ডাটাবেজের ওপর চাপ প্রয়োগ করতে পারবে।&lt;/p&gt;
&lt;figure&gt;&lt;img src=&quot;https://raw.githubusercontent.com/rafeuddaraj/rafes-blog-assets/refs/heads/how-database-connection-pools-work-under-the-hood/assets/pool-concurrency-mental-model.svg&quot; alt=&quot;Pool as a Concurrency Control Layer&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;800&quot; height=&quot;400&quot;&gt;&lt;figcaption&gt;Pool as a Concurrency Control Layer&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;ডাটাবেজ কানেকশন একটি অত্যন্ত সীমিত সম্পদ। এর সঠিক স্থাপত্য ও ব্যবস্থাপনা ছাড়া কোনো অ্যাপ্লিকেশনই প্রোডাকশনে সফলভাবে স্কেল করতে পারে না।&lt;/p&gt;</content:encoded><category>System Architecture</category><category>Database</category><category>Backend Architecture</category><category>Connection Pooling</category><category>Performance Optimization</category><category>Node.js</category><category>PostgreSQL</category><category>System Design</category><category>Under the hood</category></item><item><title>Distributed Locks Under the Hood: Redlock, Fencing Tokens and the Split-Brain Problem</title><link>https://www.rafeuddaraj.me/bn/blog/distributed-locks-redlock-fencing-tokens-explained/</link><guid isPermaLink="true">https://www.rafeuddaraj.me/bn/blog/distributed-locks-redlock-fencing-tokens-explained/</guid><description>A deep architectural dive into why standard Redis locks fail in distributed systems, covering lease expiries, paused processes, and how database-level fencing tokens guarantee absolute correctness.</description><pubDate>Tue, 01 Sep 2026 19:18:32 GMT</pubDate><content:encoded>&lt;p&gt;একটি Production System কল্পনা করুন যেখানে একই সময়ে কয়েকটি Node.js Server চলছে। ধরুন, প্রতি রাতে আপনার সিস্টেমে একটি Background Job চলে যার কাজ হলো &lt;code&gt;generateMonthlyInvoices()&lt;/code&gt; Execute করা। হঠাৎ দেখলেন একই সময়ে দুটি Server একই Job Execute করে ফেলেছে এবং একজন Customer এর Invoice দুইবার তৈরি হয়ে গেছে। অথবা Payment Processing System এ একই Payment দুইবার Process হয়ে গেছে, কিংবা একটি Shared Inventory Row দুটি আলাদা Worker একই সময়ে Update করে ফেলেছে। এই ধরনের পরিস্থিতিতে একজন Engineer এর মাথায় সবার আগে যে Obvious Solution আসে তা হলো, এই Critical Section এর আগে একটি Redis Lock বসিয়ে দেওয়া। আপাতদৃষ্টিতে মনে হতে পারে Worker A এবং Worker B এর মাঝখানে একটি Redis Coordination Point বসিয়ে দিলেই Problem Solved। কিন্তু আসল প্রশ্নটি হলো, যদি Worker A Lock নেওয়ার পরেও কাজ শেষ করতে না পারে এবং Lock এর TTL Expire হয়ে যায়, তখন আসলে কী ঘটবে? এই একটি মাত্র প্রশ্ন থেকেই Distributed Systems এর সবচেয়ে জটিল একটি Architecture এর Journey শুরু হয়।&lt;/p&gt;
&lt;h2 id=&quot;the-real-objective-behind-locking&quot;&gt;The Real Objective Behind Locking&lt;/h2&gt;
&lt;p&gt;আমাদের প্রথমেই বুঝতে হবে যে একটি Lock আসলে ঠিক কী Solve করতে চায়। এখানে কোড নিয়ে চিন্তা করার আগে Engineering Requirement Define করা বেশি জরুরি। আমাদের মূল উদ্দেশ্য হলো একই সময়ে শুধুমাত্র একজন Valid Worker যেন Critical Operation করতে পারে। এর পাশাপাশি কোনো Worker Crash করলে অন্য Worker যেন Eventually কাজ করতে পারে এবং Infrastructure Failure হলেও System যেন Unsafe State এ না যায়। এই তিনটি প্রপার্টি মূলত Safety, Liveness এবং Fault Tolerance হিসেবে পরিচিত। Safety নিশ্চিত করে যে একই সময়ে দুজন Worker যেন Protected Resource এর ওপর Conflicting Operation না করতে পারে। Liveness নিশ্চিত করে যে একজন Worker Crash করলে তার জন্য পুরো System যেন Permanently আটকে না থাকে। আর Fault Tolerance নিশ্চিত করে যে Redis Node, Network অথবা Application Instance Fail করলেও System এর Behaviour যেন Predictable থাকে। Lock শুধুমাত্র Concurrency Control করে না, এর সঙ্গে Failure Recovery ও Design করতে হয়।&lt;/p&gt;
&lt;p&gt;Horizontal Scaling এর কারণে একই Application এর একাধিক Instance চলাটাই স্বাভাবিক এবং একই Job বা Resource নিয়ে একাধিক Worker কাজ করতেই পারে। Database Transaction সবসময় পুরো Distributed Workflow Protect করতে পারে না, তাই Redis Lock কে প্রাথমিকভাবে একটি সহজ Solution মনে হয়। কিন্তু Lock Expire হওয়ার পর পুরনো Worker যদি তখনও কাজ চালিয়ে যায়, তখন নতুন Worker Lock পেলেও পুরনো Worker এর Stale Operation পুরো System এর মারাত্মক ক্ষতি করতে পারে।&lt;/p&gt;
&lt;figure&gt;&lt;img src=&quot;https://raw.githubusercontent.com/rafeuddaraj/rafes-blog-assets/refs/heads/distributed-locks-redlock-fencing-tokens-explained/assets/distributed-lock-contention.svg&quot; alt=&quot;Distributed Lock Contention&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;800&quot; height=&quot;400&quot;&gt;&lt;figcaption&gt;Distributed Lock Contention&lt;/figcaption&gt;&lt;/figure&gt;
&lt;div class=&quot;callout&quot; role=&quot;note&quot; data-type=&quot;note&quot;&gt;
&lt;p class=&quot;callout-title&quot;&gt;Mental Model Context&lt;/p&gt;
&lt;p&gt;Process Alive থাকা আর Lock Alive থাকা সম্পূর্ণ আলাদা দুটি বিষয়। একটি Worker Memory তে Alive থাকতে পারে, তার Network Connection Active থাকতে পারে, কিন্তু তার Lock এর Authority অনেক আগেই শেষ হয়ে যেতে পারে।&lt;/p&gt;
&lt;/div&gt;
&lt;h2 id=&quot;from-locks-to-time-bound-leases&quot;&gt;From Locks to Time-Bound Leases&lt;/h2&gt;
&lt;p&gt;পুরো বিষয়টিকে সহজভাবে বোঝার জন্য আমরা একটি Warehouse এর Single Access Card এর অ্যানালজি ব্যবহার করতে পারি। ধরুন একটি Warehouse এর ভেতরে একটি বিশেষ Room আছে যেখানে একই সময়ে শুধুমাত্র একজন Operator ঢুকতে পারবে। একজন Operator একটি Access Card নিয়ে ভেতরে কাজ শুরু করল, কিন্তু Security System বলছে এই Access Card ঠিক ত্রিশ মিনিট পর Automatically Invalid হয়ে যাবে। এখন Operator যদি পয়তাল্লিশ মিনিট ধরে কাজ করে, তবে ত্রিশ মিনিট পর দ্বিতীয় Operator নতুন Card পেয়ে Room এ ঢুকে যাবে। প্রথম Operator কিন্তু তখনও ভেতরেই কাজ করছে। Security System আসলে Guarantee করেনি যে Room এর ভেতরে শুধুমাত্র একজন থাকবে, সে শুধু Guarantee করেছিল যে একটি নির্দিষ্ট সময় পর্যন্ত প্রথম Operator এর Access Valid থাকবে। ঠিক এখান থেকেই Lease কনসেপ্টটির উৎপত্তি হয়।&lt;/p&gt;
&lt;p&gt;যখন আমরা Redis এ &lt;code&gt;SET resource:123 worker-token NX PX 30000&lt;/code&gt; কমান্ড চালাই, তখন &lt;code&gt;NX&lt;/code&gt; নিশ্চিত করে যে Key আগে থেকে না থাকলে তবেই Set হবে এবং &lt;code&gt;PX 30000&lt;/code&gt; নিশ্চিত করে যে ত্রিশ সেকেন্ড পর Key Expire করবে। Reader হিসেবে আপনার মনে হতে পারে এটি Perfect Solution, কারণ একজন Lock নিলে অন্যজন ঢুকতে পারবে না। কিন্তু যদি Worker A Lock নেওয়ার পর Process Crash করে, এবং Lock এর কোনো Expiry না থাকে, তবে সেই Lock Forever থেকে যাবে এবং Worker B আর কখনোই Resource Acquire করতে পারবে না। এই কারণেই TTL বা Time To Live প্রয়োজন হয়। কিন্তু Long TTL ব্যবহার করলে Crash Recovery অনেক Slow হয়ে যায়, আবার Short TTL ব্যবহার করলে Work Outliving The Lease এর সম্ভাবনা তৈরি হয়। TTL আসলে Lock কে একটি Time-Bound Ownership দেয়, যাকে আমরা Lease বলি। Lease মানে হলো এই Resource এর ওপর আপনার Authority আছে, কিন্তু সেটি Indefinite নয়, বরং নির্দিষ্ট সময় পর্যন্ত Valid। Worker এর Perspective থেকে মনে হয় সে Lock Acquire করেছে, কিন্তু System এর Perspective থেকে তার Authority শুধুমাত্র Lease Expire হওয়া পর্যন্তই সীমাবদ্ধ।&lt;/p&gt;
&lt;h2 id=&quot;the-race-condition-in-lock-release&quot;&gt;The Race Condition in Lock Release&lt;/h2&gt;
&lt;p&gt;Lease কনসেপ্টটি বুঝতে পারার পর আমাদের Lock Release মেকানিজমের ভেতরের Race Condition নিয়ে আলোচনা করতে হবে। ধরুন Worker A একটি Lock Acquire করল এবং তারপর কোনো কারণে অনেকক্ষণ Pause হয়ে থাকল। ত্রিশ সেকেন্ড পর Lock Expire করে গেল এবং Worker B একটি নতুন Lock Acquire করল। ঠিক এই সময়ে Worker A আবার Resume করল এবং সরাসরি &lt;code&gt;DEL resource:123&lt;/code&gt; Command Execute করে দিল। এখানে মারাত্মক একটি ঘটনা ঘটল, Worker A আসলে নিজের Lock Delete করছে না, সে Worker B এর নতুন Lock Delete করে দিচ্ছে। এর ফলে Worker B এর Lock Disappear হয়ে যায় এবং System সম্পূর্ণ Unsafe State এ চলে যায়।&lt;/p&gt;
&lt;figure&gt;&lt;img src=&quot;https://raw.githubusercontent.com/rafeuddaraj/rafes-blog-assets/refs/heads/distributed-locks-redlock-fencing-tokens-explained/assets/lock-release-race-condition.svg&quot; alt=&quot;Lock Release Race Condition&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;800&quot; height=&quot;450&quot;&gt;&lt;figcaption&gt;Lock Release Race Condition&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;এই ধরনের Production Bug এড়ানোর জন্যই Lock এর সঙ্গে একটি Unique Ownership Token বা Random Lock Token ব্যবহার করা প্রয়োজন। Lock Value হিসেবে একটি Random String সেট করা হয় এবং Release করার সময় Logic চেক করে দেখে যে বর্তমান Lock এর Value এবং Worker এর Token একই কি না। যদি মিলে যায় তবেই Delete করা হয়, অন্যথায় Operation Reject করা হয়। সাধারণত Lua Script বা Atomic Conditional Operation ব্যবহার করে এই Release Process Safely Handle করা হয়:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;style&gt;.expressive-code{font-family:var(--ec-uiFontFml);font-size:var(--ec-uiFontSize);font-weight:var(--ec-uiFontWg);line-height:var(--ec-uiLineHt);text-size-adjust:none;-webkit-text-size-adjust:none}.expressive-code *:not(:is(svg, svg *)){all:revert;box-sizing:border-box}.expressive-code pre{display:flex;margin:0;padding:0;border:var(--ec-brdWd) solid var(--ec-brdCol);border-radius:calc(var(--ec-brdRad) + var(--ec-brdWd));background:var(--ec-codeBg)}.expressive-code pre:focus-visible{outline:3px solid var(--ec-focusBrd);outline-offset:-3px}.expressive-code pre &gt; code{all:unset;display:block;flex:1 0 100%;padding:var(--ec-codePadBlk) 0;color:var(--ec-codeFg);font-family:var(--ec-codeFontFml);font-size:var(--ec-codeFontSize);font-weight:var(--ec-codeFontWg);line-height:var(--ec-codeLineHt)}.expressive-code pre{overflow-x:auto}.expressive-code pre.wrap .ec-line .code{white-space:pre-wrap;overflow-wrap:break-word;min-width:min(20ch, var(--ecMaxLine, 20ch))}.expressive-code pre.wrap .ec-line .code span.indent{white-space:pre}.expressive-code pre::-webkit-scrollbar,.expressive-code pre::-webkit-scrollbar-track{background-color:inherit;border-radius:calc(var(--ec-brdRad) + var(--ec-brdWd));border-top-left-radius:0;border-top-right-radius:0}.expressive-code pre::-webkit-scrollbar-thumb{background-color:var(--ec-sbThumbCol);border:4px solid transparent;background-clip:content-box;border-radius:10px}.expressive-code pre::-webkit-scrollbar-thumb:hover{background-color:var(--ec-sbThumbHoverCol)}.expressive-code pre::-webkit-scrollbar-corner{background:transparent}.expressive-code .ec-line{direction:ltr;unicode-bidi:isolate;display:grid;grid-template-areas:&apos;gutter code&apos;;grid-template-columns:auto 1fr;position:relative}.expressive-code .ec-line .gutter{grid-area:gutter;color:var(--ec-gtrFg)}.expressive-code .ec-line .gutter &gt; *{pointer-events:none;user-select:none;-webkit-user-select:none}.expressive-code .ec-line .gutter ~ .code{--ecLineBrdCol:var(--ec-gtrBrdCol)}.expressive-code .ec-line.highlight .gutter{color:var(--ec-gtrHlFg)}.expressive-code .ec-line .code{grid-area:code;position:relative;box-sizing:content-box;padding-inline-start:calc(var(--ecIndent, 0ch) + var(--ec-codePadInl) - var(--ecGtrBrdWd));padding-inline-end:var(--ec-codePadInl);text-indent:calc(var(--ecIndent, 0ch) * -1)}.expressive-code .ec-line .code::before,.expressive-code .ec-line .code::after,.expressive-code .ec-line .code :where(*){text-indent:0}.expressive-code .ec-line .code{--ecGtrBrdWd:var(--ec-gtrBrdWd);border-inline-start:var(--ecGtrBrdWd) solid var(--ecLineBrdCol, transparent)}.expressive-code .sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0, 0, 0, 0);white-space:nowrap;border-width:0}.expressive-code .ec-line.mark{--tmLineBgCol:var(--ec-tm-markBg)}.expressive-code .ec-line.mark .code{--ecLineBrdCol:var(--ec-tm-markBrdCol)}.expressive-code .ec-line.ins{--tmLineBgCol:var(--ec-tm-insBg);--tmLabel:var(--ec-tm-insDiffIndContent)}.expressive-code .ec-line.ins .code{--ecLineBrdCol:var(--ec-tm-insBrdCol)}.expressive-code .ec-line.ins .code::before{color:var(--ec-tm-insDiffIndCol)}.expressive-code .ec-line.del{--tmLineBgCol:var(--ec-tm-delBg);--tmLabel:var(--ec-tm-delDiffIndContent)}.expressive-code .ec-line.del .code{--ecLineBrdCol:var(--ec-tm-delBrdCol)}.expressive-code .ec-line.del .code::before{color:var(--ec-tm-delDiffIndCol)}.expressive-code .ec-line.mark,.expressive-code .ec-line.ins,.expressive-code .ec-line.del{background:var(--tmLineBgCol)}.expressive-code .ec-line.mark .code,.expressive-code .ec-line.ins .code,.expressive-code .ec-line.del .code{--ecGtrBrdWd:var(--ec-tm-lineMarkerAccentWd)}.expressive-code .ec-line.mark .code::before,.expressive-code .ec-line.ins .code::before,.expressive-code .ec-line.del .code::before{display:block;position:absolute;left:0;box-sizing:border-box;content:var(--tmLabel, &apos; &apos;);padding-inline-start:var(--ec-tm-lineDiffIndMargLeft);text-align:center;white-space:pre}.expressive-code .ec-line.mark.tm-label .code::before,.expressive-code .ec-line.ins.tm-label .code::before,.expressive-code .ec-line.del.tm-label .code::before{background:var(--ecLineBrdCol);padding:0 calc(var(--ec-tm-lineMarkerLabelPadInl) + var(--ec-tm-lineMarkerAccentWd)) 0 var(--ec-tm-lineMarkerLabelPadInl);color:var(--ec-tm-lineMarkerLabelCol)}.expressive-code .ec-line mark{--tmInlineBgCol:var(--ec-tm-markBg);--tmInlineBrdCol:var(--ec-tm-markBrdCol)}.expressive-code .ec-line ins{--tmInlineBgCol:var(--ec-tm-insBg);--tmInlineBrdCol:var(--ec-tm-insBrdCol)}.expressive-code .ec-line del{--tmInlineBgCol:var(--ec-tm-delBg);--tmInlineBrdCol:var(--ec-tm-delBrdCol)}.expressive-code .ec-line mark,.expressive-code .ec-line ins,.expressive-code .ec-line del{all:unset;display:inline-block;position:relative;--tmBrdL:var(--ec-tm-inlMarkerBrdWd);--tmBrdR:var(--ec-tm-inlMarkerBrdWd);--tmRadL:var(--ec-tm-inlMarkerBrdRad);--tmRadR:var(--ec-tm-inlMarkerBrdRad);margin-inline:0.025rem;padding-inline:var(--ec-tm-inlMarkerPad);border-radius:var(--tmRadL) var(--tmRadR) var(--tmRadR) var(--tmRadL);background:var(--tmInlineBgCol);background-clip:padding-box}.expressive-code .ec-line mark.open-start,.expressive-code .ec-line ins.open-start,.expressive-code .ec-line del.open-start{margin-inline-start:0;padding-inline-start:0;--tmBrdL:0px;--tmRadL:0}.expressive-code .ec-line mark.open-end,.expressive-code .ec-line ins.open-end,.expressive-code .ec-line del.open-end{margin-inline-end:0;padding-inline-end:0;--tmBrdR:0px;--tmRadR:0}.expressive-code .ec-line mark::before,.expressive-code .ec-line ins::before,.expressive-code .ec-line del::before{content:&apos;&apos;;position:absolute;pointer-events:none;display:inline-block;inset:0;border-radius:var(--tmRadL) var(--tmRadR) var(--tmRadR) var(--tmRadL);border:var(--ec-tm-inlMarkerBrdWd) solid var(--tmInlineBrdCol);border-inline-width:var(--tmBrdL) var(--tmBrdR)}.expressive-code .frame{all:unset;position:relative;display:block;--header-border-radius:calc(var(--ec-brdRad) + var(--ec-brdWd));--tab-border-radius:calc(var(--ec-frm-edTabBrdRad) + var(--ec-brdWd));--button-spacing:0.4rem;--code-background:var(--ec-frm-edBg);border-radius:var(--header-border-radius);box-shadow:var(--ec-frm-frameBoxShdCssVal)}.expressive-code .frame .header{display:none;z-index:1;position:relative;border-radius:var(--header-border-radius) var(--header-border-radius) 0 0}.expressive-code .frame.has-title pre,.expressive-code .frame.has-title code,.expressive-code .frame.is-terminal pre,.expressive-code .frame.is-terminal code{border-top:none;border-top-left-radius:0;border-top-right-radius:0}.expressive-code .frame .title:empty:before{content:&apos;\a0&apos;}.expressive-code .frame.has-title:not(.is-terminal){--button-spacing:calc(1.9rem + 2 * (var(--ec-uiPadBlk) + var(--ec-frm-edActTabIndHt)))}.expressive-code .frame.has-title:not(.is-terminal) .title{position:relative;color:var(--ec-frm-edActTabFg);background:var(--ec-frm-edActTabBg);background-clip:padding-box;margin-block-start:var(--ec-frm-edTabsMargBlkStart);padding:calc(var(--ec-uiPadBlk) + var(--ec-frm-edActTabIndHt)) var(--ec-uiPadInl);border:var(--ec-brdWd) solid var(--ec-frm-edActTabBrdCol);border-radius:var(--tab-border-radius) var(--tab-border-radius) 0 0;border-bottom:none;overflow:hidden}.expressive-code .frame.has-title:not(.is-terminal) .title::after{content:&apos;&apos;;position:absolute;pointer-events:none;inset:0;border-top:var(--ec-frm-edActTabIndHt) solid var(--ec-frm-edActTabIndTopCol);border-bottom:var(--ec-frm-edActTabIndHt) solid var(--ec-frm-edActTabIndBtmCol)}.expressive-code .frame.has-title:not(.is-terminal) .header{display:flex;background:linear-gradient(to top, var(--ec-frm-edTabBarBrdBtmCol) var(--ec-brdWd), transparent var(--ec-brdWd)),linear-gradient(var(--ec-frm-edTabBarBg), var(--ec-frm-edTabBarBg));background-repeat:no-repeat;padding-inline-start:var(--ec-frm-edTabsMargInlStart)}.expressive-code .frame.has-title:not(.is-terminal) .header::before{content:&apos;&apos;;position:absolute;pointer-events:none;inset:0;border:var(--ec-brdWd) solid var(--ec-frm-edTabBarBrdCol);border-radius:inherit;border-bottom:none}.expressive-code .frame.is-terminal{--button-spacing:calc(1.9rem + var(--ec-brdWd) + 2 * var(--ec-uiPadBlk));--code-background:var(--ec-frm-trmBg)}.expressive-code .frame.is-terminal .header{display:flex;align-items:center;justify-content:center;padding-block:var(--ec-uiPadBlk);padding-block-end:calc(var(--ec-uiPadBlk) + var(--ec-brdWd));position:relative;font-weight:500;letter-spacing:0.025ch;color:var(--ec-frm-trmTtbFg);background:var(--ec-frm-trmTtbBg);border:var(--ec-brdWd) solid var(--ec-brdCol);border-bottom:none}.expressive-code .frame.is-terminal .header::before{content:&apos;&apos;;position:absolute;pointer-events:none;left:var(--ec-uiPadInl);width:2.1rem;height:0.56rem;line-height:0;background-color:var(--ec-frm-trmTtbDotsFg);opacity:var(--ec-frm-trmTtbDotsOpa);-webkit-mask-image:var(--ec-frm-trmIcon);-webkit-mask-repeat:no-repeat;mask-image:var(--ec-frm-trmIcon);mask-repeat:no-repeat}.expressive-code .frame.is-terminal .header::after{content:&apos;&apos;;position:absolute;pointer-events:none;inset:0;border-bottom:var(--ec-brdWd) solid var(--ec-frm-trmTtbBrdBtmCol)}.expressive-code .frame pre{background:var(--code-background)}.expressive-code .copy{display:flex;gap:0.25rem;flex-direction:row;position:absolute;inset-block-start:calc(var(--ec-brdWd) + var(--button-spacing));inset-inline-end:calc(var(--ec-brdWd) + var(--ec-uiPadInl) / 2)}@media (scripting: none){.expressive-code .copy{display:none}}.expressive-code .copy{direction:ltr;unicode-bidi:isolate}.expressive-code .copy button{position:relative;align-self:flex-end;margin:0;padding:0;border:none;border-radius:0.2rem;z-index:1;cursor:pointer;transition-property:opacity, background, border-color;transition-duration:0.2s;transition-timing-function:cubic-bezier(0.25, 0.46, 0.45, 0.94);width:2.5rem;height:2.5rem;background:var(--code-background);opacity:0.75}.expressive-code .copy button div{position:absolute;inset:0;border-radius:inherit;background:var(--ec-frm-inlBtnBg);opacity:var(--ec-frm-inlBtnBgIdleOpa);transition-property:inherit;transition-duration:inherit;transition-timing-function:inherit}.expressive-code .copy button::before{content:&apos;&apos;;position:absolute;pointer-events:none;inset:0;border-radius:inherit;border:var(--ec-brdWd) solid var(--ec-frm-inlBtnBrd);opacity:var(--ec-frm-inlBtnBrdOpa)}.expressive-code .copy button::after{content:&apos;&apos;;position:absolute;pointer-events:none;inset:0;background-color:var(--ec-frm-inlBtnFg);-webkit-mask-image:var(--ec-frm-copyIcon);-webkit-mask-repeat:no-repeat;mask-image:var(--ec-frm-copyIcon);mask-repeat:no-repeat;margin:0.475rem;line-height:0}.expressive-code .copy button:hover,.expressive-code .copy button:focus:focus-visible{opacity:1}.expressive-code .copy button:hover div,.expressive-code .copy button:focus:focus-visible div{opacity:var(--ec-frm-inlBtnBgHoverOrFocusOpa)}.expressive-code .copy button:active{opacity:1}.expressive-code .copy button:active div{opacity:var(--ec-frm-inlBtnBgActOpa)}.expressive-code .copy .feedback{--tooltip-arrow-size:0.35rem;--tooltip-bg:var(--ec-frm-tooltipSuccessBg);color:var(--ec-frm-tooltipSuccessFg);pointer-events:none;user-select:none;-webkit-user-select:none;position:relative;align-self:center;background-color:var(--tooltip-bg);z-index:99;padding:0.125rem 0.75rem;border-radius:0.2rem;margin-inline-end:var(--tooltip-arrow-size);opacity:0;transition-property:opacity, transform;transition-duration:0.2s;transition-timing-function:ease-in-out;transform:translate3d(0, 0.25rem, 0)}.expressive-code .copy .feedback::after{content:&apos;&apos;;position:absolute;pointer-events:none;top:calc(50% - var(--tooltip-arrow-size));inset-inline-end:calc(-2 * (var(--tooltip-arrow-size) - 0.5px));border:var(--tooltip-arrow-size) solid transparent;border-inline-start-color:var(--tooltip-bg)}.expressive-code .copy .feedback.show{opacity:1;transform:translate3d(0, 0, 0)}@media (hover: hover){.expressive-code{}.expressive-code .copy button{opacity:0;width:2rem;height:2rem}.expressive-code .frame:hover .copy button:not(:hover),.expressive-code .frame:focus-within :focus-visible ~ .copy button:not(:hover),.expressive-code .frame .copy .feedback.show ~ button:not(:hover){opacity:0.75}}.expressive-code :nth-child(1 of .ec-line) .code{padding-inline-end:calc(2rem + var(--ec-codePadInl))}:root{--ec-brdRad:0.75rem;--ec-brdWd:1.5px;--ec-brdCol:var(--code-line);--ec-codeFontFml:var(--font-code);--ec-codeFontSize:0.875rem;--ec-codeFontWg:400;--ec-codeLineHt:1.75;--ec-codePadBlk:1rem;--ec-codePadInl:1.125rem;--ec-codeBg:var(--code-bg);--ec-codeFg:#e6edf3;--ec-codeSelBg:#264f78;--ec-gtrFg:#6e7681;--ec-gtrBrdCol:#6e768133;--ec-gtrBrdWd:1.5px;--ec-gtrHlFg:#e6edf3;--ec-uiFontFml:var(--font-mono);--ec-uiFontSize:0.75rem;--ec-uiFontWg:400;--ec-uiLineHt:1.65;--ec-uiPadBlk:0.25rem;--ec-uiPadInl:1rem;--ec-uiSelBg:#6e768166;--ec-uiSelFg:#e6edf3;--ec-focusBrd:#1f6feb;--ec-sbThumbCol:#8b949e33;--ec-sbThumbHoverCol:#8b949e3d;--ec-tm-lineMarkerAccentMarg:0rem;--ec-tm-lineMarkerAccentWd:0.15rem;--ec-tm-lineMarkerLabelPadInl:0.2rem;--ec-tm-lineMarkerLabelCol:white;--ec-tm-lineDiffIndMargLeft:0.3rem;--ec-tm-inlMarkerBrdWd:1.5px;--ec-tm-inlMarkerBrdRad:0.2rem;--ec-tm-inlMarkerPad:0.15rem;--ec-tm-insDiffIndContent:&apos;+&apos;;--ec-tm-delDiffIndContent:&apos;-&apos;;--ec-tm-markBg:#264a8980;--ec-tm-markBrdCol:#5570b3d0;--ec-tm-insBg:#26561c80;--ec-tm-insBrdCol:#4e7e41d0;--ec-tm-insDiffIndCol:#7eb070d0;--ec-tm-delBg:#81322b80;--ec-tm-delBrdCol:#ae594fd0;--ec-tm-delDiffIndCol:#e68a7ed0;--ec-frm-shdCol:#0000005b;--ec-frm-frameBoxShdCssVal:none;--ec-frm-edActTabBg:var(--code-bg);--ec-frm-edActTabFg:var(--code-muted);--ec-frm-edActTabBrdCol:transparent;--ec-frm-edActTabIndHt:1.5px;--ec-frm-edActTabIndTopCol:transparent;--ec-frm-edActTabIndBtmCol:#0d1117;--ec-frm-edTabsMargInlStart:0;--ec-frm-edTabsMargBlkStart:0;--ec-frm-edTabBrdRad:0.75rem;--ec-frm-edTabBarBg:var(--code-bg);--ec-frm-edTabBarBrdCol:var(--code-line);--ec-frm-edTabBarBrdBtmCol:var(--code-line);--ec-frm-edBg:var(--code-bg);--ec-frm-trmTtbFg:var(--code-muted);--ec-frm-trmTtbDotsFg:var(--code-muted);--ec-frm-trmTtbDotsOpa:0.15;--ec-frm-trmTtbBg:var(--code-bg);--ec-frm-trmTtbBrdBtmCol:var(--code-line);--ec-frm-trmBg:var(--code-bg);--ec-frm-inlBtnBg:var(--code-ink);--ec-frm-inlBtnBgIdleOpa:0;--ec-frm-inlBtnBgHoverOrFocusOpa:0.2;--ec-frm-inlBtnBgActOpa:0.3;--ec-frm-inlBtnFg:var(--code-ink);--ec-frm-inlBtnBrd:var(--code-line);--ec-frm-inlBtnBrdOpa:0.4;--ec-frm-tooltipSuccessBg:var(--color-emerald);--ec-frm-tooltipSuccessFg:var(--color-bg);--ec-frm-copyIcon:url(&quot;data:image/svg+xml,%3Csvg%20xmlns%3D&apos;http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg&apos;%20viewBox%3D&apos;0%200%2024%2024&apos;%20fill%3D&apos;none&apos;%20stroke%3D&apos;black&apos;%20stroke-width%3D&apos;1.75&apos;%3E%3Cpath%20d%3D&apos;M3%2019a2%202%200%200%201-1-2V2a2%202%200%200%201%201-1h13a2%202%200%200%201%202%201&apos;%2F%3E%3Crect%20x%3D&apos;6&apos;%20y%3D&apos;5&apos;%20width%3D&apos;16&apos;%20height%3D&apos;18&apos;%20rx%3D&apos;1.5&apos;%20ry%3D&apos;1.5&apos;%2F%3E%3C%2Fsvg%3E&quot;);--ec-frm-trmIcon:url(&quot;data:image/svg+xml,%3Csvg%20xmlns%3D&apos;http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg&apos;%20viewBox%3D&apos;0%200%2060%2016&apos;%20preserveAspectRatio%3D&apos;xMidYMid%20meet&apos;%3E%3Ccircle%20cx%3D&apos;8&apos;%20cy%3D&apos;8&apos;%20r%3D&apos;8&apos;%2F%3E%3Ccircle%20cx%3D&apos;30&apos;%20cy%3D&apos;8&apos;%20r%3D&apos;8&apos;%2F%3E%3Ccircle%20cx%3D&apos;52&apos;%20cy%3D&apos;8&apos;%20r%3D&apos;8&apos;%2F%3E%3C%2Fsvg%3E&quot;)}.expressive-code .ec-line :where(span[style^=&apos;--&apos;]:not([class])){color:var(--0, inherit);background-color:var(--0bg, transparent);font-style:var(--0fs, inherit);font-weight:var(--0fw, inherit);text-decoration:var(--0td, inherit)}&lt;/style&gt;&lt;script type=&quot;module&quot; src=&quot;/_astro/ec.0vx5m.js&quot;&gt;&lt;/script&gt;&lt;figure class=&quot;frame has-title&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;Lua&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;lua&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;if&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; redis.&lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;call&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;&quot;get&quot;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;, KEYS[&lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;]) &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;==&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; ARGV[&lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;] &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;then&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; redis.&lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;call&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;&quot;del&quot;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;, KEYS[&lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;])&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;else&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;0&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;end&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;if redis.call(&amp;#x22;get&amp;#x22;, KEYS[1]) == ARGV[1] then    return redis.call(&amp;#x22;del&amp;#x22;, KEYS[1])else    return 0end&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;কিন্তু এখানে একটি অত্যন্ত সূক্ষ্ম পার্থক্য মাথায় রাখতে হবে, Random Lock Token মূলত Ownership Identify করে, কিন্তু এটি Stale Worker কে Prevent করতে পারে না।&lt;/p&gt;
&lt;div class=&quot;callout&quot; role=&quot;note&quot; data-type=&quot;warning&quot;&gt;
&lt;p class=&quot;callout-title&quot;&gt;Dangerous Assumption&lt;/p&gt;
&lt;p&gt;Random Lock Token আপনাকে শুধুমাত্র Safe Unlock এর গ্যারান্টি দেয়। এটি কখনোই গ্যারান্টি দেয় না যে আপনার Worker এর Execution Context এখনও Valid আছে।&lt;/p&gt;
&lt;/div&gt;
&lt;h2 id=&quot;redis-failover-and-the-split-brain-problem&quot;&gt;Redis Failover and the Split-Brain Problem&lt;/h2&gt;
&lt;p&gt;এখন পর্যন্ত আমাদের Architecture একটি Single Redis Instance এর ওপর নির্ভরশীল ছিল, কিন্তু Production System এ Redis নিজেই Fail করতে পারে। ধরুন আপনার Architecture এ একটি Redis Primary এবং একটি Redis Replica আছে। Worker A Primary Node থেকে Lock নিল, কিন্তু ঠিক তারপরেই Primary Node Crash করল। Lock এর Data Replica তে Synchronize বা Replicate হওয়ার আগেই Replica Node টি নতুন Primary হিসেবে Promote হয়ে গেল। এই অবস্থায় Worker B নতুন Primary Node এ Request পাঠিয়ে সফলভাবে Lock Acquire করে ফেলল। এখন Worker A ভাবছে সে Lock এর মালিক, এবং Worker B ও ভাবছে সে Lock এর মালিক। এটি Distributed Locking এর সবচেয়ে Dangerous Failure Mode, যাকে Split-Brain Problem বলা হয়।&lt;/p&gt;
&lt;figure&gt;&lt;img src=&quot;https://raw.githubusercontent.com/rafeuddaraj/rafes-blog-assets/refs/heads/distributed-locks-redlock-fencing-tokens-explained/assets/redis-failover-split-brain.svg&quot; alt=&quot;Redis Failover Split Brain&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1600&quot; height=&quot;900&quot;&gt;&lt;figcaption&gt;Redis Failover Split Brain&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;এখানে একটি গুরুত্বপূর্ণ Engineering Principle Establish করা প্রয়োজন, High Availability মানেই Correctness নয়। Redis Replica Failover আপনার System কে Available রাখতে সাহায্য করে ঠিকই, কিন্তু Lock State যদি Perfectly Preserved না হয়, তবে Availability বাড়ানোর এই Process টিই আপনার System এর Safety Break করতে পারে। আমরা আসলে এমন একটি Locking Mechanism চাই যেখানে Infrastructure Fail করলেও দুজন Worker কখনোই Simultaneously Valid Owner হতে পারবে না।&lt;/p&gt;
&lt;h2 id=&quot;redlock-and-the-illusion-of-time&quot;&gt;Redlock and the Illusion of Time&lt;/h2&gt;
&lt;p&gt;Single Redis Node এর Failure Handle করার জন্য Redlock Algorithm এর আবির্ভাব ঘটে। Redlock মূলত একটি Redis এর বদলে একাধিক Independent Redis Instance ব্যবহার করে। ধরুন আপনার কাছে পাঁচটি Independent Redis Node আছে। একজন Worker এই পাঁচটি Node এই Lock Acquire করার চেষ্টা করবে এবং Majority বা অন্তত তিনটি Node এ সফলভাবে Lock পেলে তবেই সেটিকে Valid Lock হিসেবে ধরে নেওয়া হবে। যদি দুজন Worker একই সময়ে Lock পেতে চায়, তবে তাদের Majority Set এর মধ্যে অন্তত একটি Common Node থাকবেই, যার ফলে Distributed Quorum ধারণাটি কাজ করে। কিন্তু শুধু Majority পেলেই হবে না, Acquisition এর জন্য যে সময় ব্যয় হয়েছে সেটিও অত্যন্ত গুরুত্বপূর্ণ।&lt;/p&gt;
&lt;p&gt;Redlock এর Acquisition Flow অনুযায়ী, Worker প্রথমে একটি Start Timestamp রেকর্ড করে এবং এক এক করে পাঁচটি Node এ Lock Try করে। Majority পাওয়ার পর সে চেক করে দেখে যে Lock Acquire করতে মোট কত সময় লেগেছে। যদি Elapsed Time অতিক্রান্ত হওয়ার পরও Validity Remaining থাকে, তবেই Lock Acquired বলে গণ্য হয়। কিন্তু এখানেই Redlock এর সবচেয়ে বড় Hidden Assumption লুকিয়ে আছে, আর সেটি হলো Time। Redlock এর Validity পুরোপুরি Time Measurement এর ওপর নির্ভরশীল, কিন্তু Real Production Environment এ Network Delay, Clock Drift, Process Scheduling, Garbage Collection Pause, CPU Starvation, VM Pause, Container Throttling বা Network Partition এর মতো অসংখ্য ঘটনা ঘটতে পারে। একজন Worker নিজের Perspective থেকে ভাবতে পারে তার Lock এখনও Valid, কিন্তু Distributed System এর অন্য অংশের Perspective থেকে সেই Lease অনেক আগেই Expire হয়ে যেতে পারে।&lt;/p&gt;
&lt;div class=&quot;callout&quot; role=&quot;note&quot; data-type=&quot;warning&quot;&gt;
&lt;p class=&quot;callout-title&quot;&gt;Redlock Vulnerability&lt;/p&gt;
&lt;p&gt;Majority Intersection একা পুরো Correctness Problem Solve করতে পারে না। Distributed Systems এ Timing এবং Network Delay সবসময় Unpredictable থাকে।&lt;/p&gt;
&lt;/div&gt;
&lt;h2 id=&quot;the-most-dangerous-failure-paused-worker&quot;&gt;The Most Dangerous Failure: Paused Worker&lt;/h2&gt;
&lt;p&gt;পুরো Distributed Locking Architecture এর সবচেয়ে Central Failure Scenario হলো Paused Worker। ধরুন Worker A সফলভাবে Lock Acquire করে কাজ শুরু করল। হঠাৎ করে Worker A একটি দীর্ঘ Garbage Collection Pause, CPU Starvation, VM Suspension বা Network Stall এর শিকার হয়ে Pause হয়ে গেল। এই Pause চলাকালীন সময়ে তার Lock এর Lease Expire হয়ে গেল। সিস্টেমের নিয়ম অনুযায়ী Worker B নতুন Lock Acquire করে তার কাজ সফলভাবে শেষ করল। কিছুক্ষণ পর Worker A এর Pause শেষ হলো এবং সে আবার Resume করল। Worker A কিন্তু জানে না যে সে Pause হয়েছিল, সে এখনও ভাবছে Lock টি তারই আছে এবং সে তার পুরনো Operation ডাটাবেজে Write করতে গেল।&lt;/p&gt;
&lt;figure&gt;&lt;img src=&quot;https://raw.githubusercontent.com/rafeuddaraj/rafes-blog-assets/refs/heads/distributed-locks-redlock-fencing-tokens-explained/assets/paused-worker-timeline.svg&quot; alt=&quot;Paused Worker Timeline&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;800&quot; height=&quot;450&quot;&gt;&lt;figcaption&gt;Paused Worker Timeline&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;এখানে আসল সমস্যাটি হলো, পুরনো Worker কে কেউ থামায়নি। Lock Expire হওয়া মানে এই নয় যে Worker A এর Process Automatically Stop হয়ে যাবে। Lock Release বা Expiry শুধুমাত্র System এর State পরিবর্তন করে, কিন্তু Running Code Execution কে Physically Kill করতে পারে না। এটি Distributed Systems এর একটি Fundamental Truth।&lt;/p&gt;
&lt;h2 id=&quot;fencing-tokens-the-ultimate-correctness-guarantee&quot;&gt;Fencing Tokens: The Ultimate Correctness Guarantee&lt;/h2&gt;
&lt;p&gt;Paused Worker এর এই ভয়াবহ সমস্যা সমাধানের জন্য আমাদের Fencing Token কনসেপ্টটি Introduce করতে হবে। ধরুন Worker A যখন Lock নেয়, তখন সে শুধুমাত্র একটি Lock পায় না, বরং Lock Service তাকে একটি Monotonically Increasing Number দেয়, যেমন Token 33। কিছুক্ষণ পর Lease Expire হওয়ার পর Worker B যখন নতুন Lock নেয়, সে পায় Token 34। এখন Resource নিজে জানে যে তার কাছে আসা Last Accepted Token হলো 34। Worker A যদি Pause থেকে ফিরে এসে Token 33 দিয়ে Write করার চেষ্টা করে, তবে Resource দেখবে 33 বর্তমান 34 এর চেয়ে ছোট, তাই সে সরাসরি Operation Reject করে দেবে। অন্যদিকে Worker B এর Token 34 হওয়ায় সেটি অনায়াসেই Accept হয়ে যাবে।&lt;/p&gt;
&lt;figure&gt;&lt;img src=&quot;https://raw.githubusercontent.com/rafeuddaraj/rafes-blog-assets/refs/heads/distributed-locks-redlock-fencing-tokens-explained/assets/complete-failure-timeline.svg&quot; alt=&quot;Complete Failure Timeline&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;900&quot; height=&quot;300&quot;&gt;&lt;figcaption&gt;Complete Failure Timeline&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;এখানে মূল Idea হলো, পুরনো Worker এর Process Alive থাকলেও তার Authority এখন Obsolete হয়ে গেছে। Random Lock Token এবং Fencing Token এর মধ্যে পার্থক্যটি খুব পরিষ্কারভাবে বোঝা জরুরি। Random Lock Token শুধুমাত্র Uniqueness দিতে পারে, কিন্তু Ordering দিতে পারে না। Fencing Token এর একটি Ordering থাকে, যা প্রমাণ করে কোন Owner টি Newer। Random Lock Token উত্তর দেয় Who Owns This Lock, আর Fencing Token উত্তর দেয় Which Owner Is Newer।&lt;/p&gt;
&lt;div class=&quot;callout&quot; role=&quot;note&quot; data-type=&quot;note&quot;&gt;
&lt;p class=&quot;callout-title&quot;&gt;Fencing Rule&lt;/p&gt;
&lt;p&gt;Token জেনারেট করা নিজেই একটি Coordination Problem। Database Sequence, ZooKeeper Version বা কোনো Consensus-Backed Counter ব্যবহার করে এই Monotonically Increasing Token তৈরি করতে হয়।&lt;/p&gt;
&lt;/div&gt;
&lt;h2 id=&quot;database-level-fencing-enforcement&quot;&gt;Database-Level Fencing Enforcement&lt;/h2&gt;
&lt;p&gt;Fencing Token কে সঠিকভাবে কাজে লাগানোর জন্য একটি Common Architectural Mistake এড়িয়ে চলতে হবে। Lock Service থেকে Token নিয়ে Worker যদি সরাসরি Database এ Write করে এবং Database যদি Token সম্পর্কে কিছুই না জানে, তবে Fencing Token দিয়ে কোনো লাভ নেই। Correct Architecture হলো, Database বা Resource কে নিজেই Stale Operation Reject করতে হবে।&lt;/p&gt;
&lt;figure&gt;&lt;img src=&quot;https://raw.githubusercontent.com/rafeuddaraj/rafes-blog-assets/refs/heads/distributed-locks-redlock-fencing-tokens-explained/assets/fencing-token-database.svg&quot; alt=&quot;Fencing Token Database&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;800&quot; height=&quot;400&quot;&gt;&lt;figcaption&gt;Fencing Token Database&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;একটি Practical PostgreSQL Example চিন্তা করুন। আমরা একটি Table তৈরি করতে পারি যেখানে &lt;code&gt;id&lt;/code&gt;, &lt;code&gt;value&lt;/code&gt; এবং &lt;code&gt;last_fencing_token&lt;/code&gt; নামের Column থাকবে। Worker যখন Write করবে, সে তার Token টিও পাঠাবে। Query টি দেখতে অনেকটা এরকম হবে:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame has-title&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;SQL&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;sql&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;UPDATE&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; resources&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;SET&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;value&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; $&lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;last_fencing_token &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; $&lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;2&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;WHERE&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; id &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; $&lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;3&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;AND&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; last_fencing_token &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; $&lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;2&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;UPDATE resourcesSET    value = $1,    last_fencing_token = $2WHERE id = $3  AND last_fencing_token &lt; $2;&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;এখানে Database নিজেই চেক করছে যে Incoming Token টি Current Token এর চেয়ে বড় কি না। যদি Worker A Token 103 নিয়ে আসে, কিন্তু Database এর Current Token 104 থাকে, তবে Condition Match করবে না এবং Update Fail করবে। Database আপডেট এমন হতে হবে যেন Stale Worker Application লেভেলে Bug তৈরি করলেও Database লেভেলে তা Rejected হয়। Correctness-Critical Validation সবসময় Authoritative Resource এর কাছেই Enforce করা উচিত।&lt;/p&gt;
&lt;h2 id=&quot;architectural-recap-and-production-checklist&quot;&gt;Architectural Recap and Production Checklist&lt;/h2&gt;
&lt;p&gt;Network Partition বা Node Failure এর সময় Safety এবং Availability এর Trade-off বুঝতে পারা একজন Elite Architect এর কাজ। Distributed Lock কখনোই শুধুমাত্র একটি &quot;Lock Acquired&quot; Boolean নয়, এর সাথে Failure Model ও জড়িত থাকে। Long-Running Operation এর ক্ষেত্রে Worker Heartbeat দিয়ে Lease Extend করতে পারে, কিন্তু Lease Renewal Premature Expiry কমাতে পারলেও Stale Worker Problem কে Eliminate করতে পারে না। Distributed Systems এ Failed Request Retry হওয়া খুব স্বাভাবিক একটি ঘটনা, তাই Lock এর সঙ্গে Fencing, Idempotency এবং Atomic Resource Update কে একসঙ্গে Design করতে হয়।&lt;/p&gt;
&lt;p&gt;সব জায়গায় Redis Lock ব্যবহার করা ঠিক নয়। Unique Constraint, Database Transaction, &lt;code&gt;SELECT ... FOR UPDATE&lt;/code&gt;, Advisory Lock বা Optimistic Concurrency Control এর মতো Database এর Native Mechanism গুলো অনেক ক্ষেত্রেই Better Coordination প্রদান করতে পারে। যদি শুধুমাত্র Duplicate Work কমানো উদ্দেশ্য হয়, তবে Simple Redis Lock যথেষ্ট। কিন্তু Correctness Critical হলে Fencing অবশ্যই প্রয়োজন।&lt;/p&gt;
&lt;p&gt;Production এ কোনো Distributed Lock Design করার আগে নিচের চেকলিস্টটি অবশ্যই মিলিয়ে নিতে হবে:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;আপনি ঠিক কোন Resource টি Protect করছেন?&lt;/li&gt;
&lt;li&gt;Worker Crash করলে বা Work চলাকালীন Lease Expire হলে কী হবে?&lt;/li&gt;
&lt;li&gt;Stale Worker কি এখনও Execute এবং Write করতে পারে?&lt;/li&gt;
&lt;li&gt;Fencing Token কে Generate করছে এবং Resource কি সেটি Validate করছে?&lt;/li&gt;
&lt;li&gt;Network Partition, Redis Failover, Process Pause বা Client Retry এর সময় সিস্টেমের Behaviour কেমন হবে?&lt;/li&gt;
&lt;li&gt;Operation টি Idempotent করা সম্ভব কি না এবং Database নিজেই এই Problem Solve করতে পারে কি না?&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Lock বলে দেয় কে Critical Section এ ঢুকতে পারবে, Lease বলে দেয় সেই Permission কতক্ষণ Valid, Redlock Multiple Node ব্যবহার করে Distributed Lease Establish করার চেষ্টা করে, আর Fencing Token নিশ্চিত করে পুরনো Stale Worker যেন কোনোভাবেই Resource Corrupt করতে না পারে। A lock does not stop a paused process, a TTL does not kill a stale worker, and a random lock ID does not establish ordering। Production Distributed Systems এ এই লেয়ারগুলোকে আলাদা করে চিনতে পারাটাই সবচেয়ে গুরুত্বপূর্ণ Engineering Skill।&lt;/p&gt;</content:encoded><category>System Design</category><category>Distributed Systems</category><category>Redis</category><category>Architecture</category><category>Node.js</category><category>Redlock</category><category>System Design</category></item><item><title>OOP বনাম Functional Programming - আন্ডার-দ্য-হুড আর্কিটেকচার কীভাবে কাজ করে?</title><link>https://www.rafeuddaraj.me/bn/blog/deep-dive-oop-vs-functional-programming-architecture/</link><guid isPermaLink="true">https://www.rafeuddaraj.me/bn/blog/deep-dive-oop-vs-functional-programming-architecture/</guid><description>স্কেলড প্রডাকশন সিস্টেমে স্টেট ম্যানেজমেন্ট ক্রাইসিস এবং আর্কিটেকচারাল ডিসিশনের জন্য Object-Oriented Programming (OOP) বনাম Functional Programming (FP) এর ইন-ডেপথ লো-লেভেল অ্যানালাইসিস।</description><pubDate>Fri, 31 Jul 2026 10:58:32 GMT</pubDate><content:encoded>&lt;p&gt;স্কেলড প্রডাকশন সিস্টেমে কাজ করার সময় আপনি হয়তো একটি সাধারণ প্যাটার্ন খেয়াল করেছেন। বড় প্রজেক্টে যতগুলো ক্রিটিক্যাল বাগ তৈরি হয়, তার প্রায় ৮০ শতাংশই আসে অবজেক্টের ইন্টারনাল স্টেট মিউটেশন এবং অনিয়ন্ত্রিত সাইড-ইফেক্ট থেকে। ডেভেলপাররা প্রায়শই Object-Oriented Programming (OOP) এবং Functional Programming (FP) কে কেবল একটি কালচারাল ওয়ার বা সিনট্যাক্স চয়েস হিসেবে ভুল করেন। আসল পার্থক্য সিনট্যাক্সে নয়। আসল পার্থক্য হলো কীভাবে এই দুটো প্যারাডাইম Memory, State Variability এবং Control Flow হ্যান্ডেল করে। ভুল স্টেট ম্যানেজমেন্ট চয়েসের কারণে আপনার সিস্টেমে Concurrency Race Condition, Garbage Collection Pressure এবং Scalability Bottleneck তৈরি হতে পারে। আজকের এই Deep Dive এর মূল লক্ষ্য হলো অন্ধভাবে কোনো ডগমা ফলো না করে, আন্ডার-দ্য-হুড মেমরি ও আর্কিটেকচারাল ওয়ার্কফ্লো ডিসেক্ট করা। এর মাধ্যমে আপনি আপনার প্রজেক্টের জন্য সঠিক ডিজাইন ডিসিশন নেওয়ার একটি ক্লিয়ার গাইডলাইন পাবেন।&lt;/p&gt;
&lt;h2 id=&quot;১-the-foundational-mental-model-ও-analogy&quot;&gt;১. The Foundational Mental Model ও Analogy&lt;/h2&gt;
&lt;p&gt;লো-লেভেল আর্কিটেকচারে যাওয়ার আগে আমাদের স্টেট এবং ট্রান্সফরমেশনের হাই-লেভেল থিওরি বুঝতে হবে। OOP এর মেন্টাল মডেলকে আপনি একটি স্বাধীন এনটিটি বা ব্যাংকের ভোল্ট হিসেবে চিন্তা করতে পারেন। ডাটা এই ভোল্টের ভেতরে লকড থাকে, এবং কেবল নির্দিষ্ট মেথড বা ইন্টারফেস দিয়ে আপনি ভেতরের স্টেট পরিবর্তন করতে পারেন। অন্যদিকে FP এর মেন্টাল মডেল হলো একটি অ্যাসেম্বলি লাইন বা ওয়াটার পিউরিফায়ার। ডাটা এই পাইপলাইনের ভেতর দিয়ে ফ্লো করে, প্রতিটি ফাংশন ডাটাকে পরিবর্তন না করে সম্পূর্ণ নতুন ফরম্যাটের ডাটা জেনারেট করে আউটপুট দেয়।&lt;/p&gt;
&lt;p&gt;বিষয়টি পরিষ্কার করার জন্য আমরা একটি রিয়েল-ওয়ার্ল্ড Analogy ব্যবহার করতে পারি। OOP এর ক্ষেত্রে একটি স্মার্ট কার ক্লাসের Analogy চিন্তা করুন। কারের গিয়ার, এঞ্জিন এবং কারেন্ট স্পিড হলো ইন্টারনাল প্রাইভেট স্টেট। আপনি কেবল একটি accelerate মেথড কল করতে পারেন, কিন্তু সরাসরি স্পিড ভ্যালু মেমরিতে গিয়ে চেঞ্জ করতে পারেন না। কারটি নিজের স্টেট নিজেই ম্যানেজ করে। অপরদিকে FP এর ক্ষেত্রে একটি ডিজিটাল পাসপোর্ট ভ্যালিডেশন পাইপলাইনের Analogy চিন্তা করুন। মূল পাসপোর্ট সবসময় একই থাকে বা Immutable অবস্থায় থাকে। ভ্যালিডেশন ফাংশনগুলো ইনপুট হিসেবে পাসপোর্ট রিড করে এবং মডিফাই না করে একটি নতুন ভ্যালিডেশন রিপোর্ট রিটার্ন করে। এখানে ডাটা ফ্লো করে, কিন্তু অরিজিনাল সোর্স অফ ট্রুথ কখনো মিউটেট হয় না।&lt;/p&gt;
&lt;h2 id=&quot;২-under-the-hood-architecture-the-core-deep-dive&quot;&gt;২. Under-The-Hood Architecture (The Core Deep Dive)&lt;/h2&gt;
&lt;p&gt;এখন চলুন ইঞ্জিন লেভেলে মেমরি অ্যালোকেশন এবং এক্সিকিউশন মডেল কীভাবে কাজ করে তা ব্রেকডাউন করি। OOP under-the-hood কাজ করে Heap Allocation, Object Reference Graphs এবং Pointer Traversal এর মাধ্যমে। যখন আপনি একটি অবজেক্ট তৈরি করেন, ইঞ্জিন Heap এ মেমরি ব্লক অ্যালোকেট করে। পরবর্তীতে যখন আপনি স্টেট চেঞ্জ করেন, ইঞ্জিন সরাসরি পয়েন্টার ধরে মেমরিতে ইন-প্লেস রাইট করে। পারফরম্যান্স বুস্ট করার জন্য V8 ইঞ্জিনের মতো মডার্ন রানটাইমগুলো Inline Caches এবং Vtables ব্যবহার করে মেথড কল অপটিমাইজ করে।&lt;/p&gt;
&lt;p&gt;FP এর under-the-hood মেকানিজম সম্পূর্ণ ভিন্ন। এখানে Immutable Data Structures এবং Structural Sharing ব্যবহার করা হয়। যখন আপনি একটি স্টেট আপডেট করেন, FP পুরো মেমরি ব্লক কপি করে না। এর বদলে এটি Persistent Data Structures যেমন Trie Trees ব্যবহার করে। শুধুমাত্র যে নোডগুলো পরিবর্তন হয়েছে সেগুলোর জন্য নতুন মেমরি অ্যালোকেট হয়, আর বাকি অপরিবর্তিত নোডগুলো আগের রেফারেন্স শেয়ার করে। এর সাথে Pure Functions এবং Call Stack Frames মিলে এমন একটি আর্কিটেকচার তৈরি করে যেখানে কোনো ফাংশন বাইরের স্টেট সম্পর্কে জানে না।&lt;/p&gt;
&lt;figure&gt;&lt;img src=&quot;https://raw.githubusercontent.com/rafeuddaraj/rafes-blog-assets/refs/heads/deep-dive-oop-vs-functional-programming-architecture/assets/oop-vs-fp-memory-workflow.svg&quot; alt=&quot;OOP vs FP Memory Workflow&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1000&quot; height=&quot;500&quot;&gt;&lt;figcaption&gt;OOP vs FP Memory Workflow&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;Concurrency এবং Thread Safety মেকানিক্সের ক্ষেত্রে এই আর্কিটেকচারাল পার্থক্য বিশাল ইমপ্যাক্ট ফেলে। OOP তে Shared Mutable State থাকার কারণে যখন একাধিক থ্রেড একই মেমরি রেফারেন্সে রাইট করতে যায়, তখন Race Condition তৈরি হয়। এটি ঠেকানোর জন্য আপনাকে Locks বা Mutexes ব্যবহার করতে হয়, যা Latency বহুগুণ বাড়িয়ে দেয়। অপরদিকে FP তে Stateless Flow এবং ইমিউটেবল ডাটা থাকার কারণে জিরো সাইড-ইফেক্ট নিশ্চিত হয়। ফলে লক-ফ্রি থ্রেড সেফটি এবং প্যারালাল এক্সিকিউশন খুব সহজেই অর্জন করা যায়।&lt;/p&gt;
&lt;figure&gt;&lt;img src=&quot;https://raw.githubusercontent.com/rafeuddaraj/rafes-blog-assets/refs/heads/deep-dive-oop-vs-functional-programming-architecture/assets/concurrency-race-condition-vs-pure-pipeline.svg&quot; alt=&quot;Concurrency Race Condition vs Pure Pipeline&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1000&quot; height=&quot;500&quot;&gt;&lt;figcaption&gt;Concurrency Race Condition vs Pure Pipeline&lt;/figcaption&gt;&lt;/figure&gt;
&lt;h2 id=&quot;৩-step-by-step-execution-trace-ও-code-mechanics&quot;&gt;৩. Step-by-Step Execution Trace ও Code Mechanics&lt;/h2&gt;
&lt;p&gt;আর্কিটেকচারাল কনসেপ্টগুলো কীভাবে কোড লেভেলে কাজ করে তা বোঝার জন্য আমরা একটি ইউজার ইমেইল আপডেটের Execution Trace অ্যানালাইজ করব।&lt;/p&gt;
&lt;p&gt;প্রথমে Scenario A, অর্থাৎ OOP State Mutation Execution Trace বিবেচনা করুন। আপনি যখন &lt;code&gt;new User()&lt;/code&gt; কল করেন, ইঞ্জিন Heap এ মেমরি অ্যালোকেশন করে একটি ইন্সট্যান্স তৈরি করে। এরপর আপনি &lt;code&gt;user.updateEmail(&quot;new@email.com&quot;)&lt;/code&gt; মেথড ইনভোক করেন। এই মুহূর্তে Call Stack এ একটি Execution Context তৈরি হয় এবং &lt;code&gt;this&lt;/code&gt; পয়েন্টার ধরে Heap মেমরির আসল ফিল্ড রেজোলিউশন হয়। ইঞ্জিন সরাসরি ইন-প্লেস মেমরি রাইট করে, অর্থাৎ অরিজিনাল ডাটা মিউটেট হয়। যদি এই সেটারের ভেতর কোনো ডাটাবেস সিঙ্ক কল থাকে, তবে তা সাইড-ইফেক্ট ট্রিগার করে। পরবর্তীতে এই সাইড-ইফেক্ট ডেবাগ করা বা ট্রেস-ব্যাক করা অত্যন্ত কঠিন হয়ে পড়ে কারণ স্টেতের হিস্ট্রি মেমরিতে আর অস্তিত্ব রাখে না।&lt;/p&gt;
&lt;p&gt;এবার Scenario B, অর্থাৎ FP Immutable Transformation Execution Trace দেখুন। এখানে মূল &lt;code&gt;user&lt;/code&gt; অবজেক্টটি ফ্রিজড বা ইমিউটেবল হিসেবে মেমরিতে অবস্থান করে। আপনি যখন &lt;code&gt;updateEmail(user, &quot;new@email.com&quot;)&lt;/code&gt; পিওর ফাংশন কল করেন, Call Stack এ একদম আইসোলেটেড একটি Execution Frame তৈরি হয়। ইঞ্জিন Structural Sharing ব্যবহার করে কেবল পরিবর্তন হওয়া ইমেইল ফিল্ডের নতুন রেফারেন্স ক্রিয়েট করে, কিন্তু পুরোনো অবজেক্টের বাকি ফিল্ডগুলো রি-ইউজ করে। অবশেষে ফাংশনটি নতুন ইমিউটেবল অবজেক্ট রিটার্ন করে। এখানে জিরো মেমরি কলিশন ঘটে এবং ফাংশনের রিটার্ন ভ্যালু সবসময় রিপ্রোডুসিবল থাকে।&lt;/p&gt;
&lt;div class=&quot;callout&quot; role=&quot;note&quot; data-type=&quot;note&quot;&gt;
&lt;p class=&quot;callout-title&quot;&gt;Important&lt;/p&gt;
&lt;p&gt;OOP এর প্রধান শক্তি হলো Encapsulation, কিন্তু যখন একাধিক সার্ভিস একই ক্লাসের মেথড কল করে ইন্টারনাল স্টেট পরিবর্তন করে, তখন এটি Shared Mutable State এ রূপ নেয়। ডিস্ট্রিবিউটেড সিস্টেমে রেস কন্ডিশনের প্রধান কারণ হলো এই শেয়ারড স্টেট।&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;callout&quot; role=&quot;note&quot; data-type=&quot;warning&quot;&gt;
&lt;p class=&quot;callout-title&quot;&gt;Warning&lt;/p&gt;
&lt;p&gt;FP এর Immutability কোডকে চরম প্রেডিক্টেবল করে তোলে। তবে অতিরিক্ত অবজেক্ট অ্যালোকেশন এবং কপি-অন-রাইট প্যাটার্নস ব্যবহারে সতর্ক না হলে উচ্চ-থারুপুট সিস্টেমে Garbage Collection Overhead এবং Garbage Collection Pause তৈরি হতে পারে, যা Latency স্পাইক ঘটাবে।&lt;/p&gt;
&lt;/div&gt;
&lt;h2 id=&quot;৪-edge-cases-pitfalls-ও-trade-offs&quot;&gt;৪. Edge Cases, Pitfalls ও Trade-offs&lt;/h2&gt;
&lt;p&gt;যেকোনো সিস্টেম আর্কিটেকচারে পারফরম্যান্স বনাম মেইনটেনেবিলিটির একটি Trade-off থাকে। FP তে বারবার নতুন অবজেক্ট ক্রিয়েট করার ফলে মেমরি অ্যালোকেশন রেট বৃদ্ধি পায়, যা Garbage Collection এর উপর মারাত্মক প্রেশার ফেলে। যদিও Persistent Data Structures এবং Structural Sharing এই ওভারহেড অনেকাংশে কমিয়ে আনে, তবুও অত্যন্ত Memory Sensitive বা CPU-bound অ্যালগরিদমের ক্ষেত্রে এটি একটি ইস্যু হতে পারে। সেসব ক্ষেত্রে ইন-প্লেস মিউটেশন বা Imperative অ্যাপ্রোচ ফাস্টার পারফর্ম করে।&lt;/p&gt;
&lt;p&gt;অন্যদিকে OOP এর সবচেয়ে বড় ফাঁদ হলো Deep Inheritance Hell বা টাইটলি কাপল্ড অবজেক্ট রিলেশন। Joe Armstrong এর ভাষায় একে The Banana-Gorilla Problem বলা হয়, যেখানে একটি সাধারণ অবজেক্ট এক্সট্র্যাক্ট করতে গেলে পুরো এনভায়রনমেন্ট টেনে আনতে হয়। এর বিপরীতে FP তে Monad বা Currying এর মতো কনসেপ্টগুলো অনেক শক্তিশালী হলেও এর Steep Learning Curve পুরো টিমের অনবোর্ডিং চ্যালেঞ্জ বাড়িয়ে দিতে পারে। তাই আর্কিটেক্ট হিসেবে আপনাকে প্রজেক্টের সাইজ, টিমের সক্ষমতা এবং স্কেলেবিলিটির রিকোয়ারমেন্ট বুঝে সিদ্ধান্ত নিতে হবে।&lt;/p&gt;
&lt;div class=&quot;callout&quot; role=&quot;note&quot; data-type=&quot;tip&quot;&gt;
&lt;p class=&quot;callout-title&quot;&gt;Tip&lt;/p&gt;
&lt;p&gt;আর্কিটেকচারাল সুইট স্পট: মডিউল লেভেল ও সার্ভিস বাউন্ডারির জন্য Domain-Driven Design (OOP) ব্যবহার করুন। এর ফলে স্ট্রাকচার ক্লিন থাকবে। আর সার্ভিস ইন্টারনালের বিজনেস লজিক এবং ডাটা প্রসেসিংয়ের জন্য Pure Functions (FP) ব্যবহার করুন।&lt;/p&gt;
&lt;/div&gt;
&lt;h2 id=&quot;৫-practical-use-case-decision-matrix-ও-summary&quot;&gt;৫. Practical Use-Case Decision Matrix ও Summary&lt;/h2&gt;
&lt;p&gt;আধুনিক আর্কিটেকচারে অন্ধভাবে একটি প্যারাডাইম ফলো করার দিন শেষ। আপনাকে রিকোয়ারমেন্ট অনুযায়ী হাইব্রিড অ্যাপ্রোচ নিতে হবে। নিচে একটি কুইক ডিসিশন ম্যাট্রিক্স দেওয়া হলো:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;GUI, Game Engine, Complex Domain Entities:&lt;/strong&gt; এখানে OOP ব্যবহার করুন। কারণ ইন্টারঅ্যাক্টিভ অবজেক্টের স্টেট, লাইফসাইকেল এবং ইন-প্লেস মেমরি আপডেট মেথডের ভেতরে এনক্যাপসুলেট করা সবচেয়ে ন্যাচারাল।&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Data Pipelines, ETL, Analytics Infrastructure:&lt;/strong&gt; এখানে FP ব্যবহার করুন। ডাটা স্টিম ট্রান্সফরমেশনে পিওর ফাংশন এবং ইমিউটেবিলিটি সাইড-ইফেক্ট সম্পূর্ণ দূর করে এবং পাইপলাইনিং অনেক সহজ করে তোলে।&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;High-Concurrency ও Distributed Microservices:&lt;/strong&gt; এখানেও FP আর্কিটেকচার সেরা পারফর্ম করে। Shared State না থাকায় থ্রেড সেফটি নিশ্চিত হয় এবং ডেডলক বা রেস কন্ডিশন ছাড়া প্যারালাল প্রসেসিং সম্ভব হয়।&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Enterprise Business Applications (CRUD / Domain Boundary):&lt;/strong&gt; এখানে Hybrid প্যাটার্ন সবচেয়ে কার্যকরী। ডোমেইন বাউন্ডারি এবং ডিপেন্ডেন্সি ইনজেকশনের জন্য OOP মডিউল, আর ইন্টারনাল বিজনেস ট্রান্সফরমেশনের জন্য FP নীতি ব্যবহার করা উচিত।&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The Multiparadigm Paradigm এখন আধুনিক ইঞ্জিনিয়ারিংয়ের মূল ভিত্তি। আধুনিক ল্যাঙ্গুয়েজগুলো, যেমন TypeScript, Rust, বা Kotlin, খুব সুন্দরভাবে OOP এবং FP উভয়ের সেরা কনসেপ্টগুলোকে মার্জ করেছে। তাই আপনার প্রজেক্টের আর্কিটেকচার সেট করার সময় Macro Level এ OOP ব্যবহার করে সার্ভিস ইন্টারফেস সংজ্ঞায়িত করুন, এবং Micro Level এ ডাটা ট্রান্সফরমেশনের জন্য FP ব্যবহার করুন।&lt;/p&gt;
&lt;p&gt;পরিশেষে, একজন ইঞ্জিনিয়ার হিসেবে যখনই আর্কিটেকচারাল সিদ্ধান্ত নেবেন, নিজেকে তিনটি প্রশ্ন করবেন। এক, আপনি কি এমন সিস্টেম তৈরি করছেন যেখানে জটিল এনটিটির স্টেট বারবার ইন-প্লেস আপডেট হতে হবে? দুই, আপনার অ্যাপ্লিকেশনে কি হাই-কনকারেন্সি এবং মাল্টি-থ্রেডেড প্রসেসিং প্রধান অগ্রাধিকার? তিন, আপনার টিমের লার্নিং কার্ভ এবং মেইনটেনেবিলিটি ক্যাপাসিটি কেমন? এই উত্তরগুলোই আপনাকে সঠিক আর্কিটেকচারাল প্যারাডাইম বেছে নিতে সাহায্য করবে।&lt;/p&gt;</content:encoded><category>Software Architecture</category><category>Deep Dive</category><category>Architecture</category><category>Under the hood</category><category>OOP</category><category>Functional Programming</category><category>System Design</category><category>Concurrency</category><category>V8 Engine</category></item><item><title>RFC 10008 এবং HTTP QUERY Method: FastAPI দিয়ে Framework-Agnostic Production-Ready Search API বানানোর সম্পূর্ণ Engineering Handbook</title><link>https://www.rafeuddaraj.me/bn/blog/http-query-method-rfc-10008-complete-engineering-handbook/</link><guid isPermaLink="true">https://www.rafeuddaraj.me/bn/blog/http-query-method-rfc-10008-complete-engineering-handbook/</guid><description>GET আর POST দিয়ে Search API বানানোর সীমাবদ্ধতা থেকে RFC 10008 এর প্রতিটা ডিটেইল, framework-agnostic implementation principle, FastAPI reference implementation, Uvicorn parser internals, browser fetch gotcha, CORS, caching security, ecosystem adoption status, এবং production checklist পর্যন্ত সম্পূর্ণ handbook।</description><pubDate>Fri, 24 Jul 2026 22:30:16 GMT</pubDate><content:encoded>&lt;h2 id=&quot;ভূমিকা-১৬-বছর-ধরে-খুলে-রাখা-একটা-অস্বস্তিকর-ফাঁক&quot;&gt;ভূমিকা: ১৬ বছর ধরে খুলে রাখা একটা অস্বস্তিকর ফাঁক!&lt;/h2&gt;
&lt;p&gt;প্রথমেই আমার সালাম নিবেন ভাই ও বোনেরা! আজকে একটা দারুণ ইন্টারেস্টিং বিষয় নিয়ে একটু বকবক করবো। আপনি কি রেডি?&lt;/p&gt;
&lt;p&gt;বিশ্বাস করেন, ব্যাকএন্ড নিয়ে কাজ করতে গিয়ে আমি নিজে কতবার যে এই প্যারাটা খেয়েছি, তার কোনো হিসাব নাই! প্রতিটা ব্যাকএন্ড ইঞ্জিনিয়ারের লাইফে এমন একটা দিন আসে যখন তাকে একটা জটিল, হিজিবিজি search বা filter API বানাতে হয়। আর তখনই আমরা গিয়ে ধাক্কা খাই HTTP-এর একটা পুরনো, অস্বস্তিকর ফাঁকের সাথে।&lt;/p&gt;
&lt;p&gt;আমরা সবাই জানি, &lt;code&gt;GET&lt;/code&gt; একদম নিয়ম মেনে চলে, লক্ষ্মী ছেলের মতো safe আর idempotent, cache-ও করা যায় সহজে। কিন্তু ঝামেলা হলো, দুনিয়ার যাবতীয় ডেটা ওই এক চিলতে URL-এর ভেতরেই গুঁজে দিতে হয়! অন্যদিকে &lt;code&gt;POST&lt;/code&gt; হলো একটু বাউন্ডুলে টাইপের, নিয়ম ভাঙে, request body-তে যা খুশি যত খুশি ডেটা পাঠানো যায়। কিন্তু semantics-এর নিয়ম অনুযায়ী এটা তো state পরিবর্তন করার জন্য, কোনো read-only অপারেশনের জন্য তো এটা বানানো হয়নি, তাই না?&lt;/p&gt;
&lt;p&gt;আজকের এই আর্টিকেলটা শুধু শুকনো থিওরি লেকচার দেওয়ার জন্য না। এটা একটা সম্পূর্ণ engineering handbook! এখানে আমরা RFC 10008 এর প্রতিটা খুঁটিনাটি ডিটেইল, framework-agnostic implementation principle, Python FastAPI দিয়ে একদম রিয়েল-লাইফ reference implementation, ইনফ্রাস্ট্রাকচারের আসল সীমাবদ্ধতা, security consideration, আর আজকের দিনে পুরো ecosystem-এর কী অবস্থা, সব কিছু একদম পোস্টমর্টেম করে ফেলবো। আপনি যে ল্যাঙ্গুয়েজ বা ফ্রেমওয়ার্কেই কোড লিখুন না কেন, এই লেখাটা পড়ার পর নিজের প্রজেক্টে এটা খুব সহজেই implement করতে পারবেন।&lt;/p&gt;
&lt;h3 id=&quot;get-এবং-post-ঠিক-কোথায়-গিয়ে-ধোঁকা-দেয়&quot;&gt;GET এবং POST ঠিক কোথায় গিয়ে ধোঁকা দেয়?&lt;/h3&gt;
&lt;p&gt;কেন আমাদের নতুন কিছুর দরকার হলো? আসুন একটু হিসেব করি! RFC 10008 নিজেই চারটা সলিড কারণ দেখিয়ে দিয়েছে কেন &lt;code&gt;GET&lt;/code&gt; জটিল query-র জন্য একদমই যথেষ্ট না:&lt;/p&gt;
&lt;p&gt;১. &lt;strong&gt;URL-এর অনিশ্চিত লিমিট:&lt;/strong&gt; একটা request যখন আপনার সার্ভার পর্যন্ত আসে, তখন সেটা পথে একাধিক proxy, load balancer আর CDN-এর ওপর দিয়ে ধাক্কা খেতে খেতে আসে। আর এদের প্রত্যেকের নিজস্ব একটা length limit থাকে! একটু বড় filter পাঠালেই দেখবেন কে যেন মাঝপথ থেকেই request-টা লাথি মেরে ফেলে দিয়েছে!&lt;/p&gt;
&lt;p&gt;২. &lt;strong&gt;গোপনীয়তা ফাঁস:&lt;/strong&gt; URL সচরাচর access log, browser history আর referrer header-এ একদম প্রকাশ্য দিবালোকে থেকে যায়। এখন চিন্তা করেন, আপনার filter-এ যদি কোনো sensitive ডেটা থাকে, সেটা কিন্তু অনিচ্ছাকৃতভাবেই সবার কাছে লিক হয়ে যাচ্ছে! বুঝলেন তো?&lt;/p&gt;
&lt;p&gt;৩. &lt;strong&gt;হিজিবিজি অয়েসথাই কোড:&lt;/strong&gt; nested filter object (যেমন price range, multiple category, sort array) যদি URL query string-এ পাঠাতে যান, সেটা দেখতে যে কী জঘন্য হয়, তা আমরা সবাই জানি! এটা readable রাখা প্রায় অসম্ভব একটা কাজ।&lt;/p&gt;
&lt;p&gt;৪. &lt;strong&gt;ইনফ্রাস্ট্রাকচারের কনফিউশন:&lt;/strong&gt; বাধ্য হয়ে যখন আপনি &lt;code&gt;POST&lt;/code&gt; ব্যবহার করবেন, তখন আপনার load balancer বা CDN তো আর জানে না যে এই অপারেশনটা read নাকি write! ফলে caching, retry আর rate-limiting-এর মতো গুরুত্বপূর্ণ সিদ্ধান্তগুলো পুরোই ভুল হয়ে যায়।&lt;/p&gt;
&lt;h2 id=&quot;একটু-পেছনের-গল্প-১১-বছরের-ড্রাফট-থেকে-অবশেষে-rfc&quot;&gt;একটু পেছনের গল্প: ১১ বছরের ড্রাফট থেকে অবশেষে RFC!&lt;/h2&gt;
&lt;p&gt;তখন ২০১০ সাল, HTTP-তে &lt;code&gt;PATCH&lt;/code&gt; method আসার পর দীর্ঘ ১৬ বছর কেটে গেছে। ভাবা যায়? ১৬ বছর পর এই প্রথম HTTP-তে কোনো সম্পূর্ণ নতুন general-purpose method যোগ হলো!&lt;/p&gt;
&lt;p&gt;এই &lt;code&gt;QUERY&lt;/code&gt;-এর ড্রাফট (&lt;code&gt;draft-ietf-httpbis-safe-method-w-body&lt;/code&gt;) HTTP Working Group-এ বছরের পর বছর ধরে iterate হয়েছে। অবশেষে ২০২৫ সালের ২০ নভেম্বর IESG-তে এটা formally approve হয়, এবং শেষমেশ &lt;strong&gt;২০২৬ সালের ১৫ জুন RFC Editor এটাকে RFC 10008 হিসেবে অফিশিয়ালি পাবলিশ করে&lt;/strong&gt;। এটা একটা ২৪ পাতার Proposed Standard, যেটা লিখেছেন &lt;a href=&quot;https://datatracker.ietf.org/person/julian.reschke@gmx.de&quot; rel=&quot;noopener noreferrer&quot;&gt;Julian Reschke (greenbytes)&lt;/a&gt;, &lt;a href=&quot;https://blog.cloudflare.com/author/jasnell/&quot; rel=&quot;noopener noreferrer&quot;&gt;James M. Snell (Cloudflare)&lt;/a&gt; এবং &lt;a href=&quot;https://datatracker.ietf.org/person/mbishop@evequefou.be&quot; rel=&quot;noopener noreferrer&quot;&gt;Mike Bishop (Akamai)&lt;/a&gt;। ১৬ বছরের অপেক্ষা বলে কথা!&lt;/p&gt;
&lt;h2 id=&quot;rfc-10008-গভীরে-গিয়ে-দেখা-যাক&quot;&gt;RFC 10008 গভীরে গিয়ে দেখা যাক&lt;/h2&gt;
&lt;p&gt;ঠিক আছে এখন আসল কথায় আসি! স্পেসিফিকেশন আসলে আমাদের কী বলছে?&lt;/p&gt;
&lt;h3 id=&quot;সংজ্ঞা-এবং-iana-রেজিস্ট্রেশন&quot;&gt;সংজ্ঞা এবং IANA রেজিস্ট্রেশন&lt;/h3&gt;
&lt;p&gt;RFC অনুযায়ী, &lt;code&gt;QUERY&lt;/code&gt; request একটা resource-কে বলে দেয় যে request-এর সাথে সংযুক্ত content-টা একটা safe এবং idempotent উপায়ে প্রসেস করতে হবে, আর তার ফলাফলটা response হিসেবে ফেরত দিতে হবে। IANA-এর HTTP Method Registry-তে এটা ঠিক এভাবে রেজিস্টার করা আছে:&lt;/p&gt;
&lt;section class=&quot;table-wrap&quot; tabindex=&quot;0&quot; aria-label=&quot;Table 1&quot;&gt;
















&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Method Name&lt;/th&gt;&lt;th&gt;Safe&lt;/th&gt;&lt;th&gt;Idempotent&lt;/th&gt;&lt;th&gt;Specification&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;QUERY&lt;/td&gt;&lt;td&gt;Yes&lt;/td&gt;&lt;td&gt;Yes&lt;/td&gt;&lt;td&gt;Section 2, RFC 10008&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/section&gt;
&lt;p&gt;Safe আর Idempotent জিনিসটা কী? এটা অনেকটা ঘরের সবচেয়ে শান্ত ছেলের মতো। আপনি তাকে যতবারই একই কাজ করতে বলেন না কেন, সে ঘরের কোনো আসবাবপত্র ভাঙচুর করবে না (মানে সার্ভারের কোনো state change করবে না)। ইনফ্রাস্ট্রাকচার এখন নিশ্চিতভাবে জানে এই request-টা কোনো ক্ষতি করবে না, তাই মাঝপথে কানেকশন ড্রপ খেলেও টেনশন নাই, এটাকে একদম নিরাপদে আবার পাঠানো যাবে, ঠিক &lt;code&gt;GET&lt;/code&gt;-এর মতোই!&lt;/p&gt;
&lt;h3 id=&quot;body-মানেই-json-না-content-type-ই-আসল-কিং&quot;&gt;Body মানেই JSON না, Content-Type-ই আসল কিং!&lt;/h3&gt;
&lt;p&gt;এখানেই কিন্তু বেশিরভাগ মানুষ ভুল করে বসে! সবাই ভাবে request body থাকা মানেই সেটা JSON হতে হবে। আরে না ভাই! ফ্রেমওয়ার্ক-অ্যাগনস্টিক হওয়ার জন্য এই জায়গাটা বোঝা সবচেয়ে জরুরি।&lt;/p&gt;
&lt;p&gt;&lt;code&gt;QUERY&lt;/code&gt; request-এর body ঠিক কী ফরম্যাটে থাকবে, সেটা RFC নির্দিষ্ট করে দেয়নি। body এবং &lt;code&gt;Content-Type&lt;/code&gt; header একসাথে মিলে সেই query-টাকে define করে। মানে আপনি চাইলে JSON, &lt;code&gt;application/x-www-form-urlencoded&lt;/code&gt;, GraphQL query syntax, এমনকি আপনার নিজের বানানো কোনো কাস্টম SQL-জাতীয় DSL-ও পাঠাতে পারেন! শর্ত একটাই, সার্ভার এবং ক্লায়েন্ট দুইপক্ষকেই সেই Content-Type-টা বুঝতে হবে। RFC-এর নিজের দেওয়া একটা চমৎকার example দেখুন:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;style&gt;.expressive-code{font-family:var(--ec-uiFontFml);font-size:var(--ec-uiFontSize);font-weight:var(--ec-uiFontWg);line-height:var(--ec-uiLineHt);text-size-adjust:none;-webkit-text-size-adjust:none}.expressive-code *:not(:is(svg, svg *)){all:revert;box-sizing:border-box}.expressive-code pre{display:flex;margin:0;padding:0;border:var(--ec-brdWd) solid var(--ec-brdCol);border-radius:calc(var(--ec-brdRad) + var(--ec-brdWd));background:var(--ec-codeBg)}.expressive-code pre:focus-visible{outline:3px solid var(--ec-focusBrd);outline-offset:-3px}.expressive-code pre &gt; code{all:unset;display:block;flex:1 0 100%;padding:var(--ec-codePadBlk) 0;color:var(--ec-codeFg);font-family:var(--ec-codeFontFml);font-size:var(--ec-codeFontSize);font-weight:var(--ec-codeFontWg);line-height:var(--ec-codeLineHt)}.expressive-code pre{overflow-x:auto}.expressive-code pre.wrap .ec-line .code{white-space:pre-wrap;overflow-wrap:break-word;min-width:min(20ch, var(--ecMaxLine, 20ch))}.expressive-code pre.wrap .ec-line .code span.indent{white-space:pre}.expressive-code pre::-webkit-scrollbar,.expressive-code pre::-webkit-scrollbar-track{background-color:inherit;border-radius:calc(var(--ec-brdRad) + var(--ec-brdWd));border-top-left-radius:0;border-top-right-radius:0}.expressive-code pre::-webkit-scrollbar-thumb{background-color:var(--ec-sbThumbCol);border:4px solid transparent;background-clip:content-box;border-radius:10px}.expressive-code pre::-webkit-scrollbar-thumb:hover{background-color:var(--ec-sbThumbHoverCol)}.expressive-code pre::-webkit-scrollbar-corner{background:transparent}.expressive-code .ec-line{direction:ltr;unicode-bidi:isolate;display:grid;grid-template-areas:&apos;gutter code&apos;;grid-template-columns:auto 1fr;position:relative}.expressive-code .ec-line .gutter{grid-area:gutter;color:var(--ec-gtrFg)}.expressive-code .ec-line .gutter &gt; *{pointer-events:none;user-select:none;-webkit-user-select:none}.expressive-code .ec-line .gutter ~ .code{--ecLineBrdCol:var(--ec-gtrBrdCol)}.expressive-code .ec-line.highlight .gutter{color:var(--ec-gtrHlFg)}.expressive-code .ec-line .code{grid-area:code;position:relative;box-sizing:content-box;padding-inline-start:calc(var(--ecIndent, 0ch) + var(--ec-codePadInl) - var(--ecGtrBrdWd));padding-inline-end:var(--ec-codePadInl);text-indent:calc(var(--ecIndent, 0ch) * -1)}.expressive-code .ec-line .code::before,.expressive-code .ec-line .code::after,.expressive-code .ec-line .code :where(*){text-indent:0}.expressive-code .ec-line .code{--ecGtrBrdWd:var(--ec-gtrBrdWd);border-inline-start:var(--ecGtrBrdWd) solid var(--ecLineBrdCol, transparent)}.expressive-code .sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0, 0, 0, 0);white-space:nowrap;border-width:0}.expressive-code .ec-line.mark{--tmLineBgCol:var(--ec-tm-markBg)}.expressive-code .ec-line.mark .code{--ecLineBrdCol:var(--ec-tm-markBrdCol)}.expressive-code .ec-line.ins{--tmLineBgCol:var(--ec-tm-insBg);--tmLabel:var(--ec-tm-insDiffIndContent)}.expressive-code .ec-line.ins .code{--ecLineBrdCol:var(--ec-tm-insBrdCol)}.expressive-code .ec-line.ins .code::before{color:var(--ec-tm-insDiffIndCol)}.expressive-code .ec-line.del{--tmLineBgCol:var(--ec-tm-delBg);--tmLabel:var(--ec-tm-delDiffIndContent)}.expressive-code .ec-line.del .code{--ecLineBrdCol:var(--ec-tm-delBrdCol)}.expressive-code .ec-line.del .code::before{color:var(--ec-tm-delDiffIndCol)}.expressive-code .ec-line.mark,.expressive-code .ec-line.ins,.expressive-code .ec-line.del{background:var(--tmLineBgCol)}.expressive-code .ec-line.mark .code,.expressive-code .ec-line.ins .code,.expressive-code .ec-line.del .code{--ecGtrBrdWd:var(--ec-tm-lineMarkerAccentWd)}.expressive-code .ec-line.mark .code::before,.expressive-code .ec-line.ins .code::before,.expressive-code .ec-line.del .code::before{display:block;position:absolute;left:0;box-sizing:border-box;content:var(--tmLabel, &apos; &apos;);padding-inline-start:var(--ec-tm-lineDiffIndMargLeft);text-align:center;white-space:pre}.expressive-code .ec-line.mark.tm-label .code::before,.expressive-code .ec-line.ins.tm-label .code::before,.expressive-code .ec-line.del.tm-label .code::before{background:var(--ecLineBrdCol);padding:0 calc(var(--ec-tm-lineMarkerLabelPadInl) + var(--ec-tm-lineMarkerAccentWd)) 0 var(--ec-tm-lineMarkerLabelPadInl);color:var(--ec-tm-lineMarkerLabelCol)}.expressive-code .ec-line mark{--tmInlineBgCol:var(--ec-tm-markBg);--tmInlineBrdCol:var(--ec-tm-markBrdCol)}.expressive-code .ec-line ins{--tmInlineBgCol:var(--ec-tm-insBg);--tmInlineBrdCol:var(--ec-tm-insBrdCol)}.expressive-code .ec-line del{--tmInlineBgCol:var(--ec-tm-delBg);--tmInlineBrdCol:var(--ec-tm-delBrdCol)}.expressive-code .ec-line mark,.expressive-code .ec-line ins,.expressive-code .ec-line del{all:unset;display:inline-block;position:relative;--tmBrdL:var(--ec-tm-inlMarkerBrdWd);--tmBrdR:var(--ec-tm-inlMarkerBrdWd);--tmRadL:var(--ec-tm-inlMarkerBrdRad);--tmRadR:var(--ec-tm-inlMarkerBrdRad);margin-inline:0.025rem;padding-inline:var(--ec-tm-inlMarkerPad);border-radius:var(--tmRadL) var(--tmRadR) var(--tmRadR) var(--tmRadL);background:var(--tmInlineBgCol);background-clip:padding-box}.expressive-code .ec-line mark.open-start,.expressive-code .ec-line ins.open-start,.expressive-code .ec-line del.open-start{margin-inline-start:0;padding-inline-start:0;--tmBrdL:0px;--tmRadL:0}.expressive-code .ec-line mark.open-end,.expressive-code .ec-line ins.open-end,.expressive-code .ec-line del.open-end{margin-inline-end:0;padding-inline-end:0;--tmBrdR:0px;--tmRadR:0}.expressive-code .ec-line mark::before,.expressive-code .ec-line ins::before,.expressive-code .ec-line del::before{content:&apos;&apos;;position:absolute;pointer-events:none;display:inline-block;inset:0;border-radius:var(--tmRadL) var(--tmRadR) var(--tmRadR) var(--tmRadL);border:var(--ec-tm-inlMarkerBrdWd) solid var(--tmInlineBrdCol);border-inline-width:var(--tmBrdL) var(--tmBrdR)}.expressive-code .frame{all:unset;position:relative;display:block;--header-border-radius:calc(var(--ec-brdRad) + var(--ec-brdWd));--tab-border-radius:calc(var(--ec-frm-edTabBrdRad) + var(--ec-brdWd));--button-spacing:0.4rem;--code-background:var(--ec-frm-edBg);border-radius:var(--header-border-radius);box-shadow:var(--ec-frm-frameBoxShdCssVal)}.expressive-code .frame .header{display:none;z-index:1;position:relative;border-radius:var(--header-border-radius) var(--header-border-radius) 0 0}.expressive-code .frame.has-title pre,.expressive-code .frame.has-title code,.expressive-code .frame.is-terminal pre,.expressive-code .frame.is-terminal code{border-top:none;border-top-left-radius:0;border-top-right-radius:0}.expressive-code .frame .title:empty:before{content:&apos;\a0&apos;}.expressive-code .frame.has-title:not(.is-terminal){--button-spacing:calc(1.9rem + 2 * (var(--ec-uiPadBlk) + var(--ec-frm-edActTabIndHt)))}.expressive-code .frame.has-title:not(.is-terminal) .title{position:relative;color:var(--ec-frm-edActTabFg);background:var(--ec-frm-edActTabBg);background-clip:padding-box;margin-block-start:var(--ec-frm-edTabsMargBlkStart);padding:calc(var(--ec-uiPadBlk) + var(--ec-frm-edActTabIndHt)) var(--ec-uiPadInl);border:var(--ec-brdWd) solid var(--ec-frm-edActTabBrdCol);border-radius:var(--tab-border-radius) var(--tab-border-radius) 0 0;border-bottom:none;overflow:hidden}.expressive-code .frame.has-title:not(.is-terminal) .title::after{content:&apos;&apos;;position:absolute;pointer-events:none;inset:0;border-top:var(--ec-frm-edActTabIndHt) solid var(--ec-frm-edActTabIndTopCol);border-bottom:var(--ec-frm-edActTabIndHt) solid var(--ec-frm-edActTabIndBtmCol)}.expressive-code .frame.has-title:not(.is-terminal) .header{display:flex;background:linear-gradient(to top, var(--ec-frm-edTabBarBrdBtmCol) var(--ec-brdWd), transparent var(--ec-brdWd)),linear-gradient(var(--ec-frm-edTabBarBg), var(--ec-frm-edTabBarBg));background-repeat:no-repeat;padding-inline-start:var(--ec-frm-edTabsMargInlStart)}.expressive-code .frame.has-title:not(.is-terminal) .header::before{content:&apos;&apos;;position:absolute;pointer-events:none;inset:0;border:var(--ec-brdWd) solid var(--ec-frm-edTabBarBrdCol);border-radius:inherit;border-bottom:none}.expressive-code .frame.is-terminal{--button-spacing:calc(1.9rem + var(--ec-brdWd) + 2 * var(--ec-uiPadBlk));--code-background:var(--ec-frm-trmBg)}.expressive-code .frame.is-terminal .header{display:flex;align-items:center;justify-content:center;padding-block:var(--ec-uiPadBlk);padding-block-end:calc(var(--ec-uiPadBlk) + var(--ec-brdWd));position:relative;font-weight:500;letter-spacing:0.025ch;color:var(--ec-frm-trmTtbFg);background:var(--ec-frm-trmTtbBg);border:var(--ec-brdWd) solid var(--ec-brdCol);border-bottom:none}.expressive-code .frame.is-terminal .header::before{content:&apos;&apos;;position:absolute;pointer-events:none;left:var(--ec-uiPadInl);width:2.1rem;height:0.56rem;line-height:0;background-color:var(--ec-frm-trmTtbDotsFg);opacity:var(--ec-frm-trmTtbDotsOpa);-webkit-mask-image:var(--ec-frm-trmIcon);-webkit-mask-repeat:no-repeat;mask-image:var(--ec-frm-trmIcon);mask-repeat:no-repeat}.expressive-code .frame.is-terminal .header::after{content:&apos;&apos;;position:absolute;pointer-events:none;inset:0;border-bottom:var(--ec-brdWd) solid var(--ec-frm-trmTtbBrdBtmCol)}.expressive-code .frame pre{background:var(--code-background)}.expressive-code .copy{display:flex;gap:0.25rem;flex-direction:row;position:absolute;inset-block-start:calc(var(--ec-brdWd) + var(--button-spacing));inset-inline-end:calc(var(--ec-brdWd) + var(--ec-uiPadInl) / 2)}@media (scripting: none){.expressive-code .copy{display:none}}.expressive-code .copy{direction:ltr;unicode-bidi:isolate}.expressive-code .copy button{position:relative;align-self:flex-end;margin:0;padding:0;border:none;border-radius:0.2rem;z-index:1;cursor:pointer;transition-property:opacity, background, border-color;transition-duration:0.2s;transition-timing-function:cubic-bezier(0.25, 0.46, 0.45, 0.94);width:2.5rem;height:2.5rem;background:var(--code-background);opacity:0.75}.expressive-code .copy button div{position:absolute;inset:0;border-radius:inherit;background:var(--ec-frm-inlBtnBg);opacity:var(--ec-frm-inlBtnBgIdleOpa);transition-property:inherit;transition-duration:inherit;transition-timing-function:inherit}.expressive-code .copy button::before{content:&apos;&apos;;position:absolute;pointer-events:none;inset:0;border-radius:inherit;border:var(--ec-brdWd) solid var(--ec-frm-inlBtnBrd);opacity:var(--ec-frm-inlBtnBrdOpa)}.expressive-code .copy button::after{content:&apos;&apos;;position:absolute;pointer-events:none;inset:0;background-color:var(--ec-frm-inlBtnFg);-webkit-mask-image:var(--ec-frm-copyIcon);-webkit-mask-repeat:no-repeat;mask-image:var(--ec-frm-copyIcon);mask-repeat:no-repeat;margin:0.475rem;line-height:0}.expressive-code .copy button:hover,.expressive-code .copy button:focus:focus-visible{opacity:1}.expressive-code .copy button:hover div,.expressive-code .copy button:focus:focus-visible div{opacity:var(--ec-frm-inlBtnBgHoverOrFocusOpa)}.expressive-code .copy button:active{opacity:1}.expressive-code .copy button:active div{opacity:var(--ec-frm-inlBtnBgActOpa)}.expressive-code .copy .feedback{--tooltip-arrow-size:0.35rem;--tooltip-bg:var(--ec-frm-tooltipSuccessBg);color:var(--ec-frm-tooltipSuccessFg);pointer-events:none;user-select:none;-webkit-user-select:none;position:relative;align-self:center;background-color:var(--tooltip-bg);z-index:99;padding:0.125rem 0.75rem;border-radius:0.2rem;margin-inline-end:var(--tooltip-arrow-size);opacity:0;transition-property:opacity, transform;transition-duration:0.2s;transition-timing-function:ease-in-out;transform:translate3d(0, 0.25rem, 0)}.expressive-code .copy .feedback::after{content:&apos;&apos;;position:absolute;pointer-events:none;top:calc(50% - var(--tooltip-arrow-size));inset-inline-end:calc(-2 * (var(--tooltip-arrow-size) - 0.5px));border:var(--tooltip-arrow-size) solid transparent;border-inline-start-color:var(--tooltip-bg)}.expressive-code .copy .feedback.show{opacity:1;transform:translate3d(0, 0, 0)}@media (hover: hover){.expressive-code{}.expressive-code .copy button{opacity:0;width:2rem;height:2rem}.expressive-code .frame:hover .copy button:not(:hover),.expressive-code .frame:focus-within :focus-visible ~ .copy button:not(:hover),.expressive-code .frame .copy .feedback.show ~ button:not(:hover){opacity:0.75}}.expressive-code :nth-child(1 of .ec-line) .code{padding-inline-end:calc(2rem + var(--ec-codePadInl))}:root{--ec-brdRad:0.75rem;--ec-brdWd:1.5px;--ec-brdCol:var(--code-line);--ec-codeFontFml:var(--font-code);--ec-codeFontSize:0.875rem;--ec-codeFontWg:400;--ec-codeLineHt:1.75;--ec-codePadBlk:1rem;--ec-codePadInl:1.125rem;--ec-codeBg:var(--code-bg);--ec-codeFg:#e6edf3;--ec-codeSelBg:#264f78;--ec-gtrFg:#6e7681;--ec-gtrBrdCol:#6e768133;--ec-gtrBrdWd:1.5px;--ec-gtrHlFg:#e6edf3;--ec-uiFontFml:var(--font-mono);--ec-uiFontSize:0.75rem;--ec-uiFontWg:400;--ec-uiLineHt:1.65;--ec-uiPadBlk:0.25rem;--ec-uiPadInl:1rem;--ec-uiSelBg:#6e768166;--ec-uiSelFg:#e6edf3;--ec-focusBrd:#1f6feb;--ec-sbThumbCol:#8b949e33;--ec-sbThumbHoverCol:#8b949e3d;--ec-tm-lineMarkerAccentMarg:0rem;--ec-tm-lineMarkerAccentWd:0.15rem;--ec-tm-lineMarkerLabelPadInl:0.2rem;--ec-tm-lineMarkerLabelCol:white;--ec-tm-lineDiffIndMargLeft:0.3rem;--ec-tm-inlMarkerBrdWd:1.5px;--ec-tm-inlMarkerBrdRad:0.2rem;--ec-tm-inlMarkerPad:0.15rem;--ec-tm-insDiffIndContent:&apos;+&apos;;--ec-tm-delDiffIndContent:&apos;-&apos;;--ec-tm-markBg:#264a8980;--ec-tm-markBrdCol:#5570b3d0;--ec-tm-insBg:#26561c80;--ec-tm-insBrdCol:#4e7e41d0;--ec-tm-insDiffIndCol:#7eb070d0;--ec-tm-delBg:#81322b80;--ec-tm-delBrdCol:#ae594fd0;--ec-tm-delDiffIndCol:#e68a7ed0;--ec-frm-shdCol:#0000005b;--ec-frm-frameBoxShdCssVal:none;--ec-frm-edActTabBg:var(--code-bg);--ec-frm-edActTabFg:var(--code-muted);--ec-frm-edActTabBrdCol:transparent;--ec-frm-edActTabIndHt:1.5px;--ec-frm-edActTabIndTopCol:transparent;--ec-frm-edActTabIndBtmCol:#0d1117;--ec-frm-edTabsMargInlStart:0;--ec-frm-edTabsMargBlkStart:0;--ec-frm-edTabBrdRad:0.75rem;--ec-frm-edTabBarBg:var(--code-bg);--ec-frm-edTabBarBrdCol:var(--code-line);--ec-frm-edTabBarBrdBtmCol:var(--code-line);--ec-frm-edBg:var(--code-bg);--ec-frm-trmTtbFg:var(--code-muted);--ec-frm-trmTtbDotsFg:var(--code-muted);--ec-frm-trmTtbDotsOpa:0.15;--ec-frm-trmTtbBg:var(--code-bg);--ec-frm-trmTtbBrdBtmCol:var(--code-line);--ec-frm-trmBg:var(--code-bg);--ec-frm-inlBtnBg:var(--code-ink);--ec-frm-inlBtnBgIdleOpa:0;--ec-frm-inlBtnBgHoverOrFocusOpa:0.2;--ec-frm-inlBtnBgActOpa:0.3;--ec-frm-inlBtnFg:var(--code-ink);--ec-frm-inlBtnBrd:var(--code-line);--ec-frm-inlBtnBrdOpa:0.4;--ec-frm-tooltipSuccessBg:var(--color-emerald);--ec-frm-tooltipSuccessFg:var(--color-bg);--ec-frm-copyIcon:url(&quot;data:image/svg+xml,%3Csvg%20xmlns%3D&apos;http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg&apos;%20viewBox%3D&apos;0%200%2024%2024&apos;%20fill%3D&apos;none&apos;%20stroke%3D&apos;black&apos;%20stroke-width%3D&apos;1.75&apos;%3E%3Cpath%20d%3D&apos;M3%2019a2%202%200%200%201-1-2V2a2%202%200%200%201%201-1h13a2%202%200%200%201%202%201&apos;%2F%3E%3Crect%20x%3D&apos;6&apos;%20y%3D&apos;5&apos;%20width%3D&apos;16&apos;%20height%3D&apos;18&apos;%20rx%3D&apos;1.5&apos;%20ry%3D&apos;1.5&apos;%2F%3E%3C%2Fsvg%3E&quot;);--ec-frm-trmIcon:url(&quot;data:image/svg+xml,%3Csvg%20xmlns%3D&apos;http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg&apos;%20viewBox%3D&apos;0%200%2060%2016&apos;%20preserveAspectRatio%3D&apos;xMidYMid%20meet&apos;%3E%3Ccircle%20cx%3D&apos;8&apos;%20cy%3D&apos;8&apos;%20r%3D&apos;8&apos;%2F%3E%3Ccircle%20cx%3D&apos;30&apos;%20cy%3D&apos;8&apos;%20r%3D&apos;8&apos;%2F%3E%3Ccircle%20cx%3D&apos;52&apos;%20cy%3D&apos;8&apos;%20r%3D&apos;8&apos;%2F%3E%3C%2Fsvg%3E&quot;)}.expressive-code .ec-line :where(span[style^=&apos;--&apos;]:not([class])){color:var(--0, inherit);background-color:var(--0bg, transparent);font-style:var(--0fs, inherit);font-weight:var(--0fw, inherit);text-decoration:var(--0td, inherit)}&lt;/style&gt;&lt;script type=&quot;module&quot; src=&quot;/_astro/ec.0vx5m.js&quot;&gt;&lt;/script&gt;&lt;figure class=&quot;frame has-title&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;HTTP&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;http&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;QUERY /contacts HTTP/1.1&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#7EE787&quot;&gt;Host&lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;example.org&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#7EE787&quot;&gt;Content-Type&lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;application/x-www-form-urlencoded&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#7EE787&quot;&gt;Accept&lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;application/json&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;select=surname,givenname,email&amp;#x26;limit=10&amp;#x26;match=email=*@example.*&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;QUERY /contacts HTTP/1.1Host: example.orgContent-Type: application/x-www-form-urlencodedAccept: application/jsonselect=surname,givenname,email&amp;#x26;limit=10&amp;#x26;match=email=*@example.*&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;div class=&quot;callout&quot; role=&quot;note&quot; data-type=&quot;note&quot;&gt;
&lt;p class=&quot;callout-title&quot;&gt;Content-Type Validation একদম বাধ্যতামূলক!&lt;/p&gt;
&lt;p&gt;RFC অনুযায়ী সার্ভারকে অবশ্যই missing বা inconsistent &lt;code&gt;Content-Type&lt;/code&gt; header প্রত্যাখ্যান করতে হবে। আর ভুল হলে যথাযথভাবে &lt;code&gt;400 Bad Request&lt;/code&gt;, &lt;code&gt;415 Unsupported Media Type&lt;/code&gt; বা &lt;code&gt;422 Unprocessable Entity&lt;/code&gt; রিটার্ন করতে হবে। এটা কিন্তু কোনো optional best practice না ভাই, এটা স্পেসিফিকেশনের একটা MUST requirement!&lt;/p&gt;
&lt;/div&gt;
&lt;h3 id=&quot;accept-query-header-দিয়ে-discoverability&quot;&gt;Accept-Query header দিয়ে discoverability&lt;/h3&gt;
&lt;p&gt;এখন প্রশ্ন হলো, কোনো একটা resource যে &lt;code&gt;QUERY&lt;/code&gt; সাপোর্ট করে কিনা, আর কোন Content-Type সে গ্রহণ করে, সেটা ক্লায়েন্ট বুঝবে কীভাবে? এই discoverability-র জন্য RFC একটা নতুন header field সংজ্ঞায়িত করেছে, যার নাম &lt;code&gt;Accept-Query&lt;/code&gt;। এটা IANA-এর HTTP Field Name Registry-তেও যোগ হয়েছে। সাধারণত &lt;code&gt;OPTIONS&lt;/code&gt; request-এর response-এ এটা পাঠানো হয়:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame has-title&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;HTTP&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;http&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;OPTIONS&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; /products &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;HTTP&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;1.1&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#7EE787&quot;&gt;Host&lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;api.example.com&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;HTTP&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;1.1&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;204&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;No Content&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#7EE787&quot;&gt;Allow&lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;GET, QUERY, OPTIONS&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#7EE787&quot;&gt;Accept-Query&lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;application/json&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;OPTIONS /products HTTP/1.1Host: api.example.comHTTP/1.1 204 No ContentAllow: GET, QUERY, OPTIONSAccept-Query: application/json&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;h3 id=&quot;cors-এর-ব্যাপারে-rfc-নিজেই-যা-বলে&quot;&gt;CORS-এর ব্যাপারে RFC নিজেই যা বলে&lt;/h3&gt;
&lt;p&gt;CORS-এর যে কী প্যারা, সেটা তো ফ্রন্টএন্ড-ব্যাকএন্ড জোড়া লাগাতে গিয়ে আমরা সবাই জানি, তাই না? RFC নিজেই স্পষ্ট করে বলে দিয়েছে যে &lt;code&gt;QUERY&lt;/code&gt; কিন্তু CORS-safelisted method-এর তালিকায় নেই (সেই ভিআইপি তালিকায় শুধু &lt;code&gt;GET&lt;/code&gt;, &lt;code&gt;HEAD&lt;/code&gt;, আর &lt;code&gt;POST&lt;/code&gt; আছে)। তাই ব্রাউজার থেকে কোনো cross-origin &lt;code&gt;QUERY&lt;/code&gt; request পাঠালে সেটা বাধ্যতামূলকভাবে একটা preflight (&lt;code&gt;OPTIONS&lt;/code&gt;) request ট্রিগার করবেই। এটা মাথায় রাখতেই হবে!&lt;/p&gt;
&lt;h2 id=&quot;framework-agnostic-implementation-principle-যেকোনো-স্ট্যাকে-যা-করতেই-হবে&quot;&gt;Framework-Agnostic Implementation Principle: যেকোনো স্ট্যাকে যা করতেই হবে&lt;/h2&gt;
&lt;p&gt;সত্যি কথা বলতে, আপনি Python, Node.js, Go, Java, বা Ruby যেটাই ব্যবহার করেন না কেন, নিচের ছয়টা গোল্ডেন রুল সবার জন্যই সমানভাবে প্রযোজ্য। একটু চট করে দেখে নেওয়া যাক:&lt;/p&gt;
&lt;p&gt;1️ &lt;strong&gt;HTTP server layer-এ raw &lt;code&gt;QUERY&lt;/code&gt; method গ্রহণ করা:&lt;/strong&gt; আপনার application-এর একদম নিচে যে HTTP parser আছে (যেমন Uvicorn/Hypercorn, Node.js-এর HTTP module, বা Tomcat/Jetty), সেটাকে আগে &lt;code&gt;QUERY&lt;/code&gt;-কে একটা বৈধ method হিসেবে চিনতে হবে। ফ্রেমওয়ার্কে সাপোর্ট থাকলেও নিচের transport layer যদি না চেনে, সে সাইলেন্টলি request ব্লক করে দেবে!&lt;/p&gt;
&lt;p&gt;2️ &lt;strong&gt;Content-Type অনুযায়ী body parse করা:&lt;/strong&gt; ঠিক &lt;code&gt;POST&lt;/code&gt;-এর মতোই body parsing logic reuse করুন, কিন্তু Content-Type validate করে mismatch এড়াতে ভুলবেন না।&lt;/p&gt;
&lt;p&gt;3️ &lt;strong&gt;Handler-কে সত্যিকারের read-only রাখা:&lt;/strong&gt; এর ভেতরে কোনো database write বা side-effect ভুলেও রাখবেন না! কারণ ইনফ্রাস্ট্রাকচার এটাকে safe ধরে নিয়ে automatic retry মারতে পারে, আর retry হলে আপনার ডাটাবেজে duplicate এন্ট্রি পড়ে যাবে।&lt;/p&gt;
&lt;p&gt;4️ &lt;strong&gt;&lt;code&gt;Accept-Query&lt;/code&gt; এবং &lt;code&gt;Allow&lt;/code&gt; header দিয়ে discoverability দেওয়া:&lt;/strong&gt; &lt;code&gt;OPTIONS&lt;/code&gt; response-এ একদম স্পষ্টভাবে জানিয়ে দিন যে আপনার resource &lt;code&gt;QUERY&lt;/code&gt; সাপোর্ট করে।&lt;/p&gt;
&lt;p&gt;5️ &lt;strong&gt;CORS middleware-এ explicit ভাবে &lt;code&gt;QUERY&lt;/code&gt; যোগ করা:&lt;/strong&gt; ডিফল্ট CORS কনফিগারেশন কখনোই এটা নিজে থেকে ধরে নেবে না।&lt;/p&gt;
&lt;p&gt;6️ &lt;strong&gt;Method-aware টুলিং দিয়ে টেস্ট করা:&lt;/strong&gt; &lt;code&gt;curl -X QUERY&lt;/code&gt;, &lt;code&gt;httpx&lt;/code&gt; বা &lt;code&gt;k6&lt;/code&gt; নেটিভভাবে কাস্টম method সাপোর্ট করে, কিন্তু JMeter-এর মতো কিছু টুলে একটু আলাদা configuration লাগে।&lt;/p&gt;
&lt;h2 id=&quot;reference-implementation-fastapi-python-দিয়ে&quot;&gt;Reference Implementation: FastAPI (Python) দিয়ে&lt;/h2&gt;
&lt;p&gt;এই তো গেলো থিওরি কথা, এখন আসি আসল কোড নিয়ে! উদাহরণ হিসেবে আমি FastAPI বেছে নিয়েছি কারণ Python-এ এটা এখন সবচেয়ে জনপ্রিয় async framework। তবে উপরের ছয়টা প্রিন্সিপাল মাথায় রাখলে আপনি এটা Express, Spring, Django, বা Go দিয়েও একদম সহজে বানিয়ে ফেলতে পারবেন।&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame has-title&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;Python&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;python&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#8B949E&quot;&gt;# main.py&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; fastapi &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; FastAPI, Request, HTTPException&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; fastapi.middleware.cors &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; CORSMiddleware&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; pydantic &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; BaseModel, Field&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; typing &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; Optional, Literal&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;app &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; FastAPI(&lt;/span&gt;&lt;span style=&quot;--0:#FFA657&quot;&gt;title&lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;&quot;Product Search API&quot;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#8B949E&quot;&gt;# Principle 5: CORS middleware এ explicit ভাবে QUERY যোগ করা&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;app.add_middleware(&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;CORSMiddleware,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#FFA657&quot;&gt;allow_origins&lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;&quot;[https://yourfrontend.com](https://yourfrontend.com)&quot;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;],&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#FFA657&quot;&gt;allow_methods&lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;&quot;QUERY&quot;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;&quot;OPTIONS&quot;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;],&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#FFA657&quot;&gt;allow_headers&lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;&quot;Content-Type&quot;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;&quot;Accept&quot;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;],&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FFA657&quot;&gt;PriceRange&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;BaseModel&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;):&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;min&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;: Optional[&lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;float&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;] &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; Field(&lt;/span&gt;&lt;span style=&quot;--0:#FFA657&quot;&gt;default&lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;None&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#FFA657&quot;&gt;ge&lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;max&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;: Optional[&lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;float&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;] &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; Field(&lt;/span&gt;&lt;span style=&quot;--0:#FFA657&quot;&gt;default&lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;None&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#FFA657&quot;&gt;ge&lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FFA657&quot;&gt;ProductQuery&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;BaseModel&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;):&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;category: Optional[&lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;str&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;] &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;None&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;brand: Optional[&lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;str&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;] &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;None&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;price: Optional[PriceRange] &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;None&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;sort: Optional[Literal[&lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;&quot;price&quot;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;&quot;-price&quot;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;&quot;name&quot;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;&quot;-name&quot;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;]] &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;None&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;page: &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;int&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; Field(&lt;/span&gt;&lt;span style=&quot;--0:#FFA657&quot;&gt;default&lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#FFA657&quot;&gt;ge&lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;limit: &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;int&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; Field(&lt;/span&gt;&lt;span style=&quot;--0:#FFA657&quot;&gt;default&lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;20&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#FFA657&quot;&gt;le&lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;100&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D2A8FF&quot;&gt;@app.api_route&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;&quot;/products&quot;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#FFA657&quot;&gt;methods&lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;&quot;QUERY&quot;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;])&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;async&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;def&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D2A8FF&quot;&gt;query_products&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;(request: Request, payload: ProductQuery):&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#8B949E&quot;&gt;# Principle 2: Content-Type validate করা (একদম মিস করা যাবে না!)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;content_type &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; request.headers.get(&lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;&quot;content-type&quot;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;if&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;&quot;application/json&quot;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;not&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;in&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; content_type:&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;raise&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; HTTPException(&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;            &lt;/span&gt;&lt;span style=&quot;--0:#FFA657&quot;&gt;status_code&lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;415&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;            &lt;/span&gt;&lt;span style=&quot;--0:#FFA657&quot;&gt;detail&lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;&quot;This endpoint only accepts application/json for QUERY requests&quot;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#8B949E&quot;&gt;# Principle 3: এই ফাংশনের ভেতরে কোনো write operation থাকবে না&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;filtered &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; apply_filters(payload)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;&quot;query&quot;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;: payload.model_dump(&lt;/span&gt;&lt;span style=&quot;--0:#FFA657&quot;&gt;exclude_none&lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;True&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;),&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;&quot;count&quot;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;len&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;(filtered),&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;&quot;results&quot;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;: filtered,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D2A8FF&quot;&gt;@app.options&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;&quot;/products&quot;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;async&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;def&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D2A8FF&quot;&gt;products_options&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;():&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#8B949E&quot;&gt;# Principle 4: Accept-Query দিয়ে discoverability&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; fastapi.responses &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; Response&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; Response(&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#FFA657&quot;&gt;status_code&lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;204&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#FFA657&quot;&gt;headers&lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;            &lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;&quot;Allow&quot;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;&quot;GET, QUERY, OPTIONS&quot;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;            &lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;&quot;Accept-Query&quot;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;&quot;application/json&quot;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;},&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;def&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D2A8FF&quot;&gt;apply_filters&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;(query: ProductQuery) -&gt; list[&lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;dict&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;]:&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#8B949E&quot;&gt;# এখানে আপনার আসল database query logic বসবে&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; []&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;# main.pyfrom fastapi import FastAPI, Request, HTTPExceptionfrom fastapi.middleware.cors import CORSMiddlewarefrom pydantic import BaseModel, Fieldfrom typing import Optional, Literalapp = FastAPI(title=&amp;#x22;Product Search API&amp;#x22;)# Principle 5: CORS middleware এ explicit ভাবে QUERY যোগ করাapp.add_middleware(    CORSMiddleware,    allow_origins=[&amp;#x22;[https://yourfrontend.com](https://yourfrontend.com)&amp;#x22;],    allow_methods=[&amp;#x22;QUERY&amp;#x22;, &amp;#x22;OPTIONS&amp;#x22;],    allow_headers=[&amp;#x22;Content-Type&amp;#x22;, &amp;#x22;Accept&amp;#x22;],)class PriceRange(BaseModel):    min: Optional[float] = Field(default=None, ge=0)    max: Optional[float] = Field(default=None, ge=0)class ProductQuery(BaseModel):    category: Optional[str] = None    brand: Optional[str] = None    price: Optional[PriceRange] = None    sort: Optional[Literal[&amp;#x22;price&amp;#x22;, &amp;#x22;-price&amp;#x22;, &amp;#x22;name&amp;#x22;, &amp;#x22;-name&amp;#x22;]] = None    page: int = Field(default=1, ge=1)    limit: int = Field(default=20, le=100)@app.api_route(&amp;#x22;/products&amp;#x22;, methods=[&amp;#x22;QUERY&amp;#x22;])async def query_products(request: Request, payload: ProductQuery):    # Principle 2: Content-Type validate করা (একদম মিস করা যাবে না!)    content_type = request.headers.get(&amp;#x22;content-type&amp;#x22;, &amp;#x22;&amp;#x22;)    if &amp;#x22;application/json&amp;#x22; not in content_type:        raise HTTPException(            status_code=415,            detail=&amp;#x22;This endpoint only accepts application/json for QUERY requests&amp;#x22;,        )    # Principle 3: এই ফাংশনের ভেতরে কোনো write operation থাকবে না    filtered = apply_filters(payload)    return {        &amp;#x22;query&amp;#x22;: payload.model_dump(exclude_none=True),        &amp;#x22;count&amp;#x22;: len(filtered),        &amp;#x22;results&amp;#x22;: filtered,    }@app.options(&amp;#x22;/products&amp;#x22;)async def products_options():    # Principle 4: Accept-Query দিয়ে discoverability    from fastapi.responses import Response    return Response(        status_code=204,        headers={            &amp;#x22;Allow&amp;#x22;: &amp;#x22;GET, QUERY, OPTIONS&amp;#x22;,            &amp;#x22;Accept-Query&amp;#x22;: &amp;#x22;application/json&amp;#x22;,        },    )def apply_filters(query: ProductQuery) -&gt; list[dict]:    # এখানে আপনার আসল database query logic বসবে    return []&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;খেয়াল করেছেন? এখানে আমি &lt;code&gt;@app.api_route&lt;/code&gt; ব্যবহার করেছি। কারণ FastAPI-এর built-in decorator (যেমন &lt;code&gt;@app.get&lt;/code&gt; বা &lt;code&gt;@app.post&lt;/code&gt;) এর মধ্যে এখনো &lt;code&gt;QUERY&lt;/code&gt; নেই, কিন্তু &lt;code&gt;api_route&lt;/code&gt;-এর &lt;code&gt;methods&lt;/code&gt; প্যারামিটারে যেকোনো string পাস করা যায়। Starlette শুধু incoming request-এর &lt;code&gt;scope[&quot;method&quot;]&lt;/code&gt; কে আপনার দেওয়া list-এর সাথে ম্যাচ করে নেয়, তাই এটা একদম মাখনের মতো কাজ করে!&lt;/p&gt;
&lt;div class=&quot;callout&quot; role=&quot;note&quot; data-type=&quot;note&quot;&gt;
&lt;p class=&quot;callout-title&quot;&gt;OpenAPI ডকুমেন্টেশনের একটা ছোট্ট সীমাবদ্ধতা&lt;/p&gt;
&lt;p&gt;OpenAPI স্পেসিফিকেশনের method list এখনো &lt;code&gt;QUERY&lt;/code&gt; অন্তর্ভুক্ত করেনি। তাই Swagger UI বা ReDoc এই endpoint-টা সঠিকভাবে না-ও দেখাতে পারে, এটা দেখে ঘাবড়াবেন না কিন্তু! runtime-এ আপনার endpoint একদম পুরোপুরি কাজ করবে। GUI ডকুমেন্টেশনের বদলে সরাসরি HTTP client দিয়ে টেস্ট করে দেখবেন।&lt;/p&gt;
&lt;/div&gt;
&lt;h3 id=&quot;pytest-দিয়ে-টেস্ট-লেখা&quot;&gt;Pytest দিয়ে টেস্ট লেখা&lt;/h3&gt;
&lt;p&gt;কোড লিখলাম আর টেস্ট করব না, তা কি হয়? আসুন একটা ছোট async টেস্ট লিখে ফেলি:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame has-title&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;Python&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;python&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#8B949E&quot;&gt;# test_products.py&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; pytest&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; httpx &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; AsyncClient, ASGITransport&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; main &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; app&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D2A8FF&quot;&gt;@pytest.mark.asyncio&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;async&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;def&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D2A8FF&quot;&gt;test_query_products_success&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;():&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;transport &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; ASGITransport(&lt;/span&gt;&lt;span style=&quot;--0:#FFA657&quot;&gt;app&lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;app)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;async&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;with&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; AsyncClient(&lt;/span&gt;&lt;span style=&quot;--0:#FFA657&quot;&gt;transport&lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;transport, &lt;/span&gt;&lt;span style=&quot;--0:#FFA657&quot;&gt;base_url&lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;&quot;http://test&quot;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;as&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; client:&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;response &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;await&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; client.request(&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;            &lt;/span&gt;&lt;span style=&quot;--0:#FFA657&quot;&gt;method&lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;&quot;QUERY&quot;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#FFA657&quot;&gt;url&lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;&quot;/products&quot;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;            &lt;/span&gt;&lt;span style=&quot;--0:#FFA657&quot;&gt;json&lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;&quot;category&quot;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;&quot;phone&quot;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;&quot;brand&quot;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;&quot;apple&quot;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;},&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;assert&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; response.status_code &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;==&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;200&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;assert&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; response.json()[&lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;&quot;query&quot;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;][&lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;&quot;category&quot;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;] &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;==&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;&quot;phone&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;# test_products.pyimport pytestfrom httpx import AsyncClient, ASGITransportfrom main import app@pytest.mark.asyncioasync def test_query_products_success():    transport = ASGITransport(app=app)    async with AsyncClient(transport=transport, base_url=&amp;#x22;http://test&amp;#x22;) as client:        response = await client.request(            method=&amp;#x22;QUERY&amp;#x22;, url=&amp;#x22;/products&amp;#x22;,            json={&amp;#x22;category&amp;#x22;: &amp;#x22;phone&amp;#x22;, &amp;#x22;brand&amp;#x22;: &amp;#x22;apple&amp;#x22;},        )    assert response.status_code == 200    assert response.json()[&amp;#x22;query&amp;#x22;][&amp;#x22;category&amp;#x22;] == &amp;#x22;phone&amp;#x22;&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;আর টার্মিনালে curl দিয়ে ম্যানুয়াল ভেরিফিকেশন করতে চাইলে:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame is-terminal has-title&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;Terminal&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FFA657&quot;&gt;curl&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;-i&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;-X&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;QUERY&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;http://localhost:8000/products&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;\&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;-H&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;&quot;Content-Type: application/json&quot;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;\&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;-d&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;&apos;{&quot;category&quot;: &quot;phone&quot;, &quot;brand&quot;: &quot;apple&quot;, &quot;price&quot;: {&quot;min&quot;: 100, &quot;max&quot;: 1000}}&apos;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;curl -i -X QUERY http://localhost:8000/products \  -H &amp;#x22;Content-Type: application/json&amp;#x22; \  -d &amp;#x27;{&amp;#x22;category&amp;#x22;: &amp;#x22;phone&amp;#x22;, &amp;#x22;brand&amp;#x22;: &amp;#x22;apple&amp;#x22;, &amp;#x22;price&amp;#x22;: {&amp;#x22;min&amp;#x22;: 100, &amp;#x22;max&amp;#x22;: 1000}}&amp;#x27;&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;figure&gt;&lt;img src=&quot;https://raw.githubusercontent.com/rafeuddaraj/rafes-blog-assets/refs/heads/http-query-method-rfc-10008-complete-engineering-handbook/assets/http-query-method-comparison.svg&quot; alt=&quot;HTTP Method Semantic Comparison: GET vs POST vs QUERY method এর caching এবং database interaction তুলনা&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;900&quot; height=&quot;560&quot;&gt;&lt;figcaption&gt;HTTP Method Semantic Comparison: GET vs POST vs QUERY method এর caching এবং database interaction তুলনা&lt;/figcaption&gt;&lt;/figure&gt;
&lt;h2 id=&quot;server-layer-trap-uvicorn-parser-internals-এখানেই-আসল-রহস্য&quot;&gt;Server-Layer Trap: Uvicorn Parser Internals (এখানেই আসল রহস্য!)&lt;/h2&gt;
&lt;p&gt;দাঁড়ান দাঁড়ান যাবেন না! এখানে একটা মারাত্মক প্রোডাকশন ট্র্যাপ আছে! আমাদের ১ নাম্বার প্রিন্সিপালটা এখানে সবচেয়ে বেশি গুরুত্বপূর্ণ হয়ে দাঁড়ায়। কারণ উপরের কোড আপনার লোকাল মেশিনে পারফেক্টলি কাজ করলেও প্রোডাকশনে গিয়ে সাইলেন্টলি ভেঙে পড়তে পারে! কেন জানেন?&lt;/p&gt;
&lt;p&gt;Uvicorn মূলত দুই ধরনের HTTP parser দিয়ে চলতে পারে। আপনি যখন &lt;code&gt;pip install uvicorn[standard]&lt;/code&gt; করেন, তখন ডিফল্টভাবে যেটা ইনস্টল হয় সেটা হলো &lt;code&gt;httptools&lt;/code&gt;। এটা মূলত Node.js-এর &lt;code&gt;llhttp&lt;/code&gt; parser-এর একটা Python wrapper। এই parser-টা হলো একদম কড়া হেডমাস্টারের মতো! সে method name গুলো একটা fixed, case-sensitive টেবিলের সাথে ম্যাচ করে। তার মানে, তার কাছে &lt;code&gt;&quot;QUERY&quot;&lt;/code&gt; আর &lt;code&gt;&quot;query&quot;&lt;/code&gt; সম্পূর্ণ ভিন্ন দুইটা জিনিস! ভুল করে লোয়ারকেস &lt;code&gt;&quot;query&quot;&lt;/code&gt; এলে &lt;code&gt;httptools&lt;/code&gt; সেটা চিনতেই পারে না, আর আপনার FastAPI কোড পর্যন্ত পৌঁছানোর আগেই গেট থেকে সরাসরি &lt;code&gt;400 Bad Request&lt;/code&gt; দিয়ে লাথি মেরে বের করে দেয়!&lt;/p&gt;
&lt;p&gt;বিপরীতে Uvicorn-এর দ্বিতীয় অপশন হলো &lt;code&gt;h11&lt;/code&gt;। এটা একটা pure-Python HTTP/1.1 implementation, এবং এটা অনেক বেশি চিল বন্ধু টাইপের! সে লোয়ারকেস method নিয়েও কোনো অভিযোগ করে না, বরং সেটাকে একদম routing পর্যন্ত পৌঁছে দেয়। সেখানে matched route না পেলে সে ভদ্রভাবে &lt;code&gt;405 Method Not Allowed&lt;/code&gt; রিটার্ন করে।&lt;/p&gt;
&lt;figure&gt;&lt;img src=&quot;https://raw.githubusercontent.com/rafeuddaraj/rafes-blog-assets/refs/heads/http-query-method-rfc-10008-complete-engineering-handbook/assets/fastapi-uvicorn-query-parser-flow.svg&quot; alt=&quot;FastAPI QUERY request একটা httptools parser এ 400 এবং h11 parser এ 200 রিটার্ন করার routing ডায়াগ্রাম&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;900&quot; height=&quot;620&quot;&gt;&lt;figcaption&gt;FastAPI QUERY request একটা httptools parser এ 400 এবং h11 parser এ 200 রিটার্ন করার routing ডায়াগ্রাম&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;তাহলে সমাধান কী? টার্মিনালে parser এক্সপ্লিসিটভাবে সিলেক্ট করে দিবেন:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame is-terminal has-title&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;Terminal&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#8B949E&quot;&gt;# Parser এক্সপ্লিসিটভাবে সিলেক্ট করা&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FFA657&quot;&gt;uvicorn&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;main:app&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;--http&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;httptools&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;   &lt;/span&gt;&lt;span style=&quot;--0:#8B949E&quot;&gt;# ডিফল্ট, দ্রুততর, কিন্তু কেস-সেনসিটিভ&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FFA657&quot;&gt;uvicorn&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;main:app&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;--http&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;h11&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;         &lt;/span&gt;&lt;span style=&quot;--0:#8B949E&quot;&gt;# ধীরগতি, কিন্তু বেশি lenient&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;uvicorn main:app --http httptools   # ডিফল্ট, দ্রুততর, কিন্তু কেস-সেনসিটিভuvicorn main:app --http h11         # ধীরগতি, কিন্তু বেশি lenient&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;এখন প্রশ্ন হলো, এই লোয়ারকেস method আসে কোথা থেকে? এর উত্তর লুকিয়ে আছে আমাদের ক্লায়েন্ট-সাইডে!&lt;/p&gt;
&lt;h2 id=&quot;client-side-gotcha-fetch-কেন-আপনার-query-কে-lowercase-রেখে-দেয়&quot;&gt;Client-Side Gotcha: &lt;code&gt;fetch()&lt;/code&gt; কেন আপনার &lt;code&gt;QUERY&lt;/code&gt; কে lowercase রেখে দেয়?&lt;/h2&gt;
&lt;p&gt;ব্রাউজারের &lt;code&gt;fetch()&lt;/code&gt; নিয়ে একটা আজব কাহিনী শুনবেন? WHATWG Fetch স্পেসিফিকেশনে &quot;normalize a method&quot; নামে একটা স্টেপ আছে। এই স্টেপের কাজ হলো মেথডের নামকে বড় হাতের অক্ষর বা uppercase করে দেওয়া। কিন্তু মজা হলো, সে শুধু ছয়টা classic method-কেই uppercase করে: &lt;code&gt;DELETE&lt;/code&gt;, &lt;code&gt;GET&lt;/code&gt;, &lt;code&gt;HEAD&lt;/code&gt;, &lt;code&gt;OPTIONS&lt;/code&gt;, &lt;code&gt;POST&lt;/code&gt; আর &lt;code&gt;PUT&lt;/code&gt;!&lt;/p&gt;
&lt;p&gt;আমাদের বেচারা &lt;code&gt;QUERY&lt;/code&gt; এই ভিআইপি তালিকায় নেই, কারণ এটা তৈরি হয়েছে এই ছয়টা চূড়ান্ত হওয়ার অনেক অনেক পরে! ফলে কোনো ফ্রন্টএন্ড ডেভেলপার ভুল করে যদি &lt;code&gt;fetch(url, { method: &quot;query&quot; })&lt;/code&gt; লিখে ফেলে, ব্রাউজার সেটাকে ঠিক সেভাবেই, লোয়ারকেস অবস্থাতেই wire-এ পাঠিয়ে দেয়! এই আচরণ নিয়ে ২০২৬ সালের জুনে whatwg/fetch রিপোজিটরিতে একটা আলাদা ইস্যু ওপেন করা হয়েছে, যেখানে &lt;code&gt;QUERY&lt;/code&gt; কে normalize করা উচিত কিনা তা নিয়ে এখনো জোর আলোচনা চলছে।&lt;/p&gt;
&lt;p&gt;তাই ফ্রন্টএন্ড থেকে লেখার সময় একদম সঠিকভাবে লিখবেন:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame has-title&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;JavaScript&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;js&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;response&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;await&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D2A8FF&quot;&gt;fetch&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;&quot;/products&quot;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;, {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;method: &lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;&quot;QUERY&quot;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#8B949E&quot;&gt;// অবশ্যই uppercase রাখতে হবে, ভুলবেন না!&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;headers: { &lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;&quot;Content-Type&quot;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;&quot;application/json&quot;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; },&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;body: &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;JSON&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#D2A8FF&quot;&gt;stringify&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;({ category: &lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;&quot;phone&quot;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;, brand: &lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;&quot;apple&quot;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; }),&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;});&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;data&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;await&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; response.&lt;/span&gt;&lt;span style=&quot;--0:#D2A8FF&quot;&gt;json&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;const response = await fetch(&amp;#x22;/products&amp;#x22;, {  method: &amp;#x22;QUERY&amp;#x22;, // অবশ্যই uppercase রাখতে হবে, ভুলবেন না!  headers: { &amp;#x22;Content-Type&amp;#x22;: &amp;#x22;application/json&amp;#x22; },  body: JSON.stringify({ category: &amp;#x22;phone&amp;#x22;, brand: &amp;#x22;apple&amp;#x22; }),});const data = await response.json();&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;আর আপনি যদি Node.js ব্যাকএন্ড থেকে অন্য সার্ভিসে request পাঠাতে চান, তাহলে জেনে খুশি হবেন যে Node-এর নিজস্ব &lt;code&gt;undici&lt;/code&gt; লাইব্রেরি (যেটা Node-এর built-in &lt;code&gt;fetch&lt;/code&gt;-এর পেছনে কাজ করে) ২০২৬ সালের গ্রীষ্মে একটা merged pull request-এর মাধ্যমে &lt;code&gt;QUERY&lt;/code&gt; সাপোর্ট যোগ করেছে! সেই সাথে একটা body-aware cache key implementation reference-ও দিয়ে দিয়েছে। আর Node.js তার নিজস্ব HTTP parser দিয়ে ২০২৪ সালের শুরু থেকেই (Node 21.7.2 এবং 22+ ভার্সনে) &lt;code&gt;QUERY&lt;/code&gt; কে একটা বৈধ method হিসেবে চিনতে পারে।&lt;/p&gt;
&lt;p&gt;Python-এর &lt;code&gt;httpx&lt;/code&gt; দিয়ে করতে চাইলে:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame has-title&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;Python&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;python&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; httpx&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;async&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;with&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; httpx.AsyncClient() &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;as&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; client:&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;response &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;await&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; client.request(&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#FFA657&quot;&gt;method&lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;&quot;QUERY&quot;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#FFA657&quot;&gt;url&lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;&quot;http://localhost:8000/products&quot;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#FFA657&quot;&gt;json&lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;&quot;category&quot;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;&quot;phone&quot;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;&quot;brand&quot;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;&quot;apple&quot;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;},&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;import httpxasync with httpx.AsyncClient() as client:    response = await client.request(        method=&amp;#x22;QUERY&amp;#x22;,        url=&amp;#x22;http://localhost:8000/products&amp;#x22;,        json={&amp;#x22;category&amp;#x22;: &amp;#x22;phone&amp;#x22;, &amp;#x22;brand&amp;#x22;: &amp;#x22;apple&amp;#x22;},    )&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;h2 id=&quot;caching-যেটার-জন্য-এতো-নাটক-সেটার-আজকের-বাস্তবতা-কী&quot;&gt;Caching: যেটার জন্য এতো নাটক, সেটার আজকের বাস্তবতা কী?&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;QUERY&lt;/code&gt;-এর সবচেয়ে বড় selling point-ই তো ছিল caching, তাই না? RFC-এর নিয়ম অনুযায়ী এর response cache করা সম্ভব। কিন্তু এখানে একটা টুইস্ট আছে! cache key শুধু URL দিয়ে বানালে চলবে না, request body-ও cache key-এর একটা অবিচ্ছেদ্য অংশ হতে হবে! RFC নিজেই একটা মারাত্মক ঝুঁকির কথা বলেছে (যেটা আমি ব্র্যাকেটে বলে রাখছি, কোনো cache implementation যদি body ভুলভাবে normalize করে এবং সেটার কারণে false positive তৈরি হয়, তাহলে এক ইউজারের সেনসিটিভ ডেটা আরেক ইউজারের কাছে চলে যেতে পারে!)।&lt;/p&gt;
&lt;p&gt;বাস্তবতা হলো, ২০২৬ সালের জুলাই পর্যন্ত Chrome বা Firefox কেউই একই &lt;code&gt;QUERY&lt;/code&gt; request দ্বিতীয়বার পাঠালে সেটা browser cache থেকে সার্ভ করে না! browser-level caching এখনো standardization আলোচনার পর্যায়েই আছে, Fetch স্পেসিফিকেশনে এটা কীভাবে হবে তা নিয়ে এখনো চূড়ান্ত সিদ্ধান্ত হয়নি। That&apos;s the real game!&lt;/p&gt;
&lt;div class=&quot;callout&quot; role=&quot;note&quot; data-type=&quot;warning&quot;&gt;
&lt;p class=&quot;callout-title&quot;&gt;নিজস্ব Caching Layer বানালে সাবধান!&lt;/p&gt;
&lt;p&gt;আপনি যদি নিজে একটা caching layer বানান (যেমন Redis, CDN edge rule বা reverse proxy দিয়ে), সেই cache key তৈরিতে request body ঠিকমতো hash বা normalize না করলে দুইটা ভিন্ন filter criteria একই cache entry শেয়ার করে ফেলতে পারে! এর ফলাফল হতে পারে cache poisoning বা cache deception! body-এর একটা cryptographic digest (যেমন SHA-256, RFC 9530-এর &lt;code&gt;Content-Digest&lt;/code&gt; header ব্যবহার করে) cache key-তে যোগ করাই সবচেয়ে নিরাপদ পদ্ধতি। এই ধরনের digest-aware cache নিয়ে আলোচনা এখনো IETF HTTP Working Group-এ চলছে।&lt;/p&gt;
&lt;/div&gt;
&lt;h2 id=&quot;infrastructure-ও-ecosystem-adoption-আজকের-বাস্তব-অবস্থা&quot;&gt;Infrastructure ও Ecosystem Adoption: আজকের বাস্তব অবস্থা&lt;/h2&gt;
&lt;p&gt;এই টেবিলটাই সম্ভবত আজকের আর্টিকেলের সবচেয়ে বেশি প্র্যাকটিক্যাল ভ্যালু বহন করে। কারণ এটা স্পষ্ট বলে দেয় ঠিক কোথায় আজকে আপনি রিস্ক নিচ্ছেন আর কোথায় একদম সেফ:&lt;/p&gt;
&lt;section class=&quot;table-wrap&quot; tabindex=&quot;0&quot; aria-label=&quot;Table 2&quot;&gt;
















































&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Component&lt;/th&gt;&lt;th&gt;Status (জুলাই ২০২৬)&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;Node.js core HTTP parser&lt;/td&gt;&lt;td&gt;নেটিভ সাপোর্ট, Node 21.7.2 এবং 22+ থেকে&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Node.js undici / fetch&lt;/td&gt;&lt;td&gt;সাপোর্ট merged, body-aware cache key সহ&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;nginx&lt;/td&gt;&lt;td&gt;Basic RFC 10008 সাপোর্ট মার্জ হয়েছে&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Chrome, Firefox (browser fetch)&lt;/td&gt;&lt;td&gt;Scripted fetch কাজ করে, কিন্তু caching এখনো implement হয়নি&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Kong Gateway&lt;/td&gt;&lt;td&gt;Method uppercase হতে হয়, native QUERY awareness এখনো emerging&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;AWS API Gateway&lt;/td&gt;&lt;td&gt;এখনো নেটিভভাবে সাপোর্ট করে না, শুধু GET/POST/PUT/PATCH/DELETE/HEAD/ANY, ANY দিয়ে workaround করলে body strip বা 403/405 হওয়ার ঝুঁকি আছে&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Spring Framework&lt;/td&gt;&lt;td&gt;সাপোর্ট যোগ করার issue/PR এখনো ওপেন&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Ruby on Rails&lt;/td&gt;&lt;td&gt;Community proposal আলোচনায়, এখনো merged না&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Eclipse Jetty, Apache Tomcat&lt;/td&gt;&lt;td&gt;সাপোর্টের জন্য ইস্যু ওপেন, active development চলছে&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;OpenAPI tooling&lt;/td&gt;&lt;td&gt;OpenAPI 3.2 এ documented, কিন্তু Swagger UI/ReDoc rendering এখনো অসম্পূর্ণ&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/section&gt;
&lt;div class=&quot;callout&quot; role=&quot;note&quot; data-type=&quot;warning&quot;&gt;
&lt;p class=&quot;callout-title&quot;&gt;Production Readiness মাথায় রাখুন!&lt;/p&gt;
&lt;p&gt;এই টেবিল দেখেই বোঝা যায় কেন public-facing, browser-নির্ভর traffic-এ আজকেই একলাফে পুরোপুরি &lt;code&gt;QUERY&lt;/code&gt;-তে মাইগ্রেট করা ঠিক হবে না। Server-to-server communication-এ, বিশেষ করে Node.js এবং সঠিকভাবে কনফিগার করা Python backend-এর মধ্যে, এটা আজই ১০০% নির্ভরযোগ্য। কিন্তু আপনার পুরো path (client, CDN, API Gateway, WAF, backend) সবগুলো layer &lt;code&gt;QUERY&lt;/code&gt; সাপোর্ট নিশ্চিত না করা পর্যন্ত পাবলিক API-তে &lt;code&gt;POST /search&lt;/code&gt; কে fallback হিসেবে রেখে দিন।&lt;/p&gt;
&lt;/div&gt;
&lt;h2 id=&quot;security-consideration&quot;&gt;Security Consideration&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;QUERY&lt;/code&gt;-কে &quot;safe&quot; method হিসেবে চিহ্নিত করার মানে হলো, অনেক ইনফ্রাস্ট্রাকচার কম্পোনেন্ট (যেমন WAF, rate limiter, বা CSRF protection) এটাকে স্বয়ংক্রিয়ভাবে &lt;code&gt;GET&lt;/code&gt;-এর মতোই &quot;নিরাপদ ও non-mutating&quot; ধরে নেবে। এখন কোনো ভুল implementation যদি &lt;code&gt;QUERY&lt;/code&gt; handler-এর ভেতরে সত্যিকারের state mutation রেখে দেয়, তাহলে সেটা একটা মারাত্মক সিকিউরিটি হোল তৈরি করবে, কারণ ইনফ্রাস্ট্রাকচার এটাকে CSRF-exempt ধরে নেবে! এছাড়া অপরিচিত method নিয়ে পুরনো &lt;a href=&quot;/blog/block-ai-crawlers-cloudflare-waf-guide&quot;&gt;WAF&lt;/a&gt; আর reverse proxy-র আচরণও বেশ অসংগত হয়। কিছু সিস্টেম অজানা method দেখলে পুরো request ব্লক করে দেয়, আবার কিছু সিস্টেম না চিনেই pass through করে দেয়। সাবধানে হ্যান্ডেল করবেন!&lt;/p&gt;
&lt;h2 id=&quot;migration-strategy-ধাপে-ধাপে-কীভাবে-এগোবেন&quot;&gt;Migration Strategy: ধাপে ধাপে কীভাবে এগোবেন?&lt;/h2&gt;
&lt;p&gt;একলাফে সব মাইগ্রেট করার কোনো দরকার নাই ভাই! একটা বাস্তবসম্মত এবং স্মার্ট পদ্ধতি হলো dual-support। আপনার ব্যাকএন্ড একই business logic-কে দুইটা route-এ এক্সপোজ করবে:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame has-title&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;Python&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;python&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D2A8FF&quot;&gt;@app.api_route&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;&quot;/products&quot;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#FFA657&quot;&gt;methods&lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;&quot;QUERY&quot;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;])&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;async&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;def&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D2A8FF&quot;&gt;query_products&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;(request: Request, payload: ProductQuery):&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;await&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; run_search(payload)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D2A8FF&quot;&gt;@app.post&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;&quot;/products/search&quot;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;async&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;def&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D2A8FF&quot;&gt;post_search_fallback&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;(payload: ProductQuery):&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;await&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; run_search(payload)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;@app.api_route(&amp;#x22;/products&amp;#x22;, methods=[&amp;#x22;QUERY&amp;#x22;])async def query_products(request: Request, payload: ProductQuery):    return await run_search(payload)@app.post(&amp;#x22;/products/search&amp;#x22;)async def post_search_fallback(payload: ProductQuery):    return await run_search(payload)&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;ক্লায়েন্ট-সাইডে প্রথমে &lt;code&gt;OPTIONS /products&lt;/code&gt; করে &lt;code&gt;Allow&lt;/code&gt; header চেক করে নেবেন। যদি দেখেন &lt;code&gt;QUERY&lt;/code&gt; আছে, তাহলে সেটা বুক ফুলিয়ে ব্যবহার করুন, আর না থাকলে শান্তশিষ্টভাবে &lt;code&gt;POST /products/search&lt;/code&gt;-এ fallback করুন। এই ধরনের feature detection আপনাকে ecosystem-এর পরিপক্কতার সাথে সাথে স্বয়ংক্রিয়ভাবে মাইগ্রেট হতে সাহায্য করবে, কোনো hard cutover ছাড়াই!&lt;/p&gt;
&lt;h2 id=&quot;query-বনাম-graphql-একটা-সাধারণ-ভুল-বোঝাবুঝি&quot;&gt;QUERY বনাম GraphQL: একটা সাধারণ ভুল বোঝাবুঝি&lt;/h2&gt;
&lt;p&gt;অনেকেই ভাবেন &lt;code&gt;QUERY&lt;/code&gt; method এসে বুঝি GraphQL-কে খেয়ে ফেলবে বা replace করবে! আরে না ভাই, এই দুইটা সম্পূর্ণ ভিন্ন লেয়ারে কাজ করে।&lt;/p&gt;
&lt;p&gt;GraphQL হলো একটা query language এবং schema system, যেটা সাধারণত একটা single &lt;code&gt;POST&lt;/code&gt; endpoint-এর ওপর বসানো থাকে। অন্যদিকে &lt;code&gt;QUERY&lt;/code&gt; method নিজে কোনো query language না, এটা শুধু transport-লেয়ারের একটা HTTP method, যেটা GraphQL-সহ যেকোনো query language-কে সঠিক semantics দিয়ে বহন করতে পারে। ভবিষ্যতে GraphQL সার্ভারগুলো চাইলে &lt;code&gt;POST&lt;/code&gt; এর বদলে &lt;code&gt;QUERY&lt;/code&gt; method ব্যবহার করে caching এবং idempotency-র জোস সব সুবিধা নিতে পারে, কিন্তু তাতে GraphQL-এর নিজস্ব query syntax মোটেও বদলাবে না। বুঝতে পেরেছেন?&lt;/p&gt;
&lt;h2 id=&quot;testing-ও-tooling-checklist&quot;&gt;Testing ও Tooling Checklist&lt;/h2&gt;
&lt;p&gt;টেস্ট করার সময় নিচের টুলগুলোর দিকে একটু নজর রাখবেন:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;curl:&lt;/strong&gt; &lt;code&gt;-X QUERY&lt;/code&gt; দিয়ে সরাসরি সাপোর্ট করে, সবচেয়ে নির্ভরযোগ্য quick-test টুল।&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;httpx (Python):&lt;/strong&gt; &lt;code&gt;client.request(method=&quot;QUERY&quot;, ...)&lt;/code&gt; দিয়ে একদম মাখনের মতো কাজ করে।&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;k6:&lt;/strong&gt; কাস্টম HTTP method নেটিভভাবে সাপোর্ট করে, load testing-এর জন্য জোস একটা অপশন।&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;JMeter:&lt;/strong&gt; ডিফল্টভাবে &lt;code&gt;QUERY&lt;/code&gt; লিস্টে থাকে না, HTTP sampler-এ আলাদা property configuration করে নিতে হয়।&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Postman/Swagger UI:&lt;/strong&gt; এখনো একটু inconsistent, OpenAPI tooling পুরোপুরি catch up করেনি, তাই এগুলোর ওপর চোখ বন্ধ করে নির্ভর না করাই ভালো।&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;production-checklist-সংক্ষেপে-এক-নজরে&quot;&gt;Production Checklist (সংক্ষেপে এক নজরে)&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;ASGI সার্ভারের HTTP parser এক্সপ্লিসিটভাবে ঠিক করুন, টেস্ট ও প্রোডাকশনে সবসময় একই parser রাখুন।&lt;/li&gt;
&lt;li&gt;ফ্রন্টএন্ড কোডে method name সবসময় uppercase &lt;code&gt;&quot;QUERY&quot;&lt;/code&gt; রাখুন এবং &lt;code&gt;allow_methods&lt;/code&gt;-এ CORS preflight টেস্ট করে নিন।&lt;/li&gt;
&lt;li&gt;Content-Type validation বাস্তবায়ন করুন, mismatch হলে গেট থেকেই 400/415/422 রিটার্ন করুন।&lt;/li&gt;
&lt;li&gt;&lt;code&gt;OPTIONS&lt;/code&gt;-এ &lt;code&gt;Accept-Query&lt;/code&gt; এবং &lt;code&gt;Allow&lt;/code&gt; header দিয়ে discoverability নিশ্চিত করুন।&lt;/li&gt;
&lt;li&gt;Browser caching-এর ওপর অন্ধের মতো নির্ভর করবেন না, নিজস্ব caching layer বানালে body digest cache key-তে যোগ করুন।&lt;/li&gt;
&lt;li&gt;WAF, API Gateway এবং CDN আপনার path-এ &lt;code&gt;QUERY&lt;/code&gt; কীভাবে হ্যান্ডেল করছে আলাদাভাবে verify করুন, বিশেষ করে AWS API Gateway-এর মতো সার্ভিসে।&lt;/li&gt;
&lt;li&gt;পাবলিক-facing API-তে &lt;code&gt;POST /search&lt;/code&gt;-কে fallback হিসেবে রাখুন যতক্ষণ পুরো infrastructure path native সাপোর্ট নিশ্চিত না করছে।&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;সংক্ষেপে-বোঝার-জন্য-একটা-জোস-analogy&quot;&gt;সংক্ষেপে বোঝার জন্য একটা জোস Analogy!&lt;/h2&gt;
&lt;p&gt;পুরো বিষয়টা যদি এখনো একটু ঘোলাটে লাগে, তাহলে এই সহজ তুলনাটা মনে রাখেন:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;GET&lt;/code&gt; হলো খোলা পোস্টকার্ড পাঠানোর মতো। লেখার জায়গা একদম সীমিত, রাস্তার পিয়ন থেকে শুরু করে সবাই সেটা পড়তে পারে, কিন্তু এটা সম্পূর্ণ safe।&lt;/p&gt;
&lt;p&gt;&lt;code&gt;POST&lt;/code&gt; হলো একটা শক্ত করে সিল করা পার্সেল পাঠানো, যার ভেতরে কিছু তৈরি বা পরিবর্তনের স্পষ্ট নির্দেশ থাকে।&lt;/p&gt;
&lt;p&gt;আর আমাদের নতুন বন্ধু &lt;code&gt;QUERY&lt;/code&gt; হলো একটা লাইব্রেরির আর্কাইভে ডিটেইলড রিকুইজিশন ফর্ম ভরে পাঠানো! আপনি লাইব্রেরির কোনো বই বদলাতে বা ছিঁড়তে বলছেন না, শুধু জটিল সব শর্ত উল্লেখ করে সঠিক তথ্যটা খুঁজে বের করতে বলছেন। পার্থক্য হলো, এই আর্কাইভ সিস্টেমটা সবেমাত্র নতুন চালু হয়েছে, তাই কিছু কাউন্টার এখনো পুরনো নিয়মেই ফর্ম প্রসেস করছে, আর কিছু কাউন্টার এখনো সেই ফর্মটাই চেনে না! উপমাটা কেমন লাগলো? একদম সহজ না?&lt;/p&gt;
&lt;h2 id=&quot;faq&quot;&gt;FAQ&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;QUERY কি POST-কে সম্পূর্ণ replace করে ফেলবে?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;না ভাই, একদমই না! এটা শুধু সেই নির্দিষ্ট gap পূরণ করে যেখানে safe read operation-এ request body দরকার হয়। state পরিবর্তনকারী operation-এর জন্য &lt;code&gt;POST&lt;/code&gt;, &lt;code&gt;PUT&lt;/code&gt;, &lt;code&gt;PATCH&lt;/code&gt;, আর &lt;code&gt;DELETE&lt;/code&gt; আগের মতোই রাজত্ব করবে।&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;আজকেই কি প্রোডাকশনে ব্যবহার করা যাবে?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Server-to-server communication-এ, বিশেষ করে যেখানে আপনি নিজেই client এবং server দুইটাই নিয়ন্ত্রণ করেন, সেখানে আজকেই ১০০% করা যাবে। তবে Public browser-facing API-তে upstream table-এ দেখানো সীমাবদ্ধতার কারণে এখনো একটু সাবধানে এগোনো উচিত।&lt;/p&gt;
&lt;h2 id=&quot;শেষ-কথা-ও-শুভকামনা&quot;&gt;শেষ কথা ও শুভকামনা!&lt;/h2&gt;
&lt;p&gt;আজকে তো বহুত বকবক করলাম! আশা করি পুরো বিষয়টা একদম পানির মতো পরিষ্কার হয়ে গেছে। ১৬ বছরের পুরনো একটা সমস্যার সমাধান চোখের সামনে দেখতে পাওয়ার আনন্দই আলাদা, তাই না?&lt;/p&gt;
&lt;p&gt;আপনার পরবর্তী প্রজেক্টে এই &lt;code&gt;QUERY&lt;/code&gt; method ট্রাই করে দেখবেন কিনা, আমাকে কিন্তু জানাতে ভুলবেন না! আর কোনো জায়গায় বুঝতে সমস্যা হলে বা কোনো প্রশ্ন থাকলে কমেন্টে চট করে লিখে ফেলুন। আমার জন্য অনেক অনেক দোয়া করবেন, আমিও আপনাদের সবার জন্য দোয়া করি। আপনাদের অনেক অনেক ধন্যবাদ এতোক্ষণ ধরে আমার এই হিজিবিজি হজবরল লেখাটা পড়ার জন্য!&lt;/p&gt;
&lt;h2 id=&quot;references&quot;&gt;References&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Specification:&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;RFC 10008, The HTTP QUERY Method (IETF): &lt;a href=&quot;https://www.rfc-editor.org/info/rfc10008&quot; rel=&quot;noopener noreferrer&quot;&gt;https://www.rfc-editor.org/info/rfc10008&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;HTTP Semantics, RFC 9110: &lt;a href=&quot;https://www.rfc-editor.org/rfc/rfc9110.html&quot; rel=&quot;noopener noreferrer&quot;&gt;https://www.rfc-editor.org/rfc/rfc9110.html&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Content-Digest header field, RFC 9530: &lt;a href=&quot;https://www.rfc-editor.org/rfc/rfc9530.html&quot; rel=&quot;noopener noreferrer&quot;&gt;https://www.rfc-editor.org/rfc/rfc9530.html&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;IANA HTTP Field Name Registry (Accept-Query): &lt;a href=&quot;https://www.iana.org/assignments/http-fields&quot; rel=&quot;noopener noreferrer&quot;&gt;https://www.iana.org/assignments/http-fields&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;Implementation and Ecosystem Discussions:&lt;/strong&gt;&lt;/p&gt;
&lt;ol start=&quot;5&quot;&gt;
&lt;li&gt;FastAPI Discussion #5520, APIRouter HTTP Method Query: &lt;a href=&quot;https://github.com/fastapi/fastapi/discussions/5520&quot; rel=&quot;noopener noreferrer&quot;&gt;https://github.com/fastapi/fastapi/discussions/5520&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Uvicorn httptools_impl.py Source Code: &lt;a href=&quot;https://github.com/Kludex/uvicorn/blob/main/uvicorn/protocols/http/httptools_impl.py&quot; rel=&quot;noopener noreferrer&quot;&gt;https://github.com/Kludex/uvicorn/blob/main/uvicorn/protocols/http/httptools_impl.py&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Node.js undici, QUERY method support (merged PR): &lt;a href=&quot;https://github.com/nodejs/undici/pull/5459&quot; rel=&quot;noopener noreferrer&quot;&gt;https://github.com/nodejs/undici/pull/5459&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;WHATWG Fetch, Issue #1938 (method normalization, CORS, caching): &lt;a href=&quot;https://github.com/whatwg/fetch/issues/1938&quot; rel=&quot;noopener noreferrer&quot;&gt;https://github.com/whatwg/fetch/issues/1938&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Mozilla Standards Positions, RFC 10008: &lt;a href=&quot;https://github.com/mozilla/standards-positions/issues/1430&quot; rel=&quot;noopener noreferrer&quot;&gt;https://github.com/mozilla/standards-positions/issues/1430&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Spring Framework, QUERY method support issue: &lt;a href=&quot;https://github.com/spring-projects/spring-framework/issues/36988&quot; rel=&quot;noopener noreferrer&quot;&gt;https://github.com/spring-projects/spring-framework/issues/36988&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Ruby on Rails, QUERY method proposal discussion: &lt;a href=&quot;https://discuss.rubyonrails.org/t/proposal-support-for-the-http-query-method-rfc-10008/91255&quot; rel=&quot;noopener noreferrer&quot;&gt;https://discuss.rubyonrails.org/t/proposal-support-for-the-http-query-method-rfc-10008/91255&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Ecosystem Adoption Tracker, QUERY Method: &lt;a href=&quot;https://github.com/jeswr/http-query-adoption&quot; rel=&quot;noopener noreferrer&quot;&gt;https://github.com/jeswr/http-query-adoption&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;AWS re:Post, HTTP QUERY Method and API Gateway: &lt;a href=&quot;https://repost.aws/questions/QUMU66SxOLT1qXBVZaBHCtxA/http-query-method&quot; rel=&quot;noopener noreferrer&quot;&gt;https://repost.aws/questions/QUMU66SxOLT1qXBVZaBHCtxA/http-query-method&lt;/a&gt;
&lt;strong&gt;General Reference:&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;MDN Web Docs, HTTP Request Methods: &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods&quot; rel=&quot;noopener noreferrer&quot;&gt;https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;</content:encoded><category>Backend Engineering</category><category>HTTP</category><category>RFC 10008</category><category>QUERY Method</category><category>API Design</category><category>FastAPI</category><category>Python</category><category>Uvicorn</category><category>Node.js</category><category>Software Architecture</category><category>Web Development</category><category>REST API</category><category>CORS</category><category>Caching</category><category>Security</category></item><item><title>QR Code Engineering Handbook: From Optical Physics to High-Concurrency Production Pipelines</title><link>https://www.rafeuddaraj.me/bn/blog/qr-code-engineering-handbook-optical-physics-production-pipeline/</link><guid isPermaLink="true">https://www.rafeuddaraj.me/bn/blog/qr-code-engineering-handbook-optical-physics-production-pipeline/</guid><description>একদম শূন্য থেকে কিউআর কোডের ভিজ্যুয়াল অ্যানাটমি, অপটিক্যাল ফিজিক্স, Reed-Solomon Error Correction-এর জটিল গণিত এবং Node.js ও React দিয়ে প্রোডাকশন-রেডি এন্টারপ্রাইজ সিস্টেম ডিজাইন করার একটি কমপ্লিট ইঞ্জিনিয়ারিং গাইড।</description><pubDate>Mon, 20 Jul 2026 08:03:22 GMT</pubDate><content:encoded>&lt;p&gt;আমরা যখন কোনো মডার্ন সফটওয়্যার সিস্টেম, ই-কমার্স লজিস্টিকস প্ল্যাটফর্ম বা ফিনটেক পেমেন্ট গেটওয়ে ডিজাইন করি, তখন একটি সাধারণ কিন্তু অত্যন্ত জটিল সমস্যার মুখোমুখি হতে হয়। সমস্যাটি হলো ফিজিক্যাল বা বাস্তব জগতের কোনো বস্তুর সাথে আমাদের ডিজিটাল ডাটাবেসের সংযোগ স্থাপন করা। আপনি যখন কোনো সুপারশপের ক্যাশ কাউন্টার, একটি ব্যস্ত এয়ারপোর্টের বোর্ডিং গেট, কিংবা কোনো ক্যুরিয়ার সার্ভিসের ওয়্যারহাউস লক্ষ্য করবেন, তখন দেখবেন সেখানে প্রতি সেকেন্ডে হাজার হাজার প্যাকেজ এবং ট্রানজ্যাকশন প্রসেস হচ্ছে। এই দ্রুতগতির অপারেশনে যদি মানুষ কীবোর্ড চেপে সিরিয়াল নাম্বার বা ট্র্যাকিং আইডি ইনপুট দিতে চায়, তবে পুরো সিস্টেমে মারাত্বক Latency এবং Human Error তৈরি হবে। এই ফিজিক্যাল-টু-ডিজিটাল ডেটা ট্রান্সফারের সবচেয়ে নির্ভরযোগ্য এবং দ্রুততম মাধ্যম হলো অপটিক্যাল কোড স্ক্যানিং।&lt;/p&gt;
&lt;p&gt;প্রযুক্তি বিশ্বে দীর্ঘদিন ধরে One-Dimensional বা 1D Barcode (যেমন UPC-A বা EAN-13) এই দায়িত্ব পালন করে আসছিল। কিন্তু একটি গ্লোবাল সাপ্লাই চেইনে যখন একটি মাত্র লেবেলের মধ্যে প্রোডাক্টের ব্যাচ নাম্বার, ম্যানুফ্যাকচারিং ডেট, এক্সপায়ারি ডেট, এবং ডেস্টিনেশন ইউআরএল একসাথে স্টোর করার প্রয়োজন দেখা দিল, তখন চিরাচরিত 1D Barcode তার ধারণক্ষমতার শেষ সীমায় পৌঁছে যায়। এই সীমাবদ্ধতা দূর করার জন্যই 1994 সালে জাপানের Denso Wave কোম্পানির চিফ ইঞ্জিনিয়ার Masahiro Hara একটি যুগান্তকারী উদ্ভাবন করেন, যা আমরা আজ Two-Dimensional বা 2D Matrix Code বা QR Code নামে চিনি।&lt;/p&gt;
&lt;p&gt;আমাদের এই বিস্তারিত ইঞ্জিনিয়ারিং হ্যান্ডবুকের উদ্দেশ্য হলো একজন সাধারণ নবীন ডেভেলপার থেকে শুরু করে একজন Lead System Architect পর্যন্ত সবার কাছে কিউআর কোডের ভেতরের সম্পূর্ণ মেকানিজম পানির মতো সহজ করে তোলা। আমরা একদম শূন্য থেকে শুরু করে অপটিক্যাল ফিজিক্স, মেমরি লেআউট, Reed-Solomon Error Correction-এর জটিল গণিত এবং Node.js ও React দিয়ে High-Concurrency প্রোডাকশন আর্কিটেকচার তৈরি করার প্রতিটি ধাপ ধাপে ধাপে বিশ্লেষণ করব। আপনি যখন এই আর্কিটেকচারাল মেকানিজমগুলো সম্পূর্ণ আত্মস্থ করতে পারবেন, তখন আপনি কেবল লাইব্রেরি ব্যবহারকারী থাকবেন না, বরং নিজেই হাই-পারফরম্যান্স এবং ফল্ট-টলারেন্ট এন্টারপ্রাইজ সিস্টেম ডিজাইন করতে সক্ষম হবেন।&lt;/p&gt;
&lt;h2 id=&quot;step-1-the-optical-bottleneck-and-architectural-evolution-1d-vs-2d&quot;&gt;Step 1: The Optical Bottleneck and Architectural Evolution (1D vs 2D)&lt;/h2&gt;
&lt;p&gt;একটি অপটিক্যাল স্ক্যানার মূলত আলোর প্রতিফলন বা Reflection-এর ওপর ভিত্তি করে কাজ করে। আপনি যখন একটি সাধারণ 1D Barcode-এর ওপর লেজার রশ্মি ফেলেন, তখন কালো দাগগুলো আলো শোষণ করে নেয় এবং সাদা ফাঁকা জায়গাগুলো আলো ফিরিয়ে দেয়। স্ক্যানারের সেন্সর এই প্রতিফলিত আলোর তীব্রতা এবং সময়ের ব্যবধান মেপে একটি লিনিয়ার বা একমুখী বাইনারি সিগন্যাল (0 এবং 1) তৈরি করে। এই লিনিয়ার স্ক্যানিং মেকানিজমের সবচেয়ে বড় দুর্বলতা হলো এর ডাটা ধারণক্ষমতা। একটি স্ট্যান্ডার্ড 1D Barcode সর্বোচ্চ 20 থেকে 25টি Alphanumeric Character স্টোর করতে পারে। আপনি যদি এর চেয়ে বেশি ডাটা যেমন একটি সম্পূর্ণ Web URL বা একটি এনক্রিপ্টেড টোকেন স্টোর করতে চান, তবে বারকোডের দৈর্ঘ্য লিনিয়ারলি বাড়তে থাকবে। ফলস্বরূপ, কোডটি এত দীর্ঘ হয়ে যাবে যে তা কোনো ছোট প্রোডাক্টের গায়ে প্রিন্ট করা ফিজিক্যালি অসম্ভব হয়ে পড়বে।&lt;/p&gt;
&lt;p&gt;2D Matrix Code বা QR Code এই ধারণক্ষমতার সীমাবদ্ধতাকে একটি চমৎকার আর্কিটেকচারাল প্যারাডাইম শিফটের মাধ্যমে সমাধান করেছে। এখানে ডাটা শুধুমাত্র একটি অক্ষে বা Horizontal লাইনে সীমাবদ্ধ না রেখে Horizontal (X-Axis) এবং Vertical (Y-Axis) উভয় ডাইমেনশনে একটি Spatial Matrix বা গ্রিড আকারে এনকোড করা হয়। এর ফলে একই প্রিন্ট এরিয়ার মধ্যে ডাটা ডেনসিটি বা ঘনত্বের পরিমাণ কয়েকশ গুণ বেড়ে যায়। একটি সর্বোচ্চ ভার্সনের কিউআর কোড কোনো ফিজিক্যাল দৈর্ঘ্য না বাড়িয়েই প্রায় 7,089টি নিউমেরিক ক্যারেক্টার অথবা 4,296টি আলফানিউমেরিক ক্যারেক্টার স্টোর করতে সক্ষম হয়। নিচে 1D লিনিয়ার এবং 2D স্পেশাল স্ক্যানিং আর্কিটেকচারের একটি ভিজ্যুয়াল কম্পারিজন দেখানো হলো:&lt;/p&gt;
&lt;figure&gt;&lt;img src=&quot;https://raw.githubusercontent.com/rafeuddaraj/rafes-blog-assets/refs/heads/qr-code-engineering-handbook-optical-physics-production-pipeline/assets/barcode-vs-qrcode-architecture.svg&quot; alt=&quot;1D Linear vs 2D Spatial Scanning Architecture&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;800&quot; height=&quot;450&quot;&gt;&lt;figcaption&gt;1D Linear vs 2D Spatial Scanning Architecture&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;এই মেমরি লেআউট এবং ডাটা ডেনসিটির পার্থক্যটি একদম নতুনদের কাছে স্পষ্ট করার জন্য আমরা একটি অত্যন্ত সহজ এবং বাস্তব জীবনের Analogy বা অ্যানালজি ব্যবহার করতে পারি। এটি আপনার ব্রেইনে কোর কনসেপ্টটি চিরস্থায়ীভাবে গেঁথে দেবে।&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The Chessboard vs Single-Lane Highway Analogy:&lt;/strong&gt; কল্পনা করুন একটি একমুখী সরু রাস্তা বা Single-Lane Highway, যেখানে গাড়িগুলো কেবল পর পর এক লাইনে চলতে পারে। এই রাস্তায় যদি আপনি বেশি গাড়ি বা বেশি ডাটা পাঠাতে চান, তবে ট্রাফিক জ্যাম তৈরি হবে এবং লাইনের দৈর্ঘ্য বহু দূর পর্যন্ত ছড়িয়ে যাবে। এটিই হলো আমাদের চিরাচরিত 1D Barcode। অন্যদিকে, QR Code হলো একটি বিশাল Chessboard বা দাবা বোর্ডের মতো। এখানে প্রতিটি ঘর বা স্কয়ার হলো ডাটা স্টোর করার একটি স্বাধীন ব্লক। আপনি বোর্ডের বাম থেকে ডানে এবং ওপর থেকে নিচে, অর্থাৎ পুরো সারফেস জুড়ে একসাথে শত শত গুটির চাল দিতে পারেন। এই Spatial Distribution-এর কারণে অল্প জায়গায় বিপুল পরিমাণ ডাটা রাখা যায় এবং যেকোনো দিক থেকে তা দ্রুত রিড করা সম্ভব হয়।&lt;/p&gt;
&lt;div class=&quot;callout&quot; role=&quot;note&quot; data-type=&quot;note&quot;&gt;
&lt;p class=&quot;callout-title&quot;&gt;Note&lt;/p&gt;
&lt;p&gt;Masahiro Hara যখন Denso Wave-এর হয়ে এই কোড ডিজাইন করেন, তখন তার মূল লক্ষ্য কেবল ডাটা সাইজ বাড়ানো ছিল না। কারখানায় রোবোটিক আর্মগুলো যাতে চলন্ত কনভেয়ার বেল্ট থেকে যেকোনো কোণে বা 360-degree ওরিয়েন্টেশনে কোডটি মিলি-সেকেন্ডের মধ্যে স্ক্যান করতে পারে, সেটি নিশ্চিত করাই ছিল এই আবিষ্কারের সবচেয়ে বড় ইঞ্জিনিয়ারিং সাফল্য।&lt;/p&gt;
&lt;/div&gt;
&lt;hr&gt;
&lt;h2 id=&quot;step-2-qr-code-matrix-anatomy-and-optical-recognition-physics&quot;&gt;Step 2: QR Code Matrix Anatomy and Optical Recognition Physics&lt;/h2&gt;
&lt;p&gt;একটি কিউআর কোড বাইরে থেকে দেখতে সাদাকালো পিক্সেলের একটি এলোমেলো বাক্স মনে হলেও, এর ভেতরে রয়েছে অত্যন্ত সুশৃঙ্খল এবং নিখুঁত একটি ইঞ্জিনিয়ারিং আর্কিটেকচার। আমরা যখন সিস্টেম আর্কিটেকচারের দৃষ্টিকোণ থেকে এই ম্যাট্রিক্সটি বিশ্লেষণ করি, তখন এর সম্পূর্ণ ফিজিক্যাল বডিকে কয়েকটি সুনির্দিষ্ট Functional Zone বা ব্লকে ভাগ করা যায়। এই জোনগুলোর প্রতিটি স্ক্যানারের ক্যামেরা এবং ডিকোডিং অ্যালগরিদমের কাছে আলাদা আলাদা বার্তা পৌঁছায়।&lt;/p&gt;
&lt;p&gt;নিচে একটি হাই-রেজোলিউশন QR Code Matrix Anatomy এবং এর কোর কম্পোনেন্টগুলোর বিস্তারিত বিন্যাস দেখানো হলো:&lt;/p&gt;
&lt;figure&gt;&lt;img src=&quot;https://raw.githubusercontent.com/rafeuddaraj/rafes-blog-assets/refs/heads/qr-code-engineering-handbook-optical-physics-production-pipeline/assets/qr-code-matrix-anatomy.svg&quot; alt=&quot;QR Code Anatomy and 1:1:3:1:1 Ratio Breakdown&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;800&quot; height=&quot;450&quot;&gt;&lt;figcaption&gt;QR Code Anatomy and 1:1:3:1:1 Ratio Breakdown&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;ম্যাট্রিক্সের কোর কম্পোনেন্টগুলো যেভাবে কাজ করে এবং এদের ইঞ্জিনিয়ারিং গুরুত্ব:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Quiet Zone (নিরাপদ সীমানা):&lt;/strong&gt; কোডের চারপাশে সম্পূর্ণ সাদা রঙের একটি বর্ডার থাকে, যা অন্তত 4টি মডিউল বা পিক্সেলের সমান চওড়া হওয়া বাধ্যতামূলক। এটি স্ক্যানারের সেন্সরকে বাইরের ব্যাকগ্রাউন্ড নয়েজ বা অন্যান্য লেখা থেকে কোডের আসল সীমানা আলাদা করতে সাহায্য করে।&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Position Detection or Finder Patterns (অবস্থান নির্ণায়ক):&lt;/strong&gt; কোডের শীর্ষ বাম, শীর্ষ ডান এবং নিচের বাম কোণায় তিনটি বড় স্কয়ার ব্লক থাকে। আপনি যদি এই ব্লকগুলোর মাঝখান দিয়ে একটি সরলরেখা টানেন, তবে দেখবেন এদের কালো এবং সাদা পিক্সেলের অনুপাত সবসময় ঠিক 1:1:3:1:1 হয়। অর্থাৎ 1 ভাগ কালো, 1 ভাগ সাদা, 3 ভাগ কালো, 1 ভাগ সাদা এবং 1 ভাগ কালো। এই অতি-নির্দিষ্ট অপটিক্যাল সিগনেচার বা Fixed Ratio থাকার কারণে কম আলো, তীব্র গতি বা যেকোনো ব্যাকগ্রাউন্ডের মধ্যেও স্ক্যানার কোডটিকে তাৎক্ষণিক চিনে নিতে পারে।&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Alignment Patterns (সমতলকরণ ব্লক):&lt;/strong&gt; কোডের ভেতরের বিভিন্ন জোনে এই ছোট স্কয়ার ব্লকগুলো অবস্থান করে। কোডের সাইজ বা Version বৃদ্ধির সাথে সাথে এদের সংখ্যা বাড়তে থাকে। কোডটি যখন কোনো বাঁকা বোতল, গোল কৌটা বা অসম সারফেসে প্রিন্ট করা হয়, তখন ক্যামেরার লেন্সে Perspective Distortion তৈরি হয়। এই ব্লকগুলো সেই ডিসটর্শন ক্যালকুলেট করে গ্রিডটিকে জ্যামিতিকভাবে সোজা করে নেয়।&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Timing Patterns (ক্লক পালস জেনারেটর):&lt;/strong&gt; Position Pattern-গুলোর মধ্যবর্তী অনুভূমিক এবং উল্লম্ব লিনিয়ার লাইন, যা সাদা-কালো অল্টারনেট মডিউল দিয়ে তৈরি। এটি স্ক্যানারের জন্য একটি ডিজিটাল ক্লক পালস বা ঘড়ির কাটার মতো কাজ করে। কোডটি কত বড় বা প্রতিটি পিক্সেলের প্রকৃত সাইজ কতটুকু, তা এই লাইনগুলো মেপে বের করে দেয়।&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Format and Version Information Zones:&lt;/strong&gt; Position Pattern-এর ঠিক চারপাশের মডিউল জোন। এখানে কোডের Error Correction Level (L, M, Q, H) এবং কোন Masking Pattern ব্যবহার করা হয়েছে, তার এনক্রিপ্টেড মেটাডেটা স্টোর করা থাকে। স্ক্যানার সবার আগে এই জোনটি রিড করে ডিকোডিং নিয়ম ঠিক করে নেয়।&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Data and Error Correction Payload Area:&lt;/strong&gt; ম্যাট্রিক্সের বাকি সম্পূর্ণ ভেতরের অংশ। এখানে আপনার আসল বাইনারি ডাটা এবং Reed-Solomon এরর কারেকশন বিটগুলো একটি নির্দিষ্ট জিগজ্যাগ প্যাটার্নে সাজানো থাকে।&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;অপটিক্যাল রিকগনিশন মেকানিজমটি সহজে বোঝার জন্য আমরা এখানে একটি আধুনিক জিপিএস প্রযুক্তির Analogy ব্যবহার করতে পারি।&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The GPS Satellite Triangulation Analogy:&lt;/strong&gt; আপনি যখন কোনো অপরিচিত শহরে নিজের স্মার্টফোনে ম্যাপ চালু করেন, তখন আপনার ফোনটি মহাকাশে থাকা অন্তত তিনটি আলাদা জিপিএস স্যাটেলাইটের সাথে যোগাযোগ করে। এই তিনটি স্যাটেলাইট থেকে পাওয়া দূরত্বের তথ্য মিলিয়ে ট্রায়াংগুলেশন পদ্ধতিতে ফোনটি আপনার সঠিক 3D অবস্থান এবং দিক নির্ণয় করে। ঠিক একইভাবে, ক্যামেরার সেন্সর যখন কোনো কিউআর কোড ক্যাপচার করে, তখন ইমেজ প্রসেসিং অ্যালগরিদম সবার আগে কোডের তিন কোণায় থাকা তিনটি Position Detection Pattern খুঁজে বের করে। এই তিনটি বিন্দুর অবস্থান এবং দূরত্ব মেপে অ্যালগরিদমটি বুঝে নেয় কোডটি কত ডিগ্রি কোণে বা উল্টো হয়ে আছে। এরপর সে কোডটিকে ভার্চুয়ালি সোজা করে নিখুঁতভাবে ডাটা রিড করে।&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;step-3-reed-solomon-error-correction-and-galois-field-mathematics&quot;&gt;Step 3: Reed-Solomon Error Correction and Galois Field Mathematics&lt;/h2&gt;
&lt;p&gt;কিউআর কোডের সবচেয়ে শক্তিশালী, নির্ভরযোগ্য এবং একই সাথে সবচেয়ে জটিল ইঞ্জিনিয়ারিং ডোমেন হলো এর Reed-Solomon Error Correction অ্যালগরিদম। বাস্তব জগতের প্রোডাকশন এনভায়রনমেন্টে একটি প্রিন্টেড কোড কখনোই চিরকাল নতুন থাকে না। ওয়্যারহাউসের ধুলোবালি, বৃষ্টির পানি, ঘর্ষণ, তেলের দাগ, কিংবা কোডের মাঝখানে কোম্পানির লোগো বসানোর কারণে অনেক সময় কোডের একটি বড় অংশ ঢেকে যায় বা নষ্ট হয়ে যায়। সাধারণ কোনো বারকোড হলে তা তখনই অকেজো হয়ে যেত, কিন্তু কিউআর কোড তার এই ম্যাথমেটিকাল ফ্রেমওয়ার্কের কারণে সারফেসের 30% পর্যন্ত সম্পূর্ণ মুছে গেলেও মূল ডাটা 100% নির্ভুলভাবে রিকভার করতে পারে।&lt;/p&gt;
&lt;p&gt;এই এরর কারেকশন মেকানিজম মূলত Galois Fields বা Finite Field Arithmetic-এর ওপর ভিত্তি করে কাজ করে। সাধারণ বীজগণিতে আমরা যেমন অসীম সংখ্যার হিসাব করি, সসীম ফিল্ড বা &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:1.0641em;vertical-align:-0.25em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.1389em;&quot;&gt;GF&lt;/span&gt;&lt;span class=&quot;mopen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.8141em;&quot;&gt;&lt;span style=&quot;top:-3.063em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mtight&quot;&gt;8&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mclose&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; সিস্টেমে সংখ্যাগুলো 0 থেকে 255-এর একটি নির্দিষ্ট সীমার মধ্যেই ঘুরে ফিরে আসে। কিউআর কোডে চারটি স্ট্যান্ডার্ড Error Correction Level রয়েছে, যা আপনি আপনার প্রয়োজন অনুযায়ী নির্বাচন করতে পারেন:&lt;/p&gt;
&lt;section class=&quot;table-wrap&quot; tabindex=&quot;0&quot; aria-label=&quot;Table 1&quot;&gt;





























&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Error Correction Level&lt;/th&gt;&lt;th&gt;ডাটা রিকভারি ক্যাপাসিটি&lt;/th&gt;&lt;th&gt;সবচেয়ে উপযুক্ত ব্যবহার ক্ষেত্র (Real-world Use Case)&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Level L (Low)&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;আনুমানিক 7% পর্যন্ত&lt;/td&gt;&lt;td&gt;যখন প্রিন্ট কোয়ালিটি অত্যন্ত পরিষ্কার থাকে এবং আপনার সর্বোচ্চ পরিমাণ ডাটা স্টোর করার প্রয়োজন হয় (যেমন দীর্ঘ ডাটাবেস পে-লোড)।&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Level M (Medium)&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;আনুমানিক 15% পর্যন্ত&lt;/td&gt;&lt;td&gt;এটি ইন্ডাস্ট্রির ডিফল্ট স্ট্যান্ডার্ড। সাধারণ ওয়েবসাইট ইউআরএল, বিজনেস কার্ড এবং মার্কেটিং ম্যাটেরিয়ালে এটি সবচেয়ে বেশি ব্যবহৃত হয়।&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Level Q (Quartile)&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;আনুমানিক 25% পর্যন্ত&lt;/td&gt;&lt;td&gt;কর্পোরেট এনভায়রনমেন্ট, লজিস্টিকস ট্র্যাকিং এবং যেখানে কোডটি কিছুটা রাফ ব্যবহারের শিকার হতে পারে সেখানে এটি উত্তম।&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Level H (High)&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;আনুমানিক 30% পর্যন্ত&lt;/td&gt;&lt;td&gt;যখন আপনি কোডের মাঝখানে কোনো কাস্টম ব্র্যান্ড লোগো বা ছবি এম্বেড করতে চান, অথবা কারখানার মতো প্রতিকূল পরিবেশে কোড ব্যবহার করেন।&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/section&gt;
&lt;p&gt;এরর কারেকশন কোডওয়ার্ড জেনারেট করার জন্য আমরা একটি জেনারেটর পলিনোমিয়াল &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:1em;vertical-align:-0.25em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0359em;&quot;&gt;g&lt;/span&gt;&lt;span class=&quot;mopen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;mclose&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; এবং মেসেজ পলিনোমিয়াল &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:1em;vertical-align:-0.25em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;m&lt;/span&gt;&lt;span class=&quot;mopen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;mclose&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; ব্যবহার করি। Reed-Solomon Codeword জেনারেশনের মূল সমীকরণটি হলো:&lt;/p&gt;
&lt;span class=&quot;katex-display&quot;&gt;&lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:1em;vertical-align:-0.25em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;mopen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;mclose&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mrel&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:1em;vertical-align:-0.25em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;m&lt;/span&gt;&lt;span class=&quot;mopen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;mclose&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mbin&quot;&gt;⋅&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.9747em;vertical-align:-0.0833em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.8913em;&quot;&gt;&lt;span style=&quot;top:-3.113em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mathnormal mtight&quot; style=&quot;margin-right:0.0077em;&quot;&gt;R&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mbin&quot;&gt;−&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:1em;vertical-align:-0.25em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mopen&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;m&lt;/span&gt;&lt;span class=&quot;mopen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;mclose&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mbin&quot;&gt;⋅&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.8913em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.8913em;&quot;&gt;&lt;span style=&quot;top:-3.113em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mathnormal mtight&quot; style=&quot;margin-right:0.0077em;&quot;&gt;R&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mspace allowbreak&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:1em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:1em;vertical-align:-0.25em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mopen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathrm&quot;&gt;mod&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.3333em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0359em;&quot;&gt;g&lt;/span&gt;&lt;span class=&quot;mopen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;mclose&quot;&gt;))]&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;p&gt;এখানে &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.6833em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0077em;&quot;&gt;R&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; হলো Error Correction Bytes-এর সংখ্যা। যখন আপনি কোনো ডাটা এনকোড করেন, তখন এই সমীকরণের মাধ্যমে মূল ডাটার সাথে কিছু অতিরিক্ত Parity Bytes বা নিরাপত্তা বিট যুক্ত করা হয়। স্ক্যানার যখন একটি ক্ষতিগ্রস্ত কোড রিড করে, তখন সে একটি Syndrome Calculator ব্যবহার করে। যদি কোনো পিক্সেল নষ্ট থাকে, তবে সিন্ড্রোমের মান শূন্য হয় না। সেই অশূন্য মান থেকে অ্যালগরিদমটি ঠিক কোন অবস্থানে কতটুকু ভুল হয়েছে (Error Magnitude and Position) তা ক্যালকুলেট করে মূল ডাটা রিভলভ বা পুনরুদ্ধার করে নেয়। নিচে এই এরর কারেকশন এবং ডাটা রিকভারি ফ্লো-টির একটি আর্কিটেকচারাল ডায়াগ্রাম দেওয়া হলো:&lt;/p&gt;
&lt;figure&gt;&lt;img src=&quot;https://raw.githubusercontent.com/rafeuddaraj/rafes-blog-assets/refs/heads/qr-code-engineering-handbook-optical-physics-production-pipeline/assets/reed-solomon-error-correction.svg&quot; alt=&quot;Reed-Solomon Error Correction and Data Recovery Flow&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;800&quot; height=&quot;450&quot;&gt;&lt;figcaption&gt;Reed-Solomon Error Correction and Data Recovery Flow&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;এই জটিল গাণিতিক মেকানিজমটি নবীনদের কাছে সহজ করার জন্য আমরা আমাদের পরিচিত ডাটাবেস বা সার্ভার আর্কিটেকচারের একটি Analogy ব্যবহার করতে পারি।&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The RAID Server Storage Analogy:&lt;/strong&gt; আপনি যদি কোনো বড় এন্টারপ্রাইজ সার্ভার বা ডিস্ট্রিবিউটেড ডাটাবেস পরিচালনা করেন, তবে নিশ্চয়ই জানেন সেখানে আমরা ডাটা হারানোর ঝুঁকি এড়াতে RAID (Redundant Array of Independent Disks) কনফিগারেশন ব্যবহার করি। উদাহরণস্বরূপ, RAID 5 সিস্টেমে আমরা মূল ডাটার সাথে কিছু Parity Bit আলাদা ড্রাইভে সেভ করে রাখি। এর ফলে হঠাৎ কোনো একটি হার্ডডিস্ক সম্পূর্ণ ক্র্যাশ করলেও আমরা বাকি ডিস্ক এবং প্যারিটি বিটের গাণিতিক হিসাব থেকে হারিয়ে যাওয়া ডাটা 100% রিকভার করতে পারি। কিউআর কোডের Reed-Solomon অ্যালগরিদম ঠিক এই কাজটিই করে থাকে। এটি কোডের ভেতরেই একটি মিনি প্যারিটি ব্যাকআপ সিস্টেম তৈরি করে রাখে, যা যেকোনো ফিজিক্যাল ড্যামেজের বিরুদ্ধে একটি শক্তিশালী ঢাল হিসেবে কাজ করে।&lt;/p&gt;
&lt;div class=&quot;callout&quot; role=&quot;note&quot; data-type=&quot;warning&quot;&gt;
&lt;p class=&quot;callout-title&quot;&gt;Level H Memory Overhead Warning&lt;/p&gt;
&lt;p&gt;আপনি যদি কোনো সঠিক কারণ বা লোগো এম্বেড করার প্রয়োজন ছাড়াই সবসময় Level H নির্বাচন করেন, তবে কোডের ডাটা ধারণক্ষমতা ব্যাপকভাবে হ্রাস পাবে। কারণ মেমরির প্রায় এক-তৃতীয়াংশ জায়গা তখন শুধুমাত্র Error Correction Bit স্টোর করার কাজে দখল হয়ে যায়। তাই সাধারণ টেক্সট বা ইউআরএলের জন্য Level M ব্যবহার করাই সবচেয়ে অপ্টিমাল ইঞ্জিনিয়ারিং প্র্যাক্টিস।&lt;/p&gt;
&lt;/div&gt;
&lt;hr&gt;
&lt;h2 id=&quot;step-4-step-by-step-data-encoding-pipeline-and-bit-level-masking&quot;&gt;Step 4: Step-by-Step Data Encoding Pipeline and Bit-Level Masking&lt;/h2&gt;
&lt;p&gt;কিউআর কোড মোট 40টি Version বা সাইজে কাজ করে, যা মূলত এর মেমরি ধারণক্ষমতা এবং ম্যাট্রিক্স গ্রিডের আকার নির্ধারণ করে। Version 1 হলো সবচেয়ে ছোট, যা একটি 21x21 Module Grid দিয়ে তৈরি। এরপর প্রতি Version বৃদ্ধিতে গ্রিডের দৈর্ঘ্য এবং প্রস্থে 4টি করে মডিউল বা পিক্সেল যোগ হয়। এভাবে বাড়তে বাড়তে Version 40 হলো একটি বিশাল 177x177 Module Grid। আপনার ইনপুট ডাটার সাইজ এবং নির্বাচিত Error Correction Level-এর ওপর ভিত্তি করে একটি প্রোডাকশন সিস্টেম স্বয়ংস্ক্রিয়ভাবে সবচেয়ে অপ্টিমাল ভার্সনটি নির্বাচন করে নেয়।&lt;/p&gt;
&lt;p&gt;একটি Raw String যেমন &lt;code&gt;https://blog.rafeuddaraj.me&lt;/code&gt; কীভাবে বাইনারি বিট থেকে রূপান্তরিত হয়ে একটি পূর্ণাঙ্গ ভিজ্যুয়াল কিউআর কোডে রূপ নেয়, তার এন্ড-টু-এন্ড Architectural Process Flow নিচে দেওয়া হলো:&lt;/p&gt;
&lt;figure&gt;&lt;img src=&quot;https://raw.githubusercontent.com/rafeuddaraj/rafes-blog-assets/refs/heads/qr-code-engineering-handbook-optical-physics-production-pipeline/assets/end-to-end-qr-pipeline.svg&quot; alt=&quot;End-to-End QR Code Generation and Decoding Pipeline&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;800&quot; height=&quot;450&quot;&gt;&lt;figcaption&gt;End-to-End QR Code Generation and Decoding Pipeline&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;একটি প্রোডাকশন-গ্রেড এনকোডার ঠিক কীভাবে এই পাইপলাইনের প্রতিটি ধাপ সম্পন্ন করে, তা নিচে বিস্তারিতভাবে ভেঙে দেখানো হলো:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;ধাপ ১ - Mode Selection (মোড নির্বাচন):&lt;/strong&gt; এনকোডার সবার আগে আপনার ইনপুট ডাটার ক্যারেক্টারগুলো বিশ্লেষণ করে। ডাটা সাইজ সবচেয়ে ছোট রাখার জন্য এটি চারটি স্ট্যান্ডার্ড মোডের যেকোনো একটি বেছে নেয়: Numeric (শুধুমাত্র 0-9 সংখ্যা), Alphanumeric (সংখ্যা, বড় হাতের ইংরেজি অক্ষর এবং কিছু বিশেষ চিহ্ন), Byte (যেকোনো 8-bit ডাটা বা UTF-8 ক্যারেক্টার), এবং Kanji (জাপানিজ ক্যারেক্টার)। উদাহরণস্বরূপ, শুধুমাত্র সংখ্যার জন্য বাইট মোড ব্যবহার করলে মেমরির অপচয় হয়, তাই এনকোডার নিউমেরিক মোড বেছে নেয়।&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;ধাপ ২ - Bit Stream Conversion and Padding (বিট রূপান্তর এবং প্যাডিং):&lt;/strong&gt; নির্বাচিত মোড অনুযায়ী প্রতিটি ক্যারেক্টারকে বাইনারি বিট স্ট্রিংয়ে কনভার্ট করা হয়। স্ট্রিংয়ের শুরুতে একটি 4-bit Mode Indicator (যেমন বাইট মোডের জন্য &lt;code&gt;0100&lt;/code&gt;) এবং একটি Character Count Indicator যোগ করা হয়। এরপর যদি বিট স্ট্রিংয়ের দৈর্ঘ্য কোডের ধারণক্ষমতার চেয়ে ছোট হয়, তবে শেষে কিছু শূন্য বিট এবং স্ট্যান্ডার্ড প্যাডিং বাইট (&lt;code&gt;11101100&lt;/code&gt; এবং &lt;code&gt;00010001&lt;/code&gt;, যা ডেসিমাল 236 এবং 17) পর্যায়ক্রমে যোগ করে মেমরি ব্লক পূর্ণ করা হয়।&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;ধাপ ৩ - Reed-Solomon ECC Generation (এরর কোড জেনারেশন):&lt;/strong&gt; তৈরি হওয়া সম্পূর্ণ বিট স্ট্রিংটিকে নির্দিষ্ট সাইজের কয়েকটি ছোট ব্লকে ভাগ করা হয়। প্রতিটি ব্লকের ওপর আমাদের আগের ধাপে আলোচিত Galois Field Math প্রয়োগ করে প্রয়োজনীয় সংখ্যক Error Correction Codewords তৈরি করা হয়। এরপর মূল ডাটা বিট এবং এরর কারেকশন বিটগুলোকে Interleaving বা পর্যায়ক্রমে যুক্ত করে একটি একক লম্বা বাইনারি সিকোয়েন্স তৈরি করা হয়।&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;ধাপ ৪ - Matrix Placement (ম্যাট্রিক্সে বিট স্থাপন):&lt;/strong&gt; এই লম্বা বাইনারি সিকোয়েন্সের প্রতিটি বিটকে (0 হলে সাদা, 1 হলে কালো) 2D ম্যাট্রিক্স গ্রিডে বসানো হয়। এই বসানোর কাজটি শুরু হয় কোডের একদম নিচের ডান কোণা থেকে। এরপর একটি নির্দিষ্ট জিগজ্যাগ প্যাটার্নে দুই কলাম করে ওপরের দিকে এবং পরে নিচের দিকে সাপের মতো এঁকেবেঁকে বিটগুলো বসানো হয়।&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;ধাপ ৫ - Masking Pattern Application (মাস্কিং এবং অপ্টিমাইজেশন):&lt;/strong&gt; বিটগুলো বসানোর পর কোডে অনেক সময় এমন পরিস্থিতি তৈরি হয় যেখানে একসাথে অনেকগুলো সাদা বা কালো পিক্সেল পাশাপাশি জমা হয়ে যায়, অথবা কোডের ভেতর অবস্থান নির্ণায়ক প্যাটার্নের (1:1:3:1:1) মতো বিভ্রান্তিকর ডিজাইন তৈরি হয়। এটি স্ক্যানারকে অন্ধ বা বিভ্রান্ত করতে পারে। এই সমস্যা সমাধানের জন্য কিউআর কোডে 8টি স্ট্যান্ডার্ড Masking Pattern রয়েছে (যেমন প্রতিটি জোড় সারি উল্টে দেওয়া, বা &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.7429em;vertical-align:-0.0833em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mbin&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.854em;vertical-align:-0.1944em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0572em;&quot;&gt;j&lt;/span&gt;&lt;span class=&quot;mspace allowbreak&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.4444em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:1em;vertical-align:-0.25em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mopen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathrm&quot;&gt;mod&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.3333em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;mclose&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mrel&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.6444em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;0&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; সূত্রে পিক্সেল ইনভার্ট করা)। এনকোডার প্রতিটি মাস্ক প্যাটার্ন প্রয়োগ করে দেখে এবং একটি Penalty Scoring সিস্টেমের মাধ্যমে যে প্যাটার্নে সবচেয়ে কম অপটিক্যাল নয়েজ হয়, সেটি চূড়ান্তভাবে নির্বাচন করে।&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;ধাপ ৬ - Final Rendering (চূড়ান্ত রেন্ডারিং):&lt;/strong&gt; চূড়ান্ত মাস্কিং প্রয়োগ করার পর কোডের চারপাশের ফরম্যাট ইনফরমেশন জোনে মাস্ক আইডিটি লিখে দেওয়া হয় এবং চারপাশে 4 মডিউল চওড়া Quiet Zone যোগ করে ফাইনাল ইমেজটি (PNG, SVG বা Buffer) রেন্ডার করা হয়।&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id=&quot;step-5-enterprise-production-architecture-nodejs-backend-and-react-frontend&quot;&gt;Step 5: Enterprise Production Architecture (Node.js Backend and React Frontend)&lt;/h2&gt;
&lt;p&gt;তাত্ত্বিক কনসেপ্ট এবং ম্যাথমেটিক্যাল মেকানিজম বোঝার পর এবার আমরা একটি বাস্তব প্রোডাকশন এনভায়রনমেন্টে প্রবেশ করব। আপনি যখন এমন কোনো এন্টারপ্রাইজ ব্যাকএন্ড আর্কিটেকচার তৈরি করবেন যেখানে প্রতি সেকেন্ডে হাজার হাজার ডায়নামিক কিউআর কোড (যেমন ফিনটেক ওটিপি, ইভেন্ট টিকিট বা পেমেন্ট রিকোয়েস্ট) জেনারেট করতে হয়, তখন সাধারণ ফাইল সিস্টেম অপারেশনের ওপর নির্ভর করা একটি মারাত্বক ইঞ্জিনিয়ারিং ভুল হবে। প্রতিবার কোড জেনারেট করে তা হার্ডডিস্কে রাইট করা এবং পরে রিড করে ক্লায়েন্টকে পাঠানো একটি অত্যন্ত Slow প্রসেস। Disk I/O সবসময় Node.js-এর Main Event Loop-কে ব্লক করে দেয় এবং সার্ভারে High CPU Overhead ও Memory Leak তৈরি করে।&lt;/p&gt;
&lt;p&gt;এই Bottleneck সমাধানের জন্য আমাদের অবশ্যই In-Memory Buffer Stream এবং Asynchronous Operations ব্যবহার করতে হবে। নিচে Node.js, TypeScript এবং জনপ্রিয় &lt;code&gt;qrcode&lt;/code&gt; লাইব্রেরি ব্যবহার করে একটি প্রোডাকশন-রেডি, মেমরি-অপ্টিমাইজড এন্টারপ্রাইজ কিউআর জেনারেশন সার্ভিসের ব্লুপ্রিন্ট দেওয়া হলো:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;style&gt;.expressive-code{font-family:var(--ec-uiFontFml);font-size:var(--ec-uiFontSize);font-weight:var(--ec-uiFontWg);line-height:var(--ec-uiLineHt);text-size-adjust:none;-webkit-text-size-adjust:none}.expressive-code *:not(:is(svg, svg *)){all:revert;box-sizing:border-box}.expressive-code pre{display:flex;margin:0;padding:0;border:var(--ec-brdWd) solid var(--ec-brdCol);border-radius:calc(var(--ec-brdRad) + var(--ec-brdWd));background:var(--ec-codeBg)}.expressive-code pre:focus-visible{outline:3px solid var(--ec-focusBrd);outline-offset:-3px}.expressive-code pre &gt; code{all:unset;display:block;flex:1 0 100%;padding:var(--ec-codePadBlk) 0;color:var(--ec-codeFg);font-family:var(--ec-codeFontFml);font-size:var(--ec-codeFontSize);font-weight:var(--ec-codeFontWg);line-height:var(--ec-codeLineHt)}.expressive-code pre{overflow-x:auto}.expressive-code pre.wrap .ec-line .code{white-space:pre-wrap;overflow-wrap:break-word;min-width:min(20ch, var(--ecMaxLine, 20ch))}.expressive-code pre.wrap .ec-line .code span.indent{white-space:pre}.expressive-code pre::-webkit-scrollbar,.expressive-code pre::-webkit-scrollbar-track{background-color:inherit;border-radius:calc(var(--ec-brdRad) + var(--ec-brdWd));border-top-left-radius:0;border-top-right-radius:0}.expressive-code pre::-webkit-scrollbar-thumb{background-color:var(--ec-sbThumbCol);border:4px solid transparent;background-clip:content-box;border-radius:10px}.expressive-code pre::-webkit-scrollbar-thumb:hover{background-color:var(--ec-sbThumbHoverCol)}.expressive-code pre::-webkit-scrollbar-corner{background:transparent}.expressive-code .ec-line{direction:ltr;unicode-bidi:isolate;display:grid;grid-template-areas:&apos;gutter code&apos;;grid-template-columns:auto 1fr;position:relative}.expressive-code .ec-line .gutter{grid-area:gutter;color:var(--ec-gtrFg)}.expressive-code .ec-line .gutter &gt; *{pointer-events:none;user-select:none;-webkit-user-select:none}.expressive-code .ec-line .gutter ~ .code{--ecLineBrdCol:var(--ec-gtrBrdCol)}.expressive-code .ec-line.highlight .gutter{color:var(--ec-gtrHlFg)}.expressive-code .ec-line .code{grid-area:code;position:relative;box-sizing:content-box;padding-inline-start:calc(var(--ecIndent, 0ch) + var(--ec-codePadInl) - var(--ecGtrBrdWd));padding-inline-end:var(--ec-codePadInl);text-indent:calc(var(--ecIndent, 0ch) * -1)}.expressive-code .ec-line .code::before,.expressive-code .ec-line .code::after,.expressive-code .ec-line .code :where(*){text-indent:0}.expressive-code .ec-line .code{--ecGtrBrdWd:var(--ec-gtrBrdWd);border-inline-start:var(--ecGtrBrdWd) solid var(--ecLineBrdCol, transparent)}.expressive-code .sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0, 0, 0, 0);white-space:nowrap;border-width:0}.expressive-code .ec-line.mark{--tmLineBgCol:var(--ec-tm-markBg)}.expressive-code .ec-line.mark .code{--ecLineBrdCol:var(--ec-tm-markBrdCol)}.expressive-code .ec-line.ins{--tmLineBgCol:var(--ec-tm-insBg);--tmLabel:var(--ec-tm-insDiffIndContent)}.expressive-code .ec-line.ins .code{--ecLineBrdCol:var(--ec-tm-insBrdCol)}.expressive-code .ec-line.ins .code::before{color:var(--ec-tm-insDiffIndCol)}.expressive-code .ec-line.del{--tmLineBgCol:var(--ec-tm-delBg);--tmLabel:var(--ec-tm-delDiffIndContent)}.expressive-code .ec-line.del .code{--ecLineBrdCol:var(--ec-tm-delBrdCol)}.expressive-code .ec-line.del .code::before{color:var(--ec-tm-delDiffIndCol)}.expressive-code .ec-line.mark,.expressive-code .ec-line.ins,.expressive-code .ec-line.del{background:var(--tmLineBgCol)}.expressive-code .ec-line.mark .code,.expressive-code .ec-line.ins .code,.expressive-code .ec-line.del .code{--ecGtrBrdWd:var(--ec-tm-lineMarkerAccentWd)}.expressive-code .ec-line.mark .code::before,.expressive-code .ec-line.ins .code::before,.expressive-code .ec-line.del .code::before{display:block;position:absolute;left:0;box-sizing:border-box;content:var(--tmLabel, &apos; &apos;);padding-inline-start:var(--ec-tm-lineDiffIndMargLeft);text-align:center;white-space:pre}.expressive-code .ec-line.mark.tm-label .code::before,.expressive-code .ec-line.ins.tm-label .code::before,.expressive-code .ec-line.del.tm-label .code::before{background:var(--ecLineBrdCol);padding:0 calc(var(--ec-tm-lineMarkerLabelPadInl) + var(--ec-tm-lineMarkerAccentWd)) 0 var(--ec-tm-lineMarkerLabelPadInl);color:var(--ec-tm-lineMarkerLabelCol)}.expressive-code .ec-line mark{--tmInlineBgCol:var(--ec-tm-markBg);--tmInlineBrdCol:var(--ec-tm-markBrdCol)}.expressive-code .ec-line ins{--tmInlineBgCol:var(--ec-tm-insBg);--tmInlineBrdCol:var(--ec-tm-insBrdCol)}.expressive-code .ec-line del{--tmInlineBgCol:var(--ec-tm-delBg);--tmInlineBrdCol:var(--ec-tm-delBrdCol)}.expressive-code .ec-line mark,.expressive-code .ec-line ins,.expressive-code .ec-line del{all:unset;display:inline-block;position:relative;--tmBrdL:var(--ec-tm-inlMarkerBrdWd);--tmBrdR:var(--ec-tm-inlMarkerBrdWd);--tmRadL:var(--ec-tm-inlMarkerBrdRad);--tmRadR:var(--ec-tm-inlMarkerBrdRad);margin-inline:0.025rem;padding-inline:var(--ec-tm-inlMarkerPad);border-radius:var(--tmRadL) var(--tmRadR) var(--tmRadR) var(--tmRadL);background:var(--tmInlineBgCol);background-clip:padding-box}.expressive-code .ec-line mark.open-start,.expressive-code .ec-line ins.open-start,.expressive-code .ec-line del.open-start{margin-inline-start:0;padding-inline-start:0;--tmBrdL:0px;--tmRadL:0}.expressive-code .ec-line mark.open-end,.expressive-code .ec-line ins.open-end,.expressive-code .ec-line del.open-end{margin-inline-end:0;padding-inline-end:0;--tmBrdR:0px;--tmRadR:0}.expressive-code .ec-line mark::before,.expressive-code .ec-line ins::before,.expressive-code .ec-line del::before{content:&apos;&apos;;position:absolute;pointer-events:none;display:inline-block;inset:0;border-radius:var(--tmRadL) var(--tmRadR) var(--tmRadR) var(--tmRadL);border:var(--ec-tm-inlMarkerBrdWd) solid var(--tmInlineBrdCol);border-inline-width:var(--tmBrdL) var(--tmBrdR)}.expressive-code .frame{all:unset;position:relative;display:block;--header-border-radius:calc(var(--ec-brdRad) + var(--ec-brdWd));--tab-border-radius:calc(var(--ec-frm-edTabBrdRad) + var(--ec-brdWd));--button-spacing:0.4rem;--code-background:var(--ec-frm-edBg);border-radius:var(--header-border-radius);box-shadow:var(--ec-frm-frameBoxShdCssVal)}.expressive-code .frame .header{display:none;z-index:1;position:relative;border-radius:var(--header-border-radius) var(--header-border-radius) 0 0}.expressive-code .frame.has-title pre,.expressive-code .frame.has-title code,.expressive-code .frame.is-terminal pre,.expressive-code .frame.is-terminal code{border-top:none;border-top-left-radius:0;border-top-right-radius:0}.expressive-code .frame .title:empty:before{content:&apos;\a0&apos;}.expressive-code .frame.has-title:not(.is-terminal){--button-spacing:calc(1.9rem + 2 * (var(--ec-uiPadBlk) + var(--ec-frm-edActTabIndHt)))}.expressive-code .frame.has-title:not(.is-terminal) .title{position:relative;color:var(--ec-frm-edActTabFg);background:var(--ec-frm-edActTabBg);background-clip:padding-box;margin-block-start:var(--ec-frm-edTabsMargBlkStart);padding:calc(var(--ec-uiPadBlk) + var(--ec-frm-edActTabIndHt)) var(--ec-uiPadInl);border:var(--ec-brdWd) solid var(--ec-frm-edActTabBrdCol);border-radius:var(--tab-border-radius) var(--tab-border-radius) 0 0;border-bottom:none;overflow:hidden}.expressive-code .frame.has-title:not(.is-terminal) .title::after{content:&apos;&apos;;position:absolute;pointer-events:none;inset:0;border-top:var(--ec-frm-edActTabIndHt) solid var(--ec-frm-edActTabIndTopCol);border-bottom:var(--ec-frm-edActTabIndHt) solid var(--ec-frm-edActTabIndBtmCol)}.expressive-code .frame.has-title:not(.is-terminal) .header{display:flex;background:linear-gradient(to top, var(--ec-frm-edTabBarBrdBtmCol) var(--ec-brdWd), transparent var(--ec-brdWd)),linear-gradient(var(--ec-frm-edTabBarBg), var(--ec-frm-edTabBarBg));background-repeat:no-repeat;padding-inline-start:var(--ec-frm-edTabsMargInlStart)}.expressive-code .frame.has-title:not(.is-terminal) .header::before{content:&apos;&apos;;position:absolute;pointer-events:none;inset:0;border:var(--ec-brdWd) solid var(--ec-frm-edTabBarBrdCol);border-radius:inherit;border-bottom:none}.expressive-code .frame.is-terminal{--button-spacing:calc(1.9rem + var(--ec-brdWd) + 2 * var(--ec-uiPadBlk));--code-background:var(--ec-frm-trmBg)}.expressive-code .frame.is-terminal .header{display:flex;align-items:center;justify-content:center;padding-block:var(--ec-uiPadBlk);padding-block-end:calc(var(--ec-uiPadBlk) + var(--ec-brdWd));position:relative;font-weight:500;letter-spacing:0.025ch;color:var(--ec-frm-trmTtbFg);background:var(--ec-frm-trmTtbBg);border:var(--ec-brdWd) solid var(--ec-brdCol);border-bottom:none}.expressive-code .frame.is-terminal .header::before{content:&apos;&apos;;position:absolute;pointer-events:none;left:var(--ec-uiPadInl);width:2.1rem;height:0.56rem;line-height:0;background-color:var(--ec-frm-trmTtbDotsFg);opacity:var(--ec-frm-trmTtbDotsOpa);-webkit-mask-image:var(--ec-frm-trmIcon);-webkit-mask-repeat:no-repeat;mask-image:var(--ec-frm-trmIcon);mask-repeat:no-repeat}.expressive-code .frame.is-terminal .header::after{content:&apos;&apos;;position:absolute;pointer-events:none;inset:0;border-bottom:var(--ec-brdWd) solid var(--ec-frm-trmTtbBrdBtmCol)}.expressive-code .frame pre{background:var(--code-background)}.expressive-code .copy{display:flex;gap:0.25rem;flex-direction:row;position:absolute;inset-block-start:calc(var(--ec-brdWd) + var(--button-spacing));inset-inline-end:calc(var(--ec-brdWd) + var(--ec-uiPadInl) / 2)}@media (scripting: none){.expressive-code .copy{display:none}}.expressive-code .copy{direction:ltr;unicode-bidi:isolate}.expressive-code .copy button{position:relative;align-self:flex-end;margin:0;padding:0;border:none;border-radius:0.2rem;z-index:1;cursor:pointer;transition-property:opacity, background, border-color;transition-duration:0.2s;transition-timing-function:cubic-bezier(0.25, 0.46, 0.45, 0.94);width:2.5rem;height:2.5rem;background:var(--code-background);opacity:0.75}.expressive-code .copy button div{position:absolute;inset:0;border-radius:inherit;background:var(--ec-frm-inlBtnBg);opacity:var(--ec-frm-inlBtnBgIdleOpa);transition-property:inherit;transition-duration:inherit;transition-timing-function:inherit}.expressive-code .copy button::before{content:&apos;&apos;;position:absolute;pointer-events:none;inset:0;border-radius:inherit;border:var(--ec-brdWd) solid var(--ec-frm-inlBtnBrd);opacity:var(--ec-frm-inlBtnBrdOpa)}.expressive-code .copy button::after{content:&apos;&apos;;position:absolute;pointer-events:none;inset:0;background-color:var(--ec-frm-inlBtnFg);-webkit-mask-image:var(--ec-frm-copyIcon);-webkit-mask-repeat:no-repeat;mask-image:var(--ec-frm-copyIcon);mask-repeat:no-repeat;margin:0.475rem;line-height:0}.expressive-code .copy button:hover,.expressive-code .copy button:focus:focus-visible{opacity:1}.expressive-code .copy button:hover div,.expressive-code .copy button:focus:focus-visible div{opacity:var(--ec-frm-inlBtnBgHoverOrFocusOpa)}.expressive-code .copy button:active{opacity:1}.expressive-code .copy button:active div{opacity:var(--ec-frm-inlBtnBgActOpa)}.expressive-code .copy .feedback{--tooltip-arrow-size:0.35rem;--tooltip-bg:var(--ec-frm-tooltipSuccessBg);color:var(--ec-frm-tooltipSuccessFg);pointer-events:none;user-select:none;-webkit-user-select:none;position:relative;align-self:center;background-color:var(--tooltip-bg);z-index:99;padding:0.125rem 0.75rem;border-radius:0.2rem;margin-inline-end:var(--tooltip-arrow-size);opacity:0;transition-property:opacity, transform;transition-duration:0.2s;transition-timing-function:ease-in-out;transform:translate3d(0, 0.25rem, 0)}.expressive-code .copy .feedback::after{content:&apos;&apos;;position:absolute;pointer-events:none;top:calc(50% - var(--tooltip-arrow-size));inset-inline-end:calc(-2 * (var(--tooltip-arrow-size) - 0.5px));border:var(--tooltip-arrow-size) solid transparent;border-inline-start-color:var(--tooltip-bg)}.expressive-code .copy .feedback.show{opacity:1;transform:translate3d(0, 0, 0)}@media (hover: hover){.expressive-code{}.expressive-code .copy button{opacity:0;width:2rem;height:2rem}.expressive-code .frame:hover .copy button:not(:hover),.expressive-code .frame:focus-within :focus-visible ~ .copy button:not(:hover),.expressive-code .frame .copy .feedback.show ~ button:not(:hover){opacity:0.75}}.expressive-code :nth-child(1 of .ec-line) .code{padding-inline-end:calc(2rem + var(--ec-codePadInl))}:root{--ec-brdRad:0.75rem;--ec-brdWd:1.5px;--ec-brdCol:var(--code-line);--ec-codeFontFml:var(--font-code);--ec-codeFontSize:0.875rem;--ec-codeFontWg:400;--ec-codeLineHt:1.75;--ec-codePadBlk:1rem;--ec-codePadInl:1.125rem;--ec-codeBg:var(--code-bg);--ec-codeFg:#e6edf3;--ec-codeSelBg:#264f78;--ec-gtrFg:#6e7681;--ec-gtrBrdCol:#6e768133;--ec-gtrBrdWd:1.5px;--ec-gtrHlFg:#e6edf3;--ec-uiFontFml:var(--font-mono);--ec-uiFontSize:0.75rem;--ec-uiFontWg:400;--ec-uiLineHt:1.65;--ec-uiPadBlk:0.25rem;--ec-uiPadInl:1rem;--ec-uiSelBg:#6e768166;--ec-uiSelFg:#e6edf3;--ec-focusBrd:#1f6feb;--ec-sbThumbCol:#8b949e33;--ec-sbThumbHoverCol:#8b949e3d;--ec-tm-lineMarkerAccentMarg:0rem;--ec-tm-lineMarkerAccentWd:0.15rem;--ec-tm-lineMarkerLabelPadInl:0.2rem;--ec-tm-lineMarkerLabelCol:white;--ec-tm-lineDiffIndMargLeft:0.3rem;--ec-tm-inlMarkerBrdWd:1.5px;--ec-tm-inlMarkerBrdRad:0.2rem;--ec-tm-inlMarkerPad:0.15rem;--ec-tm-insDiffIndContent:&apos;+&apos;;--ec-tm-delDiffIndContent:&apos;-&apos;;--ec-tm-markBg:#264a8980;--ec-tm-markBrdCol:#5570b3d0;--ec-tm-insBg:#26561c80;--ec-tm-insBrdCol:#4e7e41d0;--ec-tm-insDiffIndCol:#7eb070d0;--ec-tm-delBg:#81322b80;--ec-tm-delBrdCol:#ae594fd0;--ec-tm-delDiffIndCol:#e68a7ed0;--ec-frm-shdCol:#0000005b;--ec-frm-frameBoxShdCssVal:none;--ec-frm-edActTabBg:var(--code-bg);--ec-frm-edActTabFg:var(--code-muted);--ec-frm-edActTabBrdCol:transparent;--ec-frm-edActTabIndHt:1.5px;--ec-frm-edActTabIndTopCol:transparent;--ec-frm-edActTabIndBtmCol:#0d1117;--ec-frm-edTabsMargInlStart:0;--ec-frm-edTabsMargBlkStart:0;--ec-frm-edTabBrdRad:0.75rem;--ec-frm-edTabBarBg:var(--code-bg);--ec-frm-edTabBarBrdCol:var(--code-line);--ec-frm-edTabBarBrdBtmCol:var(--code-line);--ec-frm-edBg:var(--code-bg);--ec-frm-trmTtbFg:var(--code-muted);--ec-frm-trmTtbDotsFg:var(--code-muted);--ec-frm-trmTtbDotsOpa:0.15;--ec-frm-trmTtbBg:var(--code-bg);--ec-frm-trmTtbBrdBtmCol:var(--code-line);--ec-frm-trmBg:var(--code-bg);--ec-frm-inlBtnBg:var(--code-ink);--ec-frm-inlBtnBgIdleOpa:0;--ec-frm-inlBtnBgHoverOrFocusOpa:0.2;--ec-frm-inlBtnBgActOpa:0.3;--ec-frm-inlBtnFg:var(--code-ink);--ec-frm-inlBtnBrd:var(--code-line);--ec-frm-inlBtnBrdOpa:0.4;--ec-frm-tooltipSuccessBg:var(--color-emerald);--ec-frm-tooltipSuccessFg:var(--color-bg);--ec-frm-copyIcon:url(&quot;data:image/svg+xml,%3Csvg%20xmlns%3D&apos;http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg&apos;%20viewBox%3D&apos;0%200%2024%2024&apos;%20fill%3D&apos;none&apos;%20stroke%3D&apos;black&apos;%20stroke-width%3D&apos;1.75&apos;%3E%3Cpath%20d%3D&apos;M3%2019a2%202%200%200%201-1-2V2a2%202%200%200%201%201-1h13a2%202%200%200%201%202%201&apos;%2F%3E%3Crect%20x%3D&apos;6&apos;%20y%3D&apos;5&apos;%20width%3D&apos;16&apos;%20height%3D&apos;18&apos;%20rx%3D&apos;1.5&apos;%20ry%3D&apos;1.5&apos;%2F%3E%3C%2Fsvg%3E&quot;);--ec-frm-trmIcon:url(&quot;data:image/svg+xml,%3Csvg%20xmlns%3D&apos;http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg&apos;%20viewBox%3D&apos;0%200%2060%2016&apos;%20preserveAspectRatio%3D&apos;xMidYMid%20meet&apos;%3E%3Ccircle%20cx%3D&apos;8&apos;%20cy%3D&apos;8&apos;%20r%3D&apos;8&apos;%2F%3E%3Ccircle%20cx%3D&apos;30&apos;%20cy%3D&apos;8&apos;%20r%3D&apos;8&apos;%2F%3E%3Ccircle%20cx%3D&apos;52&apos;%20cy%3D&apos;8&apos;%20r%3D&apos;8&apos;%2F%3E%3C%2Fsvg%3E&quot;)}.expressive-code .ec-line :where(span[style^=&apos;--&apos;]:not([class])){color:var(--0, inherit);background-color:var(--0bg, transparent);font-style:var(--0fs, inherit);font-weight:var(--0fw, inherit);text-decoration:var(--0td, inherit)}&lt;/style&gt;&lt;script type=&quot;module&quot; src=&quot;/_astro/ec.0vx5m.js&quot;&gt;&lt;/script&gt;&lt;figure class=&quot;frame has-title&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;TypeScript&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;typescript&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#8B949E&quot;&gt;// Enterprise-grade High-Performance QR Code Service (Node.js / TypeScript)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; QRCode, { QRCodeToBufferOptions } &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;&apos;qrcode&apos;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; fs &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;&apos;fs/promises&apos;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; path &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;&apos;path&apos;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#8B949E&quot;&gt;/**&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#8B949E&quot;&gt; &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#8B949E&quot;&gt;* Interface representing standard enterprise response payload for QR generation.&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#8B949E&quot;&gt; &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#8B949E&quot;&gt;*/&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;export&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;interface&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FFA657&quot;&gt;QRCodeServiceResponse&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#FFA657&quot;&gt;success&lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;boolean&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#FFA657&quot;&gt;buffer&lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FFA657&quot;&gt;Buffer&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#FFA657&quot;&gt;base64DataUrl&lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;string&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#FFA657&quot;&gt;savedPath&lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;?:&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;string&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#FFA657&quot;&gt;executionTimeMs&lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;number&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#8B949E&quot;&gt;/**&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#8B949E&quot;&gt; &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#8B949E&quot;&gt;* Generates an enterprise-grade, high-contrast QR Code buffer in-memory.&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#8B949E&quot;&gt; &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#8B949E&quot;&gt;* Optimized for high-concurrency microservices without blocking the Event Loop.&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#8B949E&quot;&gt; &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#8B949E&quot;&gt;*&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#8B949E&quot;&gt; &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#8B949E&quot;&gt;* &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;@param&lt;/span&gt;&lt;span style=&quot;--0:#8B949E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;payload&lt;/span&gt;&lt;span style=&quot;--0:#8B949E&quot;&gt; - The raw string, URL, or JSON payload to encode.&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#8B949E&quot;&gt; &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#8B949E&quot;&gt;* &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;@param&lt;/span&gt;&lt;span style=&quot;--0:#8B949E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;saveToDisk&lt;/span&gt;&lt;span style=&quot;--0:#8B949E&quot;&gt; - Optional flag to asynchronously persist the image to storage.&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#8B949E&quot;&gt; &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#8B949E&quot;&gt;* &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;@param&lt;/span&gt;&lt;span style=&quot;--0:#8B949E&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;customPath&lt;/span&gt;&lt;span style=&quot;--0:#8B949E&quot;&gt; - Optional destination file path if saveToDisk is enabled.&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#8B949E&quot;&gt; &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#8B949E&quot;&gt;* &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;@returns&lt;/span&gt;&lt;span style=&quot;--0:#8B949E&quot;&gt; Promise resolving to the complete QR Code service response.&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#8B949E&quot;&gt; &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#8B949E&quot;&gt;*/&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;export&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;async&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;function&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D2A8FF&quot;&gt;generateEnterpriseQRCode&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;(&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#FFA657&quot;&gt;payload&lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;string&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#FFA657&quot;&gt;saveToDisk&lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;boolean&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;false&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#FFA657&quot;&gt;customPath&lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;?:&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;string&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FFA657&quot;&gt;Promise&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;--0:#FFA657&quot;&gt;QRCodeServiceResponse&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;startTime&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; Date.&lt;/span&gt;&lt;span style=&quot;--0:#D2A8FF&quot;&gt;now&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#8B949E&quot;&gt;// Validate payload length to prevent unexpected memory bloat in extreme scenarios&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;if&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;!&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;payload &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;||&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; payload.&lt;/span&gt;&lt;span style=&quot;--0:#D2A8FF&quot;&gt;trim&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;().&lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;length&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;===&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;) {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;throw&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D2A8FF&quot;&gt;Error&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;&apos;[CRITICAL] QR Payload cannot be empty or undefined.&apos;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#8B949E&quot;&gt;// Enterprise configuration strictly enforcing optical contrast and safety boundaries&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;options&lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FFA657&quot;&gt;QRCodeToBufferOptions&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;errorCorrectionLevel: &lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;&apos;H&apos;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#8B949E&quot;&gt;// 30% fault tolerance for harsh production environments&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;type: &lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;&apos;png&apos;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;quality: &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;0.98&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;margin: &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;4&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;,                 &lt;/span&gt;&lt;span style=&quot;--0:#8B949E&quot;&gt;// Strict adherence to the 4-module Quiet Zone standard&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;color: {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;dark: &lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;&apos;#0F172A&apos;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;,         &lt;/span&gt;&lt;span style=&quot;--0:#8B949E&quot;&gt;// High-contrast Deep Slate (Never use absolute #000000 if printing on gloss)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;light: &lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;&apos;#FFFFFF&apos;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;         &lt;/span&gt;&lt;span style=&quot;--0:#8B949E&quot;&gt;// Absolute optical white background for maximum sensor reflection&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;};&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;try&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#8B949E&quot;&gt;// Step 1: Generate High-Speed In-Memory Buffer directly bypassing disk I/O&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;qrBuffer&lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FFA657&quot;&gt;Buffer&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;await&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; QRCode.&lt;/span&gt;&lt;span style=&quot;--0:#D2A8FF&quot;&gt;toBuffer&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;(payload, options);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#8B949E&quot;&gt;// Step 2: Convert buffer to Base64 Data URL for instant React/Frontend rendering&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;base64DataUrl&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;`data:image/png;base64,${&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;qrBuffer&lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#D2A8FF&quot;&gt;toString&lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;&apos;base64&apos;&lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;}`&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;let&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; resolvedPath&lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;string&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;|&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;undefined&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;undefined&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#8B949E&quot;&gt;// Step 3: Asynchronously persist to Disk or Object Storage (S3/GCS) only if explicitly requested&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;if&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; (saveToDisk &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;&amp;#x26;&amp;#x26;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; customPath) {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;resolvedPath &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; path.&lt;/span&gt;&lt;span style=&quot;--0:#D2A8FF&quot;&gt;resolve&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;(customPath);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;--0:#8B949E&quot;&gt;// Non-blocking asynchronous file writing&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;await&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; fs.&lt;/span&gt;&lt;span style=&quot;--0:#D2A8FF&quot;&gt;writeFile&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;(resolvedPath, qrBuffer);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;executionTimeMs&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; Date.&lt;/span&gt;&lt;span style=&quot;--0:#D2A8FF&quot;&gt;now&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;() &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; startTime;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;success: &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;true&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;buffer: qrBuffer,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;base64DataUrl,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;savedPath: resolvedPath,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;executionTimeMs&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;};&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;} &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;catch&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;--0:#FFA657&quot;&gt;error&lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;any&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;) {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;console.&lt;/span&gt;&lt;span style=&quot;--0:#D2A8FF&quot;&gt;error&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;`[FATAL] System Architecture Error in QR Generation Pipeline: ${&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;error&lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;message&lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;}`&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;throw&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D2A8FF&quot;&gt;Error&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;`Enterprise QR Pipeline Failed: ${&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;error&lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;message&lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;}`&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#8B949E&quot;&gt;// ============================================================================&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#8B949E&quot;&gt;// Example Execution inside a Fastify / Express API Controller or Microservice&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#8B949E&quot;&gt;// ============================================================================&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;async&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; () &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;=&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;try&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;samplePayload&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;&apos;https://blog.rafeuddaraj.me/articles/qr-code-engineering-handbook-optical-physics-production-pipeline&apos;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;console.&lt;/span&gt;&lt;span style=&quot;--0:#D2A8FF&quot;&gt;log&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;&apos;[LOG] Initiating In-Memory QR Code Generation...&apos;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;result&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;await&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D2A8FF&quot;&gt;generateEnterpriseQRCode&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;(samplePayload, &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;true&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;&apos;./dist/secure-payload.png&apos;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;console.&lt;/span&gt;&lt;span style=&quot;--0:#D2A8FF&quot;&gt;log&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;`[SUCCESS] QR Code Generated in ${&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;result&lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;executionTimeMs&lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;}ms.`&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;console.&lt;/span&gt;&lt;span style=&quot;--0:#D2A8FF&quot;&gt;log&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;`[LOG] Data URL Preview (First 50 chars): ${&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;result&lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;base64DataUrl&lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#D2A8FF&quot;&gt;substring&lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;50&lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;}...`&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;if&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; (result.savedPath) {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;console.&lt;/span&gt;&lt;span style=&quot;--0:#D2A8FF&quot;&gt;log&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;`[LOG] Asynchronously persisted to local storage at: ${&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;result&lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;savedPath&lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;}`&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;} &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;catch&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;--0:#FFA657&quot;&gt;err&lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;any&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;) {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;console.&lt;/span&gt;&lt;span style=&quot;--0:#D2A8FF&quot;&gt;error&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;&apos;[ERROR] Microservice execution aborted:&apos;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;, err.message);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;})();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;// Enterprise-grade High-Performance QR Code Service (Node.js / TypeScript)import QRCode, { QRCodeToBufferOptions } from &amp;#x27;qrcode&amp;#x27;;import fs from &amp;#x27;fs/promises&amp;#x27;;import path from &amp;#x27;path&amp;#x27;;/** * Interface representing standard enterprise response payload for QR generation. */export interface QRCodeServiceResponse {  success: boolean;  buffer: Buffer;  base64DataUrl: string;  savedPath?: string;  executionTimeMs: number;}/** * Generates an enterprise-grade, high-contrast QR Code buffer in-memory. * Optimized for high-concurrency microservices without blocking the Event Loop. * * @param payload - The raw string, URL, or JSON payload to encode. * @param saveToDisk - Optional flag to asynchronously persist the image to storage. * @param customPath - Optional destination file path if saveToDisk is enabled. * @returns Promise resolving to the complete QR Code service response. */export async function generateEnterpriseQRCode(  payload: string,  saveToDisk: boolean = false,  customPath?: string): Promise&lt;QRCodeServiceResponse&gt; {  const startTime = Date.now();  // Validate payload length to prevent unexpected memory bloat in extreme scenarios  if (!payload || payload.trim().length === 0) {    throw new Error(&amp;#x27;[CRITICAL] QR Payload cannot be empty or undefined.&amp;#x27;);  }  // Enterprise configuration strictly enforcing optical contrast and safety boundaries  const options: QRCodeToBufferOptions = {    errorCorrectionLevel: &amp;#x27;H&amp;#x27;, // 30% fault tolerance for harsh production environments    type: &amp;#x27;png&amp;#x27;,    quality: 0.98,    margin: 4,                 // Strict adherence to the 4-module Quiet Zone standard    color: {      dark: &amp;#x27;#0F172A&amp;#x27;,         // High-contrast Deep Slate (Never use absolute #000000 if printing on gloss)      light: &amp;#x27;#FFFFFF&amp;#x27;         // Absolute optical white background for maximum sensor reflection    }  };  try {    // Step 1: Generate High-Speed In-Memory Buffer directly bypassing disk I/O    const qrBuffer: Buffer = await QRCode.toBuffer(payload, options);    // Step 2: Convert buffer to Base64 Data URL for instant React/Frontend rendering    const base64DataUrl = &amp;#x60;data:image/png;base64,${qrBuffer.toString(&amp;#x27;base64&amp;#x27;)}&amp;#x60;;    let resolvedPath: string | undefined = undefined;    // Step 3: Asynchronously persist to Disk or Object Storage (S3/GCS) only if explicitly requested    if (saveToDisk &amp;#x26;&amp;#x26; customPath) {      resolvedPath = path.resolve(customPath);      // Non-blocking asynchronous file writing      await fs.writeFile(resolvedPath, qrBuffer);    }    const executionTimeMs = Date.now() - startTime;    return {      success: true,      buffer: qrBuffer,      base64DataUrl,      savedPath: resolvedPath,      executionTimeMs    };  } catch (error: any) {    console.error(&amp;#x60;[FATAL] System Architecture Error in QR Generation Pipeline: ${error.message}&amp;#x60;);    throw new Error(&amp;#x60;Enterprise QR Pipeline Failed: ${error.message}&amp;#x60;);  }}// ============================================================================// Example Execution inside a Fastify / Express API Controller or Microservice// ============================================================================(async () =&gt; {  try {    const samplePayload = &amp;#x27;https://blog.rafeuddaraj.me/articles/qr-code-engineering-handbook-optical-physics-production-pipeline&amp;#x27;;    console.log(&amp;#x27;[LOG] Initiating In-Memory QR Code Generation...&amp;#x27;);    const result = await generateEnterpriseQRCode(samplePayload, true, &amp;#x27;./dist/secure-payload.png&amp;#x27;);    console.log(&amp;#x60;[SUCCESS] QR Code Generated in ${result.executionTimeMs}ms.&amp;#x60;);    console.log(&amp;#x60;[LOG] Data URL Preview (First 50 chars): ${result.base64DataUrl.substring(0, 50)}...&amp;#x60;);    if (result.savedPath) {      console.log(&amp;#x60;[LOG] Asynchronously persisted to local storage at: ${result.savedPath}&amp;#x60;);    }  } catch (err: any) {    console.error(&amp;#x27;[ERROR] Microservice execution aborted:&amp;#x27;, err.message);  }})();&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;ব্যাকএন্ডে আমরা যেমন মেমরি এবং সিপিইউ অপ্টিমাইজ করলাম, ফ্রন্টএন্ড বা ক্লায়েন্ট সাইডে (যেমন React বা Next.js ওয়েব অ্যাপ্লিকেশনে) লাইভ ক্যামেরা থেকে কিউআর কোড স্ক্যান করার সময় আমাদের আরও বড় একটি ইঞ্জিনিয়ারিং চ্যালেঞ্জের মুখোমুখি হতে হয়। একটি মডার্ন স্মার্টফোন ক্যামেরা প্রতি সেকেন্ডে 60টি হাই-রেজোলিউশন ফ্রেম (60 FPS Video Stream) ব্রাউজারে পাঠায়। আপনি যদি সাধারণ জাভাস্ক্রিপ্ট দিয়ে ব্রাউজারের Main UI Thread-এ এই প্রতিটি ফ্রেম রিড করে Binarization এবং ডিকোড করতে যান, তবে আপনার অ্যাপ্লিকেশন মারাত্বক Slow হয়ে যাবে, ফ্রেম ড্রপ করবে এবং মোবাইল ফোন গরম হয়ে ব্যাটারি দ্রুত শেষ হবে।&lt;/p&gt;
&lt;p&gt;এই সমস্যা সমাধানের জন্য আমাদের ক্লায়েন্ট-সাইড আর্কিটেকচার হতে হবে Non-blocking এবং Asynchronous। আমাদের অবশ্যই Web Worker এবং WebAssembly (WASM) ব্যবহার করতে হবে। নিচে React এবং TypeScript ব্যবহার করে একটি অপ্টিমাইজড, প্রোডাকশন-রেডি Custom Hook এবং Component আর্কিটেকচার দেখানো হলো, যা Main UI Thread ব্লক না করেই লাইভ ভিডিও স্ট্রিম প্রসেস করতে পারে:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame has-title&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;TSX&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;tsx&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#8B949E&quot;&gt;// Production-grade React Custom Hook &amp;#x26; Component for Non-Blocking QR Scanning&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; React, { useEffect, useRef, useState, useCallback } &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;&apos;react&apos;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#8B949E&quot;&gt;/**&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#8B949E&quot;&gt; &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#8B949E&quot;&gt;* Interface for the Decoded QR Result payload.&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#8B949E&quot;&gt; &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#8B949E&quot;&gt;*/&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;export&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;interface&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FFA657&quot;&gt;DecodedQRResult&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#FFA657&quot;&gt;text&lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;string&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#FFA657&quot;&gt;timestamp&lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;number&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#8B949E&quot;&gt;/**&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#8B949E&quot;&gt; &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#8B949E&quot;&gt;* A specialized custom hook to manage live camera streaming and background Canvas frame extraction.&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#8B949E&quot;&gt; &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#8B949E&quot;&gt;*/&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;export&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;function&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D2A8FF&quot;&gt;useOptimizedQRScanner&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#D2A8FF&quot;&gt;onDecode&lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;--0:#FFA657&quot;&gt;result&lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FFA657&quot;&gt;DecodedQRResult&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;=&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;void&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;) {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;videoRef&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D2A8FF&quot;&gt;useRef&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;--0:#FFA657&quot;&gt;HTMLVideoElement&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;|&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;null&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;null&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;canvasRef&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D2A8FF&quot;&gt;useRef&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;--0:#FFA657&quot;&gt;HTMLCanvasElement&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;|&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;null&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;null&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; [&lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;isScanning&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;setIsScanning&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;] &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D2A8FF&quot;&gt;useState&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;boolean&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;false&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; [&lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;error&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;setError&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;] &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D2A8FF&quot;&gt;useState&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;string&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;|&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;null&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;null&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;animationFrameId&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D2A8FF&quot;&gt;useRef&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;number&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;|&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;null&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;null&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#8B949E&quot;&gt;// Stop camera stream safely to prevent memory leaks and hardware locks&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;stopCamera&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D2A8FF&quot;&gt;useCallback&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;(() &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;=&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;if&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; (videoRef.current &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;&amp;#x26;&amp;#x26;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; videoRef.current.srcObject) {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;stream&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; videoRef.current.srcObject &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;as&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FFA657&quot;&gt;MediaStream&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;stream.&lt;/span&gt;&lt;span style=&quot;--0:#D2A8FF&quot;&gt;getTracks&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;().&lt;/span&gt;&lt;span style=&quot;--0:#D2A8FF&quot;&gt;forEach&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;((&lt;/span&gt;&lt;span style=&quot;--0:#FFA657&quot;&gt;track&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;=&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; track.&lt;/span&gt;&lt;span style=&quot;--0:#D2A8FF&quot;&gt;stop&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;());&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;videoRef.current.srcObject &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;null&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;if&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; (animationFrameId.current) {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;--0:#D2A8FF&quot;&gt;cancelAnimationFrame&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;(animationFrameId.current);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#D2A8FF&quot;&gt;setIsScanning&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;false&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;}, []);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#8B949E&quot;&gt;// Frame extraction loop running at controlled intervals to save battery&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;scanFrame&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D2A8FF&quot;&gt;useCallback&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;(() &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;=&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;if&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;!&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;videoRef.current &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;||&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;!&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;canvasRef.current &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;||&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;!&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;isScanning) &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;video&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; videoRef.current;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;canvas&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; canvasRef.current;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;context&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; canvas.&lt;/span&gt;&lt;span style=&quot;--0:#D2A8FF&quot;&gt;getContext&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;&apos;2d&apos;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;, { willReadFrequently: &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;true&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; });&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;if&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; (video.readyState &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;===&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; video.&lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;HAVE_ENOUGH_DATA&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;&amp;#x26;&amp;#x26;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; context) {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;canvas.width &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; video.videoWidth;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;canvas.height &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; video.videoHeight;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;--0:#8B949E&quot;&gt;// Draw video frame to off-screen canvas&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;context.&lt;/span&gt;&lt;span style=&quot;--0:#D2A8FF&quot;&gt;drawImage&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;(video, &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;, canvas.width, canvas.height);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;try&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#8B949E&quot;&gt;// Extract ImageData for background processing&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;imageData&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; context.&lt;/span&gt;&lt;span style=&quot;--0:#D2A8FF&quot;&gt;getImageData&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;, canvas.width, canvas.height);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#8B949E&quot;&gt;// In a true enterprise setup, send `imageData.data.buffer` to a Web Worker / WebAssembly decoder&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#8B949E&quot;&gt;// Example simulation of detection logic:&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;if&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; (imageData.width &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;) {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;          &lt;/span&gt;&lt;span style=&quot;--0:#8B949E&quot;&gt;// Simulated non-blocking detection check&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;          &lt;/span&gt;&lt;span style=&quot;--0:#8B949E&quot;&gt;// When WASM worker returns success, trigger callback:&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;          &lt;/span&gt;&lt;span style=&quot;--0:#8B949E&quot;&gt;// onDecode({ text: &quot;https://blog.rafeuddaraj.me&quot;, timestamp: Date.now() });&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;} &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;catch&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;--0:#FFA657&quot;&gt;err&lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;any&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;) {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;console.&lt;/span&gt;&lt;span style=&quot;--0:#D2A8FF&quot;&gt;warn&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;&apos;[WARN] Frame extraction temporarily failed:&apos;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;, err.message);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#8B949E&quot;&gt;// Schedule next frame check using requestAnimationFrame instead of setInterval&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;animationFrameId.current &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D2A8FF&quot;&gt;requestAnimationFrame&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;(scanFrame);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;}, [isScanning, onDecode]);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#8B949E&quot;&gt;// Initialize Hardware Camera Access&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;startCamera&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D2A8FF&quot;&gt;useCallback&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;async&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; () &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;=&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;try&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;--0:#D2A8FF&quot;&gt;setError&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;null&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;stream&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;await&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; navigator.mediaDevices.&lt;/span&gt;&lt;span style=&quot;--0:#D2A8FF&quot;&gt;getUserMedia&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;({&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;video: {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;          &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;facingMode: &lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;&apos;environment&apos;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#8B949E&quot;&gt;// Request back camera for physical scanning&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;          &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;width: { ideal: &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;1280&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; },&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;          &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;height: { ideal: &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;720&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; }&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;});&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;if&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; (videoRef.current) {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;videoRef.current.srcObject &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; stream;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;videoRef.current.&lt;/span&gt;&lt;span style=&quot;--0:#D2A8FF&quot;&gt;setAttribute&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;&apos;playsinline&apos;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;&apos;true&apos;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;); &lt;/span&gt;&lt;span style=&quot;--0:#8B949E&quot;&gt;// Required for iOS Safari&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;await&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; videoRef.current.&lt;/span&gt;&lt;span style=&quot;--0:#D2A8FF&quot;&gt;play&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#D2A8FF&quot;&gt;setIsScanning&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;true&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;} &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;catch&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;--0:#FFA657&quot;&gt;err&lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;any&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;) {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;--0:#D2A8FF&quot;&gt;setError&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;`Camera access denied or unavailable: ${&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;err&lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;message&lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;}`&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;--0:#D2A8FF&quot;&gt;setIsScanning&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;false&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;}, []);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#D2A8FF&quot;&gt;useEffect&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;(() &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;=&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;if&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; (isScanning) {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;animationFrameId.current &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D2A8FF&quot;&gt;requestAnimationFrame&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;(scanFrame);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; () &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;=&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D2A8FF&quot;&gt;stopCamera&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;}, [isScanning, scanFrame, stopCamera]);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; { videoRef, canvasRef, isScanning, startCamera, stopCamera, error };&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#8B949E&quot;&gt;// ============================================================================&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#8B949E&quot;&gt;// Functional UI Component implementation&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#8B949E&quot;&gt;// ============================================================================&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;export&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D2A8FF&quot;&gt;EnterpriseQRScannerUI&lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FFA657&quot;&gt;React&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#FFA657&quot;&gt;FC&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; () &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;=&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; [&lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;lastScanned&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;setLastScanned&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;] &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D2A8FF&quot;&gt;useState&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;string&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;&apos;No data detected yet.&apos;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;handleDecode&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D2A8FF&quot;&gt;useCallback&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;((&lt;/span&gt;&lt;span style=&quot;--0:#FFA657&quot;&gt;result&lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FFA657&quot;&gt;DecodedQRResult&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;=&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#D2A8FF&quot;&gt;setLastScanned&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;`${&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;result&lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;text&lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;} (Time: ${&lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D2A8FF&quot;&gt;Date&lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;result&lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;timestamp&lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;).&lt;/span&gt;&lt;span style=&quot;--0:#D2A8FF&quot;&gt;toLocaleTimeString&lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;})`&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;}, []);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; { &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;videoRef&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;canvasRef&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;isScanning&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;startCamera&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;stopCamera&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;error&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; } &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D2A8FF&quot;&gt;useOptimizedQRScanner&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;(handleDecode);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; (&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;--0:#7EE787&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;style&lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;={&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;{ padding: &lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;&apos;20px&apos;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;, backgroundColor: &lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;&apos;#0F172A&apos;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;, color: &lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;&apos;#FFFFFF&apos;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;, borderRadius: &lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;&apos;8px&apos;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;, maxWidth: &lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;&apos;600px&apos;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;, margin: &lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;&apos;0 auto&apos;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; }&lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;--0:#7EE787&quot;&gt;h3&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;style&lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;={&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;{ color: &lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;&apos;#FFC83B&apos;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;, borderBottom: &lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;&apos;1px solid #334155&apos;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;, paddingBottom: &lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;&apos;10px&apos;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; }&lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;Enterprise Live Optical Scanner&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;--0:#7EE787&quot;&gt;h3&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;error &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;&amp;#x26;&amp;#x26;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; (&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;--0:#7EE787&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;style&lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;={&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;{ backgroundColor: &lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;&apos;#EF4444&apos;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;, padding: &lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;&apos;10px&apos;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;, borderRadius: &lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;&apos;4px&apos;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;, margin: &lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;&apos;10px 0&apos;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; }&lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;          &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;[ERROR]: &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;error&lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;--0:#7EE787&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;--0:#7EE787&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;style&lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;={&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;{ position: &lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;&apos;relative&apos;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;, width: &lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;&apos;100%&apos;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;, height: &lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;&apos;350px&apos;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;, backgroundColor: &lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;&apos;#000000&apos;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;, borderRadius: &lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;&apos;6px&apos;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;, overflow: &lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;&apos;hidden&apos;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;, border: &lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;&apos;2px solid #334155&apos;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; }&lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;--0:#7EE787&quot;&gt;video&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;ref&lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;={&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;videoRef&lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;style&lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;={&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;{ width: &lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;&apos;100%&apos;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;, height: &lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;&apos;100%&apos;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;, objectFit: &lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;&apos;cover&apos;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; }&lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; /&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;--0:#8B949E&quot;&gt;/* Hidden Canvas used exclusively for fast background pixel manipulation */&lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;--0:#7EE787&quot;&gt;canvas&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;ref&lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;={&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;canvasRef&lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;style&lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;={&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;{ display: &lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;&apos;none&apos;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; }&lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; /&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;{!&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;isScanning &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;&amp;#x26;&amp;#x26;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; (&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;          &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;--0:#7EE787&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;style&lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;={&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;{ position: &lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;&apos;absolute&apos;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;, top: &lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;&apos;50%&apos;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;, left: &lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;&apos;50%&apos;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;, transform: &lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;&apos;translate(-50%, -50%)&apos;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;, color: &lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;&apos;#94A3B8&apos;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; }&lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;Camera Stream Inactive&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;          &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;--0:#7EE787&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;--0:#7EE787&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;--0:#7EE787&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;style&lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;={&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;{ marginTop: &lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;&apos;15px&apos;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;, display: &lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;&apos;flex&apos;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;, gap: &lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;&apos;10px&apos;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;, justifyContent: &lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;&apos;space-between&apos;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;, alignItems: &lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;&apos;center&apos;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; }&lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;--0:#7EE787&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;          &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;--0:#7EE787&quot;&gt;button&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;            &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;onClick&lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;={&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;isScanning &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;?&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; stopCamera &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; startCamera&lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;            &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;style&lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;={&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;              &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;padding: &lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;&apos;10px 20px&apos;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;              &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;backgroundColor: isScanning &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;?&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;&apos;#EF4444&apos;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;&apos;#10B981&apos;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;              &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;color: &lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;&apos;#FFFFFF&apos;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;              &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;border: &lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;&apos;none&apos;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;              &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;borderRadius: &lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;&apos;4px&apos;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;              &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;fontWeight: &lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;&apos;bold&apos;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;              &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;cursor: &lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;&apos;pointer&apos;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;          &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;            &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;isScanning &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;?&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;&apos;Terminate Scanner&apos;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;&apos;Initialize Hardware Scanner&apos;&lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;          &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;--0:#7EE787&quot;&gt;button&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;--0:#7EE787&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;--0:#7EE787&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;style&lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;={&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;{ fontSize: &lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;&apos;13px&apos;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;, color: &lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;&apos;#00E5FF&apos;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; }&lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;          &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;Status: &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;isScanning &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;?&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;&apos;ACTIVE (60 FPS Stream)&apos;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;&apos;STANDBY&apos;&lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;--0:#7EE787&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;--0:#7EE787&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;--0:#7EE787&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;style&lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;={&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;{ marginTop: &lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;&apos;15px&apos;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;, padding: &lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;&apos;10px&apos;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;, backgroundColor: &lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;&apos;#1E293B&apos;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;, borderRadius: &lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;&apos;4px&apos;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;, fontSize: &lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;&apos;14px&apos;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;, wordBreak: &lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;&apos;break-all&apos;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; }&lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;--0:#7EE787&quot;&gt;strong&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;style&lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;={&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;{ color: &lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;&apos;#FFC83B&apos;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; }&lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;&gt;Latest Payload: &amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;--0:#7EE787&quot;&gt;strong&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;lastScanned&lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;--0:#7EE787&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;--0:#7EE787&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;};&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;// Production-grade React Custom Hook &amp;#x26; Component for Non-Blocking QR Scanningimport React, { useEffect, useRef, useState, useCallback } from &amp;#x27;react&amp;#x27;;/** * Interface for the Decoded QR Result payload. */export interface DecodedQRResult {  text: string;  timestamp: number;}/** * A specialized custom hook to manage live camera streaming and background Canvas frame extraction. */export function useOptimizedQRScanner(onDecode: (result: DecodedQRResult) =&gt; void) {  const videoRef = useRef&lt;HTMLVideoElement | null&gt;(null);  const canvasRef = useRef&lt;HTMLCanvasElement | null&gt;(null);  const [isScanning, setIsScanning] = useState&lt;boolean&gt;(false);  const [error, setError] = useState&lt;string | null&gt;(null);  const animationFrameId = useRef&lt;number | null&gt;(null);  // Stop camera stream safely to prevent memory leaks and hardware locks  const stopCamera = useCallback(() =&gt; {    if (videoRef.current &amp;#x26;&amp;#x26; videoRef.current.srcObject) {      const stream = videoRef.current.srcObject as MediaStream;      stream.getTracks().forEach((track) =&gt; track.stop());      videoRef.current.srcObject = null;    }    if (animationFrameId.current) {      cancelAnimationFrame(animationFrameId.current);    }    setIsScanning(false);  }, []);  // Frame extraction loop running at controlled intervals to save battery  const scanFrame = useCallback(() =&gt; {    if (!videoRef.current || !canvasRef.current || !isScanning) return;    const video = videoRef.current;    const canvas = canvasRef.current;    const context = canvas.getContext(&amp;#x27;2d&amp;#x27;, { willReadFrequently: true });    if (video.readyState === video.HAVE_ENOUGH_DATA &amp;#x26;&amp;#x26; context) {      canvas.width = video.videoWidth;      canvas.height = video.videoHeight;      // Draw video frame to off-screen canvas      context.drawImage(video, 0, 0, canvas.width, canvas.height);      try {        // Extract ImageData for background processing        const imageData = context.getImageData(0, 0, canvas.width, canvas.height);        // In a true enterprise setup, send &amp;#x60;imageData.data.buffer&amp;#x60; to a Web Worker / WebAssembly decoder        // Example simulation of detection logic:        if (imageData.width &gt; 0) {          // Simulated non-blocking detection check          // When WASM worker returns success, trigger callback:          // onDecode({ text: &amp;#x22;https://blog.rafeuddaraj.me&amp;#x22;, timestamp: Date.now() });        }      } catch (err: any) {        console.warn(&amp;#x27;[WARN] Frame extraction temporarily failed:&amp;#x27;, err.message);      }    }    // Schedule next frame check using requestAnimationFrame instead of setInterval    animationFrameId.current = requestAnimationFrame(scanFrame);  }, [isScanning, onDecode]);  // Initialize Hardware Camera Access  const startCamera = useCallback(async () =&gt; {    try {      setError(null);      const stream = await navigator.mediaDevices.getUserMedia({        video: {          facingMode: &amp;#x27;environment&amp;#x27;, // Request back camera for physical scanning          width: { ideal: 1280 },          height: { ideal: 720 }        }      });      if (videoRef.current) {        videoRef.current.srcObject = stream;        videoRef.current.setAttribute(&amp;#x27;playsinline&amp;#x27;, &amp;#x27;true&amp;#x27;); // Required for iOS Safari        await videoRef.current.play();        setIsScanning(true);      }    } catch (err: any) {      setError(&amp;#x60;Camera access denied or unavailable: ${err.message}&amp;#x60;);      setIsScanning(false);    }  }, []);  useEffect(() =&gt; {    if (isScanning) {      animationFrameId.current = requestAnimationFrame(scanFrame);    }    return () =&gt; stopCamera();  }, [isScanning, scanFrame, stopCamera]);  return { videoRef, canvasRef, isScanning, startCamera, stopCamera, error };}// ============================================================================// Functional UI Component implementation// ============================================================================export const EnterpriseQRScannerUI: React.FC = () =&gt; {  const [lastScanned, setLastScanned] = useState&lt;string&gt;(&amp;#x27;No data detected yet.&amp;#x27;);  const handleDecode = useCallback((result: DecodedQRResult) =&gt; {    setLastScanned(&amp;#x60;${result.text} (Time: ${new Date(result.timestamp).toLocaleTimeString()})&amp;#x60;);  }, []);  const { videoRef, canvasRef, isScanning, startCamera, stopCamera, error } = useOptimizedQRScanner(handleDecode);  return (    &lt;div style={{ padding: &amp;#x27;20px&amp;#x27;, backgroundColor: &amp;#x27;#0F172A&amp;#x27;, color: &amp;#x27;#FFFFFF&amp;#x27;, borderRadius: &amp;#x27;8px&amp;#x27;, maxWidth: &amp;#x27;600px&amp;#x27;, margin: &amp;#x27;0 auto&amp;#x27; }}&gt;      &lt;h3 style={{ color: &amp;#x27;#FFC83B&amp;#x27;, borderBottom: &amp;#x27;1px solid #334155&amp;#x27;, paddingBottom: &amp;#x27;10px&amp;#x27; }}&gt;        Enterprise Live Optical Scanner      &lt;/h3&gt;      {error &amp;#x26;&amp;#x26; (        &lt;div style={{ backgroundColor: &amp;#x27;#EF4444&amp;#x27;, padding: &amp;#x27;10px&amp;#x27;, borderRadius: &amp;#x27;4px&amp;#x27;, margin: &amp;#x27;10px 0&amp;#x27; }}&gt;          [ERROR]: {error}        &lt;/div&gt;      )}      &lt;div style={{ position: &amp;#x27;relative&amp;#x27;, width: &amp;#x27;100%&amp;#x27;, height: &amp;#x27;350px&amp;#x27;, backgroundColor: &amp;#x27;#000000&amp;#x27;, borderRadius: &amp;#x27;6px&amp;#x27;, overflow: &amp;#x27;hidden&amp;#x27;, border: &amp;#x27;2px solid #334155&amp;#x27; }}&gt;        &lt;video ref={videoRef} style={{ width: &amp;#x27;100%&amp;#x27;, height: &amp;#x27;100%&amp;#x27;, objectFit: &amp;#x27;cover&amp;#x27; }} /&gt;        {/* Hidden Canvas used exclusively for fast background pixel manipulation */}        &lt;canvas ref={canvasRef} style={{ display: &amp;#x27;none&amp;#x27; }} /&gt;        {!isScanning &amp;#x26;&amp;#x26; (          &lt;div style={{ position: &amp;#x27;absolute&amp;#x27;, top: &amp;#x27;50%&amp;#x27;, left: &amp;#x27;50%&amp;#x27;, transform: &amp;#x27;translate(-50%, -50%)&amp;#x27;, color: &amp;#x27;#94A3B8&amp;#x27; }}&gt;            Camera Stream Inactive          &lt;/div&gt;        )}      &lt;/div&gt;      &lt;div style={{ marginTop: &amp;#x27;15px&amp;#x27;, display: &amp;#x27;flex&amp;#x27;, gap: &amp;#x27;10px&amp;#x27;, justifyContent: &amp;#x27;space-between&amp;#x27;, alignItems: &amp;#x27;center&amp;#x27; }}&gt;        &lt;div&gt;          &lt;button            onClick={isScanning ? stopCamera : startCamera}            style={{              padding: &amp;#x27;10px 20px&amp;#x27;,              backgroundColor: isScanning ? &amp;#x27;#EF4444&amp;#x27; : &amp;#x27;#10B981&amp;#x27;,              color: &amp;#x27;#FFFFFF&amp;#x27;,              border: &amp;#x27;none&amp;#x27;,              borderRadius: &amp;#x27;4px&amp;#x27;,              fontWeight: &amp;#x27;bold&amp;#x27;,              cursor: &amp;#x27;pointer&amp;#x27;            }}          &gt;            {isScanning ? &amp;#x27;Terminate Scanner&amp;#x27; : &amp;#x27;Initialize Hardware Scanner&amp;#x27;}          &lt;/button&gt;        &lt;/div&gt;        &lt;div style={{ fontSize: &amp;#x27;13px&amp;#x27;, color: &amp;#x27;#00E5FF&amp;#x27; }}&gt;          Status: {isScanning ? &amp;#x27;ACTIVE (60 FPS Stream)&amp;#x27; : &amp;#x27;STANDBY&amp;#x27;}        &lt;/div&gt;      &lt;/div&gt;      &lt;div style={{ marginTop: &amp;#x27;15px&amp;#x27;, padding: &amp;#x27;10px&amp;#x27;, backgroundColor: &amp;#x27;#1E293B&amp;#x27;, borderRadius: &amp;#x27;4px&amp;#x27;, fontSize: &amp;#x27;14px&amp;#x27;, wordBreak: &amp;#x27;break-all&amp;#x27; }}&gt;        &lt;strong style={{ color: &amp;#x27;#FFC83B&amp;#x27; }}&gt;Latest Payload: &lt;/strong&gt; {lastScanned}      &lt;/div&gt;    &lt;/div&gt;  );};&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;div class=&quot;callout&quot; role=&quot;note&quot; data-type=&quot;tip&quot;&gt;
&lt;p class=&quot;callout-title&quot;&gt;Memory Leak and Worker Thread Optimization&lt;/p&gt;
&lt;p&gt;আপনি যখন ক্লায়েন্ট সাইডে লাইভ ক্যামেরা স্ক্যানার ইমপ্লিমেন্ট করবেন, তখন কম্পোনেন্ট Unmount হওয়ার সাথে সাথে অবশ্যই Video Stream Track এবং Web Worker সম্পূর্ণ টার্মিনেট করুন। অন্যথায় এটি মারাত্বক Memory Leak তৈরি করবে, ব্যাকগ্রাউন্ডে ক্যামেরা অন রেখে দেবে এবং ইউজারের ডিভাইসের ব্যাটারি ও মেমরি দ্রুত ড্রেইন করবে।&lt;/p&gt;
&lt;/div&gt;
&lt;hr&gt;
&lt;h2 id=&quot;step-6-production-deployment-checklist-and-security-best-practices&quot;&gt;Step 6: Production Deployment Checklist and Security Best Practices&lt;/h2&gt;
&lt;p&gt;আপনি যখন আপনার পরবর্তী প্রজেক্ট, স্টার্টআপ বা এন্টারপ্রাইজ প্রোডাকশন সিস্টেমে কিউআর কোড আর্কিটেকচার ইমপ্লিমেন্ট করবেন, তখন নিচের চেকলিস্ট এবং আর্কিটেকচারাল বেস্ট প্র্যাক্টিসগুলো কঠোরভাবে মেনে চলবেন। এটি আপনার সিস্টেমের স্ক্যানিং স্পিড, রিলায়েবিলিটি এবং সিকিউরিটি সর্বোচ্চ স্তরে নিয়ে যাবে।&lt;/p&gt;
&lt;section class=&quot;table-wrap&quot; tabindex=&quot;0&quot; aria-label=&quot;Table 2&quot;&gt;







































&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;আর্কিটেকচারাল ডোমেন&lt;/th&gt;&lt;th&gt;প্রোডাকশন বেস্ট প্র্যাক্টিস এবং নিয়মাবলী&lt;/th&gt;&lt;th&gt;সম্ভাব্য ঝুঁকি এবং সমাধান (Risk &amp;#x26; Mitigation)&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;১. Error Correction Level&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;সাধারণ টেক্সট বা ছোট ইউআরএলের জন্য সবসময় &lt;code&gt;Level M&lt;/code&gt; (15%) ব্যবহার করুন। কোডের মাঝখানে ব্র্যান্ড লোগো বসাতে চাইলে বা কারখানার মতো রাফ পরিবেশে অবশ্যই &lt;code&gt;Level H&lt;/code&gt; (30%) সিলেক্ট করুন।&lt;/td&gt;&lt;td&gt;অপ্রয়োজনে &lt;code&gt;Level H&lt;/code&gt; ব্যবহার করলে মেমরি ওভারহেড বাড়ে এবং কোডের সাইজ বড় হয়ে স্ক্যানিং ল্যাটেন্সি তৈরি করে।&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;২. Payload &amp;#x26; Version Scaling&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;কোডের ভেতর সরাসরি সম্পূর্ণ JSON অবজেক্ট বা দীর্ঘ ডাটা এম্বেড করবেন না। এর বদলে একটি Short URL বা Unique Identifier (UUID/NanoID) এম্বেড করুন।&lt;/td&gt;&lt;td&gt;বেশি ডাটা দিলে কোড Version 30 বা তার ওপরে চলে যায়। পিক্সেলগুলো এত ছোট হয়ে যায় যে সস্তা বা কম মেগাপিক্সেলের ক্যামেরা তা রিড করতে পারে না।&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;৩. Optical Contrast Ratio&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;ব্যাকগ্রাউন্ড সবসময় উজ্জ্বল হালকা রঙের (যেমন সাদা) এবং মডিউলগুলো গাঢ় রঙের (যেমন কালো বা ডিপ স্লেট) হতে হবে। ইনভার্টেড কালার (কালোর ওপর সাদা কোড) ব্যবহার থেকে বিরত থাকুন।&lt;/td&gt;&lt;td&gt;অনেক পুরনো বা সস্তা বারকোড স্ক্যানার ইনভার্টেড কালার বা লো-কন্ট্রাস্ট কোড রিড করার অপটিক্যাল সেন্সর রাখে না।&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;৪. Quiet Zone Integrity&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;কোডের চারপাশে অন্তত 4টি মডিউলের সমান সম্পূর্ণ ফাঁকা বা সাদা জায়গা (Quiet Zone) রাখা বাধ্যতামূলক। এই সীমানার ওপর কোনো টেক্সট বা বর্ডার লাইন ড্র করবেন না।&lt;/td&gt;&lt;td&gt;Quiet Zone না থাকলে স্ক্যানার কোডের সীমানা ডিটেক্ট করতে পারে না এবং অপটিক্যাল রিকগনিশন সম্পূর্ণ ফেইল করে।&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;৫. Static vs Dynamic Routing&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;ফিনটেক, পেমেন্ট গেটওয়ে বা লজিস্টিকসের জন্য সবসময় Dynamic QR Code ব্যবহার করুন। এখানে কোডে একটি রিডাইরেক্ট ইউআরএল থাকে, যার ব্যাকএন্ড ডাটা আপনি যেকোনো সময় পরিবর্তন করতে পারেন।&lt;/td&gt;&lt;td&gt;Static Code একবার প্রিন্ট করার পর তার পেছনের ইউআরএল বা ডাটা পরিবর্তন করা যায় না। লিঙ্কে ভুল হলে লাখ লাখ প্রিন্ট মেটেরিয়াল ফেলে দিতে হয়।&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;৬. Security &amp;#x26; Threat Defense&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;কিউআর কোড স্ক্যান করে পাওয়া ইউআরএল বা ডাটা সরাসরি ডম (DOM) বা ডাটাবেসে ইনজেক্ট করবেন না। স্ক্যান করা পে-লোডকে সবসময় Input Sanitization এবং Phishing Detection ফিল্টারের ভেতর দিয়ে প্রসেস করুন।&lt;/td&gt;&lt;td&gt;হ্যাকাররা কোডের ভেতর Malicious Script (XSS) বা ফিশিং সাইটের লিঙ্ক এম্বেড করে QRLjacking বা সেশন হাইজ্যাক করার চেষ্টা করতে পারে।&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/section&gt;
&lt;p&gt;একজন সফটওয়্যার আর্কিটেক্ট হিসেবে কিউআর কোডের এই গভীর মেকানিজম এবং অপ্টিমাইজেশন টেকনিকগুলো জানা থাকলে আপনি যেকোনো হাই-স্কেল সিস্টেমে নির্ভুল এবং দ্রুতগতির অপটিক্যাল ডেটা পাইপলাইন তৈরি করতে পারবেন। এই হ্যান্ডবুকটি আপনার পরবর্তী ইঞ্জিনিয়ারিং প্রজেক্টের একটি নির্ভরযোগ্য রেফারেন্স হিসেবে কাজ করবে।&lt;/p&gt;</content:encoded><category>System Design</category><category>QR Code</category><category>System Architecture</category><category>Node.js</category><category>React</category><category>TypeScript</category><category>WebAssembly</category><category>Optical Scanning</category><category>Software Engineering</category><category>Algorithms</category><category>Backend Development</category></item><item><title>Distributed Systems-এ Transactional Outbox Pattern এবং Idempotency আসলে Under-the-Hood কীভাবে কাজ করে?</title><link>https://www.rafeuddaraj.me/bn/blog/distributed-systems-transactional-outbox-idempotency-deep-dive/</link><guid isPermaLink="true">https://www.rafeuddaraj.me/bn/blog/distributed-systems-transactional-outbox-idempotency-deep-dive/</guid><description>Monolith থেকে Microservices-এ শিফট করার পর Distributed Transactions এবং Data Consistency হ্যান্ডেল করার প্রোডাকশন-রেডি গাইড। জানুন Dual-Write Anti-Pattern, CDC, WAL এবং Idempotency-র low-level mechanics।</description><pubDate>Thu, 16 Jul 2026 21:26:02 GMT</pubDate><content:encoded>&lt;p&gt;মনোলিথিক আর্কিটেকচার থেকে মাইক্রোসার্ভিসে শিফট করার পর আমরা যে সবচেয়ে বড় এবং ভয়ঙ্কর সমস্যার মুখোমুখি হই, তা হলো Distributed Transactions এবং Data Consistency হ্যান্ডেল করা। মনোলিথিক অ্যাপ্লিকেশনে একটি সিঙ্গেল রিলেশনাল ডেটাবেজ থাকে, যেখানে আমরা খুব সহজেই ACID ট্রানজেকশন ব্যবহার করে ডেটার পারমাণবিকতা নিশ্চিত করতে পারি। কিন্তু যখন আমরা মাইক্রোসার্ভিস আর্কিটেকচারে চলে আসি, তখন প্রতিটি সার্ভিসের নিজস্ব ডেটাবেজ থাকে এবং সার্ভিসগুলো পরস্পরের সাথে যোগাযোগ করার জন্য নেটওয়ার্ক বা মেসেজ ব্রোকারের উপর নির্ভর করে। এই জায়গায় তৈরি হয় একটি জটিল আর্কিটেকচারাল মিস্ট্রি যা সঠিক সিস্টেমে সমাধান না করলে আপনার প্রোডাকশন ডেটাবেজ সাইলেন্টলি করাপ্টেড হয়ে যেতে পারে।&lt;/p&gt;
&lt;p&gt;আজকের এই Deep Dive সেশনে আমরা সরাসরি কথা বলব কেন সাধারণ রিট্রাই মেকানিজম বা ট্রাই-ক্যাচ ব্লক লার্জ-স্কেল ডিস্ট্রিবিউটেড সিস্টেমে ফেইল করে, এবং কীভাবে Transactional Outbox Pattern ও Idempotent Consumer মেকানিজম ব্যবহার করে আমরা একটি প্রোডাকশন-গ্রেড, ফল্ট-টল্যারেন্ট সিস্টেম ডিজাইন করতে পারি। আসুন, একদম Under-the-hood লেভেল থেকে বিষয়টি বিশ্লেষণ করা যাক।&lt;/p&gt;
&lt;h2 id=&quot;১-the-core-mystery-এবং-why-it-matters&quot;&gt;১. The Core Mystery এবং Why It Matters&lt;/h2&gt;
&lt;p&gt;যখন কোনো একটি সার্ভিস তার লোকাল ডেটাবেজ আপডেট করার পাশাপাশি একটি এক্সটার্নাল মেসেজ ব্রোকারে (যেমন: Apache Kafka বা RabbitMQ) ইভেন্ট পাবলিশ করে, তখন সেই প্যাটার্নটিকে আমরা বলি Dual-Write। আপাতদৃষ্টিতে এটি খুব সাধারণ এবং সহজ একটি লজিক মনে হতে পারে, কিন্তু সিস্টেম আর্কিটেকচারের দৃষ্টিকোণ থেকে এটি একটি মারাত্মক Anti-Pattern। আপনি যখন একই কোড ব্লকের ভেতরে দুটি সম্পূর্ণ ভিন্ন এবং স্বাধীন স্টোরেজ ইঞ্জিনে রাইট অপারেশন চালাতে যান, তখন নেটওয়ার্ক ল্যাটেন্সি এবং আংশিক ফেইলরের কারণে সিস্টেমটি খুব দ্রুত একটি ইনকন্সিস্টেন্ট স্টেটে চলে যায়।&lt;/p&gt;
&lt;p&gt;ধরুন, আপনি একটি ই-কমার্স প্ল্যাটফর্মের Order Service তৈরি করছেন। যখন কোনো ইউজার একটি অর্ডার প্লেস করে, তখন আপনার কোড প্রথমে ডেটাবেজে অর্ডারের তথ্য সেভ করে এবং তারপর কাফকা ব্রোকারে একটি &lt;code&gt;OrderCreated&lt;/code&gt; ইভেন্ট পাঠায় যাতে Inventory Service স্টক কমাতে পারে এবং Payment Service পেমেন্ট প্রসেস করতে পারে। এখন চিন্তা করুন, আপনার ডেটাবেজ ট্রানজেকশন সাকসেসফুল হলো এবং অর্ডার টেবিলে ডেটা সেভ হয়ে গেল, কিন্তু ঠিক সেই মুহূর্তে কাফকা ব্রোকার ডাউন হয়ে গেল অথবা আপনার নেটওয়ার্ক কানেকশন ড্রপ করল। ফলে কাফকাতে ইভেন্টটি পাবলিশ হলো না। এখন আপনার Order Service মনে করছে অর্ডার সফল, কিন্তু Inventory এবং Payment Service এই অর্ডারের ব্যাপারে কিছুই জানে না। এই অবস্থাকেই বলা হয় সাইলেন্ট ডেটা করাপশন, যা বিজনেস লজিককে পুরোপুরি ধ্বংস করে দেয়।&lt;/p&gt;
&lt;p&gt;অনেক সিনিয়র ইঞ্জিনিয়ার এই সমস্যার সমাধানে সাধারণ ট্রাই-ক্যাচ ব্লক বা রিট্রাই মেকানিজমের উপর নির্ভর করেন। তারা মনে করেন, কাফকাতে ইভেন্ট পাঠানো ফেইল করলে কোড কয়েকবার রিট্রাই করবে অথবা এক্সেপশন থ্রো করে ডেটাবেজ ট্রানজেকশন রোলব্যাক করে দেবে। কিন্তু ডিস্ট্রিবিউটেড সিস্টেমে এই ধারণাটি সম্পূর্ণ ভুল। যদি আপনার মেসেজটি কাফকা ব্রোকারে ঠিকই পৌঁছায়, কিন্তু ব্রোকার থেকে আপনার অ্যাপ্লিকেশনে একনলেজমেন্ট আসার পথে নেটওয়ার্ক পার্টিশন হয়, তখন আপনার অ্যাপ্লিকেশন মনে করবে মেসেজটি যায়নি। ফলে আপনি যদি রিট্রাই করেন, তবে কাফকাতে একই মেসেজ দুইবার চলে যাবে। আবার যদি আপনি ডেটাবেজ রোলব্যাক করে দেন, তাহলে কাফকাতে মেসেজ থেকে যাবে অথচ ডেটাবেজে কোনো রেকর্ড থাকবে না। এই লজিক্যাল ডেথ ট্র্যাপ থেকে বের হওয়ার একমাত্র উপায় হলো ডেটাবেজের পারমাণবিক ক্ষমতা ব্যবহার করা।&lt;/p&gt;
&lt;h2 id=&quot;২-the-foundational-mental-model-এবং-analogy&quot;&gt;২. The Foundational Mental Model এবং Analogy&lt;/h2&gt;
&lt;p&gt;Transactional Outbox Pattern-এর মূল কনসেপ্ট খুবই সহজ এবং চমৎকার। আমরা রিয়েল-টাইমে এক্সটার্নাল মেসেজ ব্রোকারে ডেটা পাঠানোর চেষ্টা পুরোপুরি বাদ দেব। এর পরিবর্তে, আমরা আমাদের লোকাল ডেটাবেজের পারমাণবিক ক্ষমতা বা ACID প্রোপার্টি ব্যবহার করব। যখন কোনো বিজনেস ট্রানজেকশন ঘটবে, তখন আমরা মূল বিজনেস টেবিলের সাথে একই ট্রানজেকশনের ভেতরে আরেকটি বিশেষ টেবিলে ইভেন্টের তথ্য সেভ করে রাখব। এই বিশেষ টেবিলটিকে বলা হয় &lt;code&gt;outbox_messages&lt;/code&gt; টেবিল। যেহেতু দুটি টেবিলই একই ডেটাবেজের ভেতরে আছে এবং একই ট্রানজেকশনের অংশ, তাই ডেটাবেজ ইঞ্জিন গ্যারান্টি দেবে যে হয় দুটি টেবিলেই ডেটা সেভ হবে, অথবা কোনোটিতেই হবে না।&lt;/p&gt;
&lt;p&gt;বিষয়টি পরিষ্কার করার জন্য আমরা একটি রিয়েল-ওয়ার্ল্ড অ্যানালজি বিবেচনা করতে পারি। ধরুন, আপনি একটি ব্যাংকের কাউন্টারে দাঁড়িয়ে আছেন এবং অন্য একটি ব্যাংকের অ্যাকাউন্টে টাকা পাঠাতে চান। ক্যাশিয়ার যদি সরাসরি আপনার সামনে দাঁড়িয়ে অন্য ব্যাংকের সার্ভারে রিয়েল-টাইমে কানেক্ট করার চেষ্টা করেন, এবং সেই মুহূর্তে তাদের নেটওয়ার্ক স্লো থাকে, তবে আপনার লেনদেন আটকে যাবে অথবা ভুল হবে। এর বদলে ক্যাশিয়ার যা করেন তা হলো: তিনি প্রথমে আপনার অ্যাকাউন্ট থেকে টাকা কাটার এন্ট্রি তার লোকাল লেজারে লিখে রাখেন, এবং ঠিক সেই লেজারেরই একটি আউটবক্স সেকশনে লিখে রাখেন যে অন্য ব্যাংকে একটি চেক পাঠাতে হবে। এই পুরো কাজটি তিনি এক কলমের খোঁচায় সম্পন্ন করেন। পরবর্তীতে ব্যাংকের ব্যাকগ্রাউন্ড স্টাফরা সেই আউটবক্স সেকশন থেকে চেকগুলো সংগ্রহ করে নিরাপদ সময়ে অন্য ব্যাংকে পাঠিয়ে দেয়।&lt;/p&gt;
&lt;p&gt;ডিস্ট্রিবিউটেড সিস্টেমে এই মানসিক মডেলটিকে আমরা বলি Eventual Consistency। আমরা স্ট্রং কন্সিস্টেন্সি বা রিয়েল-টাইম সিঙ্ক্রোনাইজেশনের আশা ছেড়ে দিয়ে সিস্টেমকে এমনভাবে ডিজাইন করি যেন কিছু মিলিসেকেন্ড বা সেকেন্ডের মধ্যে পুরো সিস্টেমের ডেটা নিজেদের মধ্যে সিঙ্ক হয়ে যায়। হাই-স্কেল এবং হাই-থ্রুপুট সিস্টেমে রিয়েল-টাইম লকিং ব্যবহার করা অসম্ভব, তাই Eventual Consistency-ই প্রোডাকশন আর্কিটেকচারের একমাত্র বাস্তবসম্মত সমাধান।&lt;/p&gt;
&lt;h2 id=&quot;৩-under-the-hood-architecture-the-core-deep-dive&quot;&gt;৩. Under-The-Hood Architecture (The Core Deep Dive)&lt;/h2&gt;
&lt;p&gt;এখন আমরা দেখব এই পুরো প্রক্রিয়াটি Under-the-hood বা ইঞ্জিনের একদম মেমোরি ও ডিস্ক লেভেলে কীভাবে কাজ করে। আপনি যখন রিলেশনাল ডেটাবেজে (যেমন: PostgreSQL বা MySQL) একটি ট্রানজেকশন শুরু করেন, তখন ডেটাবেজ ইঞ্জিন সরাসরি আপনার মেইন ডেটা ফাইলে হাত দেয় না। এর পরিবর্তে সে Write-Ahead Log (WAL) নামক একটি অপ্টিমাইজড, সিকোয়েনশিয়াল ডিস্ক ফাইলে আপনার পরিবর্তনের নির্দেশগুলো রেকর্ড করে। আপনি যখন একই ট্রানজেকশনের ভেতরে &lt;code&gt;orders&lt;/code&gt; টেবিল এবং &lt;code&gt;outbox_messages&lt;/code&gt; টেবিলে ডেটা ইনসার্ট করেন, তখন ডেটাবেজ ইঞ্জিন সেই দুটি রাইট অপারেশনকে একই WAL এন্ট্রির অংশ হিসেবে মেমোরি বাফারে এবং পরবর্তীতে ডিস্কে ফ্লাশ করে।&lt;/p&gt;
&lt;p&gt;যখন আপনি &lt;code&gt;COMMIT&lt;/code&gt; কমান্ড দেন, তখন ডেটাবেজ ইঞ্জিন নিশ্চিত করে যে WAL ফাইলে দুটি টেবিলের পরিবর্তনই পারমাণবিক বা Atomic ভাবে লেখা হয়েছে। যদি ডিস্ক রাইট হওয়ার সময় কারেন্ট চলে যায় বা সার্ভার ক্র্যাশ করে, তবে ডেটাবেজ রিস্টার্ট হওয়ার সময় WAL ফাইল রিড করে পুরো ট্রানজেকশনটি রোলব্যাক করে দেবে। ফলে আপনার বিজনেস ডেটা এবং আউটবক্স ইভেন্টের মধ্যে ১oo% সিঙ্ক বজায় থাকে। এখানে কোনো এক্সটার্নাল নেটওয়ার্ক কলের ঝুঁকি নেই, কারণ পুরো প্রসেসটি ডেটাবেজের ইন্টারনাল স্টোরেজ ইঞ্জিনের ভেতরেই ঘটছে।&lt;/p&gt;
&lt;p&gt;আউটবক্স প্যাটার্ন আমাদের ডেটাবেজ লেভেলে কন্সিস্টেন্সি দিলেও, মেসেজ ব্রোকার থেকে কনজিউমার সার্ভিসে ডেটা যাওয়ার সময় আমাদের Message Delivery Guarantees নিয়ে খুব সতর্ক থাকতে হয়। ডিস্ট্রিবিউটেড সিস্টেমে তিন ধরনের ডেলিভারি গ্যারান্টি দেখা যায়: At-most-once, At-least-once, এবং Exactly-once। আউটবক্স প্যাটার্ন ডিফল্টভাবে আমাদের At-least-once ডেলিভারি গ্যারান্টি প্রদান করে। এর মানে হলো, আপনার ইভেন্টটি কমপক্ষে একবার কনজিউমার সার্ভিসের কাছে পৌঁছাবেই, কিন্তু নেটওয়ার্ক রিট্রাই বা ফেইলর রিকভারির কারণে একই ইভেন্ট একাধিকবারও পৌঁছাতে পারে।&lt;/p&gt;
&lt;p&gt;অনেকেই মনে করেন কাফকা বা আধুনিক ব্রোকারগুলো Exactly-once ডেলিভারি দিতে পারে, কিন্তু ডিস্ট্রিবিউটেড সিস্টেমের লো-লেভেল রিয়েলিটিতে End-to-End Exactly-once ডেলিভারি থিওরিটিক্যালি এবং প্র্যাকটিক্যালি অসম্ভব। ব্রোকার হয়তো তার নিজের লেয়ারে ডুপ্লিকেট আটকাতে পারে, কিন্তু নেটওয়ার্ক ল্যাটেন্সির কারণে আপনার ব্যাকগ্রাউন্ড পোলার বা কনজিউমার সার্ভিস একই মেসেজ দুইবার প্রসেস করতেই পারে। তাই প্র্যাকটিক্যাল প্রোডাকশন আর্কিটেকচারে আমরা সবসময় At-least-once ডেলিভারি গ্যারান্টির সাথে কনজিউমার এন্ডে Idempotency লজিক যুক্ত করে Exactly-once প্রসেসিং নিশ্চিত করি।&lt;/p&gt;
&lt;p&gt;উপরে দেখানো আর্কিটেকচারাল ডায়াগ্রামটিতে আপনি দেখতে পাচ্ছেন কীভাবে আমাদের মূল অ্যাপ্লিকেশন একটি একক ট্রানজেকশনের মাধ্যমে ডেটাবেজের বিজনেস টেবিল এবং আউটবক্স টেবিল আপডেট করছে। পরবর্তীতে একটি ব্যাকগ্রাউন্ড প্রসেস বা Change Data Capture (CDC) ইঞ্জিন সেই আউটবক্স টেবিল থেকে ডেটা রিড করে মেসেজ ব্রোকারে পাঠাচ্ছে, যা শেষ পর্যন্ত কনজিউমার সার্ভিস রিসিভ করে ইডেমপোটেন্সি চেক করার মাধ্যমে প্রসেস করছে।&lt;/p&gt;
&lt;h2 id=&quot;৪-step-by-step-execution-trace-এবং-code-mechanics&quot;&gt;৪. Step-by-Step Execution Trace এবং Code Mechanics&lt;/h2&gt;
&lt;p&gt;একটি প্রোডাকশন-রেডি আর্কিটেকচার ডিজাইন করার জন্য আমাদের প্রথমে ডেটাবেজ স্কিমা এবং ব্যাকএন্ড কোডের মেকানিজম বুঝতে হবে। আসুন আমরা ধাপে ধাপে পুরো এক্সিকিউশন ট্রেসটি দেখে নিই।&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;ধাপ ১: SQL Schema Design-এর ব্লুপ্রিন্ট&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;আমাদের ডেটাবেজে আউটবক্স মেসেজগুলো স্টোর করার জন্য একটি সুনির্দিষ্ট স্কিমা প্রয়োজন। এই টেবিলে ইভেন্টের পেলোড, স্ট্যাটাস এবং রিট্রাই ট্র্যাকিংয়ের ব্যবস্থা থাকতে হবে। একই সাথে কনজিউমার সার্ভিসের ডেটাবেজে ডুপ্লিকেট মেসেজ রোখার জন্য একটি ইডেমপোটেন্সি টেবিল তৈরি করতে হবে।&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;style&gt;.expressive-code{font-family:var(--ec-uiFontFml);font-size:var(--ec-uiFontSize);font-weight:var(--ec-uiFontWg);line-height:var(--ec-uiLineHt);text-size-adjust:none;-webkit-text-size-adjust:none}.expressive-code *:not(:is(svg, svg *)){all:revert;box-sizing:border-box}.expressive-code pre{display:flex;margin:0;padding:0;border:var(--ec-brdWd) solid var(--ec-brdCol);border-radius:calc(var(--ec-brdRad) + var(--ec-brdWd));background:var(--ec-codeBg)}.expressive-code pre:focus-visible{outline:3px solid var(--ec-focusBrd);outline-offset:-3px}.expressive-code pre &gt; code{all:unset;display:block;flex:1 0 100%;padding:var(--ec-codePadBlk) 0;color:var(--ec-codeFg);font-family:var(--ec-codeFontFml);font-size:var(--ec-codeFontSize);font-weight:var(--ec-codeFontWg);line-height:var(--ec-codeLineHt)}.expressive-code pre{overflow-x:auto}.expressive-code pre.wrap .ec-line .code{white-space:pre-wrap;overflow-wrap:break-word;min-width:min(20ch, var(--ecMaxLine, 20ch))}.expressive-code pre.wrap .ec-line .code span.indent{white-space:pre}.expressive-code pre::-webkit-scrollbar,.expressive-code pre::-webkit-scrollbar-track{background-color:inherit;border-radius:calc(var(--ec-brdRad) + var(--ec-brdWd));border-top-left-radius:0;border-top-right-radius:0}.expressive-code pre::-webkit-scrollbar-thumb{background-color:var(--ec-sbThumbCol);border:4px solid transparent;background-clip:content-box;border-radius:10px}.expressive-code pre::-webkit-scrollbar-thumb:hover{background-color:var(--ec-sbThumbHoverCol)}.expressive-code pre::-webkit-scrollbar-corner{background:transparent}.expressive-code .ec-line{direction:ltr;unicode-bidi:isolate;display:grid;grid-template-areas:&apos;gutter code&apos;;grid-template-columns:auto 1fr;position:relative}.expressive-code .ec-line .gutter{grid-area:gutter;color:var(--ec-gtrFg)}.expressive-code .ec-line .gutter &gt; *{pointer-events:none;user-select:none;-webkit-user-select:none}.expressive-code .ec-line .gutter ~ .code{--ecLineBrdCol:var(--ec-gtrBrdCol)}.expressive-code .ec-line.highlight .gutter{color:var(--ec-gtrHlFg)}.expressive-code .ec-line .code{grid-area:code;position:relative;box-sizing:content-box;padding-inline-start:calc(var(--ecIndent, 0ch) + var(--ec-codePadInl) - var(--ecGtrBrdWd));padding-inline-end:var(--ec-codePadInl);text-indent:calc(var(--ecIndent, 0ch) * -1)}.expressive-code .ec-line .code::before,.expressive-code .ec-line .code::after,.expressive-code .ec-line .code :where(*){text-indent:0}.expressive-code .ec-line .code{--ecGtrBrdWd:var(--ec-gtrBrdWd);border-inline-start:var(--ecGtrBrdWd) solid var(--ecLineBrdCol, transparent)}.expressive-code .sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0, 0, 0, 0);white-space:nowrap;border-width:0}.expressive-code .ec-line.mark{--tmLineBgCol:var(--ec-tm-markBg)}.expressive-code .ec-line.mark .code{--ecLineBrdCol:var(--ec-tm-markBrdCol)}.expressive-code .ec-line.ins{--tmLineBgCol:var(--ec-tm-insBg);--tmLabel:var(--ec-tm-insDiffIndContent)}.expressive-code .ec-line.ins .code{--ecLineBrdCol:var(--ec-tm-insBrdCol)}.expressive-code .ec-line.ins .code::before{color:var(--ec-tm-insDiffIndCol)}.expressive-code .ec-line.del{--tmLineBgCol:var(--ec-tm-delBg);--tmLabel:var(--ec-tm-delDiffIndContent)}.expressive-code .ec-line.del .code{--ecLineBrdCol:var(--ec-tm-delBrdCol)}.expressive-code .ec-line.del .code::before{color:var(--ec-tm-delDiffIndCol)}.expressive-code .ec-line.mark,.expressive-code .ec-line.ins,.expressive-code .ec-line.del{background:var(--tmLineBgCol)}.expressive-code .ec-line.mark .code,.expressive-code .ec-line.ins .code,.expressive-code .ec-line.del .code{--ecGtrBrdWd:var(--ec-tm-lineMarkerAccentWd)}.expressive-code .ec-line.mark .code::before,.expressive-code .ec-line.ins .code::before,.expressive-code .ec-line.del .code::before{display:block;position:absolute;left:0;box-sizing:border-box;content:var(--tmLabel, &apos; &apos;);padding-inline-start:var(--ec-tm-lineDiffIndMargLeft);text-align:center;white-space:pre}.expressive-code .ec-line.mark.tm-label .code::before,.expressive-code .ec-line.ins.tm-label .code::before,.expressive-code .ec-line.del.tm-label .code::before{background:var(--ecLineBrdCol);padding:0 calc(var(--ec-tm-lineMarkerLabelPadInl) + var(--ec-tm-lineMarkerAccentWd)) 0 var(--ec-tm-lineMarkerLabelPadInl);color:var(--ec-tm-lineMarkerLabelCol)}.expressive-code .ec-line mark{--tmInlineBgCol:var(--ec-tm-markBg);--tmInlineBrdCol:var(--ec-tm-markBrdCol)}.expressive-code .ec-line ins{--tmInlineBgCol:var(--ec-tm-insBg);--tmInlineBrdCol:var(--ec-tm-insBrdCol)}.expressive-code .ec-line del{--tmInlineBgCol:var(--ec-tm-delBg);--tmInlineBrdCol:var(--ec-tm-delBrdCol)}.expressive-code .ec-line mark,.expressive-code .ec-line ins,.expressive-code .ec-line del{all:unset;display:inline-block;position:relative;--tmBrdL:var(--ec-tm-inlMarkerBrdWd);--tmBrdR:var(--ec-tm-inlMarkerBrdWd);--tmRadL:var(--ec-tm-inlMarkerBrdRad);--tmRadR:var(--ec-tm-inlMarkerBrdRad);margin-inline:0.025rem;padding-inline:var(--ec-tm-inlMarkerPad);border-radius:var(--tmRadL) var(--tmRadR) var(--tmRadR) var(--tmRadL);background:var(--tmInlineBgCol);background-clip:padding-box}.expressive-code .ec-line mark.open-start,.expressive-code .ec-line ins.open-start,.expressive-code .ec-line del.open-start{margin-inline-start:0;padding-inline-start:0;--tmBrdL:0px;--tmRadL:0}.expressive-code .ec-line mark.open-end,.expressive-code .ec-line ins.open-end,.expressive-code .ec-line del.open-end{margin-inline-end:0;padding-inline-end:0;--tmBrdR:0px;--tmRadR:0}.expressive-code .ec-line mark::before,.expressive-code .ec-line ins::before,.expressive-code .ec-line del::before{content:&apos;&apos;;position:absolute;pointer-events:none;display:inline-block;inset:0;border-radius:var(--tmRadL) var(--tmRadR) var(--tmRadR) var(--tmRadL);border:var(--ec-tm-inlMarkerBrdWd) solid var(--tmInlineBrdCol);border-inline-width:var(--tmBrdL) var(--tmBrdR)}.expressive-code .frame{all:unset;position:relative;display:block;--header-border-radius:calc(var(--ec-brdRad) + var(--ec-brdWd));--tab-border-radius:calc(var(--ec-frm-edTabBrdRad) + var(--ec-brdWd));--button-spacing:0.4rem;--code-background:var(--ec-frm-edBg);border-radius:var(--header-border-radius);box-shadow:var(--ec-frm-frameBoxShdCssVal)}.expressive-code .frame .header{display:none;z-index:1;position:relative;border-radius:var(--header-border-radius) var(--header-border-radius) 0 0}.expressive-code .frame.has-title pre,.expressive-code .frame.has-title code,.expressive-code .frame.is-terminal pre,.expressive-code .frame.is-terminal code{border-top:none;border-top-left-radius:0;border-top-right-radius:0}.expressive-code .frame .title:empty:before{content:&apos;\a0&apos;}.expressive-code .frame.has-title:not(.is-terminal){--button-spacing:calc(1.9rem + 2 * (var(--ec-uiPadBlk) + var(--ec-frm-edActTabIndHt)))}.expressive-code .frame.has-title:not(.is-terminal) .title{position:relative;color:var(--ec-frm-edActTabFg);background:var(--ec-frm-edActTabBg);background-clip:padding-box;margin-block-start:var(--ec-frm-edTabsMargBlkStart);padding:calc(var(--ec-uiPadBlk) + var(--ec-frm-edActTabIndHt)) var(--ec-uiPadInl);border:var(--ec-brdWd) solid var(--ec-frm-edActTabBrdCol);border-radius:var(--tab-border-radius) var(--tab-border-radius) 0 0;border-bottom:none;overflow:hidden}.expressive-code .frame.has-title:not(.is-terminal) .title::after{content:&apos;&apos;;position:absolute;pointer-events:none;inset:0;border-top:var(--ec-frm-edActTabIndHt) solid var(--ec-frm-edActTabIndTopCol);border-bottom:var(--ec-frm-edActTabIndHt) solid var(--ec-frm-edActTabIndBtmCol)}.expressive-code .frame.has-title:not(.is-terminal) .header{display:flex;background:linear-gradient(to top, var(--ec-frm-edTabBarBrdBtmCol) var(--ec-brdWd), transparent var(--ec-brdWd)),linear-gradient(var(--ec-frm-edTabBarBg), var(--ec-frm-edTabBarBg));background-repeat:no-repeat;padding-inline-start:var(--ec-frm-edTabsMargInlStart)}.expressive-code .frame.has-title:not(.is-terminal) .header::before{content:&apos;&apos;;position:absolute;pointer-events:none;inset:0;border:var(--ec-brdWd) solid var(--ec-frm-edTabBarBrdCol);border-radius:inherit;border-bottom:none}.expressive-code .frame.is-terminal{--button-spacing:calc(1.9rem + var(--ec-brdWd) + 2 * var(--ec-uiPadBlk));--code-background:var(--ec-frm-trmBg)}.expressive-code .frame.is-terminal .header{display:flex;align-items:center;justify-content:center;padding-block:var(--ec-uiPadBlk);padding-block-end:calc(var(--ec-uiPadBlk) + var(--ec-brdWd));position:relative;font-weight:500;letter-spacing:0.025ch;color:var(--ec-frm-trmTtbFg);background:var(--ec-frm-trmTtbBg);border:var(--ec-brdWd) solid var(--ec-brdCol);border-bottom:none}.expressive-code .frame.is-terminal .header::before{content:&apos;&apos;;position:absolute;pointer-events:none;left:var(--ec-uiPadInl);width:2.1rem;height:0.56rem;line-height:0;background-color:var(--ec-frm-trmTtbDotsFg);opacity:var(--ec-frm-trmTtbDotsOpa);-webkit-mask-image:var(--ec-frm-trmIcon);-webkit-mask-repeat:no-repeat;mask-image:var(--ec-frm-trmIcon);mask-repeat:no-repeat}.expressive-code .frame.is-terminal .header::after{content:&apos;&apos;;position:absolute;pointer-events:none;inset:0;border-bottom:var(--ec-brdWd) solid var(--ec-frm-trmTtbBrdBtmCol)}.expressive-code .frame pre{background:var(--code-background)}.expressive-code .copy{display:flex;gap:0.25rem;flex-direction:row;position:absolute;inset-block-start:calc(var(--ec-brdWd) + var(--button-spacing));inset-inline-end:calc(var(--ec-brdWd) + var(--ec-uiPadInl) / 2)}@media (scripting: none){.expressive-code .copy{display:none}}.expressive-code .copy{direction:ltr;unicode-bidi:isolate}.expressive-code .copy button{position:relative;align-self:flex-end;margin:0;padding:0;border:none;border-radius:0.2rem;z-index:1;cursor:pointer;transition-property:opacity, background, border-color;transition-duration:0.2s;transition-timing-function:cubic-bezier(0.25, 0.46, 0.45, 0.94);width:2.5rem;height:2.5rem;background:var(--code-background);opacity:0.75}.expressive-code .copy button div{position:absolute;inset:0;border-radius:inherit;background:var(--ec-frm-inlBtnBg);opacity:var(--ec-frm-inlBtnBgIdleOpa);transition-property:inherit;transition-duration:inherit;transition-timing-function:inherit}.expressive-code .copy button::before{content:&apos;&apos;;position:absolute;pointer-events:none;inset:0;border-radius:inherit;border:var(--ec-brdWd) solid var(--ec-frm-inlBtnBrd);opacity:var(--ec-frm-inlBtnBrdOpa)}.expressive-code .copy button::after{content:&apos;&apos;;position:absolute;pointer-events:none;inset:0;background-color:var(--ec-frm-inlBtnFg);-webkit-mask-image:var(--ec-frm-copyIcon);-webkit-mask-repeat:no-repeat;mask-image:var(--ec-frm-copyIcon);mask-repeat:no-repeat;margin:0.475rem;line-height:0}.expressive-code .copy button:hover,.expressive-code .copy button:focus:focus-visible{opacity:1}.expressive-code .copy button:hover div,.expressive-code .copy button:focus:focus-visible div{opacity:var(--ec-frm-inlBtnBgHoverOrFocusOpa)}.expressive-code .copy button:active{opacity:1}.expressive-code .copy button:active div{opacity:var(--ec-frm-inlBtnBgActOpa)}.expressive-code .copy .feedback{--tooltip-arrow-size:0.35rem;--tooltip-bg:var(--ec-frm-tooltipSuccessBg);color:var(--ec-frm-tooltipSuccessFg);pointer-events:none;user-select:none;-webkit-user-select:none;position:relative;align-self:center;background-color:var(--tooltip-bg);z-index:99;padding:0.125rem 0.75rem;border-radius:0.2rem;margin-inline-end:var(--tooltip-arrow-size);opacity:0;transition-property:opacity, transform;transition-duration:0.2s;transition-timing-function:ease-in-out;transform:translate3d(0, 0.25rem, 0)}.expressive-code .copy .feedback::after{content:&apos;&apos;;position:absolute;pointer-events:none;top:calc(50% - var(--tooltip-arrow-size));inset-inline-end:calc(-2 * (var(--tooltip-arrow-size) - 0.5px));border:var(--tooltip-arrow-size) solid transparent;border-inline-start-color:var(--tooltip-bg)}.expressive-code .copy .feedback.show{opacity:1;transform:translate3d(0, 0, 0)}@media (hover: hover){.expressive-code{}.expressive-code .copy button{opacity:0;width:2rem;height:2rem}.expressive-code .frame:hover .copy button:not(:hover),.expressive-code .frame:focus-within :focus-visible ~ .copy button:not(:hover),.expressive-code .frame .copy .feedback.show ~ button:not(:hover){opacity:0.75}}.expressive-code :nth-child(1 of .ec-line) .code{padding-inline-end:calc(2rem + var(--ec-codePadInl))}:root{--ec-brdRad:0.75rem;--ec-brdWd:1.5px;--ec-brdCol:var(--code-line);--ec-codeFontFml:var(--font-code);--ec-codeFontSize:0.875rem;--ec-codeFontWg:400;--ec-codeLineHt:1.75;--ec-codePadBlk:1rem;--ec-codePadInl:1.125rem;--ec-codeBg:var(--code-bg);--ec-codeFg:#e6edf3;--ec-codeSelBg:#264f78;--ec-gtrFg:#6e7681;--ec-gtrBrdCol:#6e768133;--ec-gtrBrdWd:1.5px;--ec-gtrHlFg:#e6edf3;--ec-uiFontFml:var(--font-mono);--ec-uiFontSize:0.75rem;--ec-uiFontWg:400;--ec-uiLineHt:1.65;--ec-uiPadBlk:0.25rem;--ec-uiPadInl:1rem;--ec-uiSelBg:#6e768166;--ec-uiSelFg:#e6edf3;--ec-focusBrd:#1f6feb;--ec-sbThumbCol:#8b949e33;--ec-sbThumbHoverCol:#8b949e3d;--ec-tm-lineMarkerAccentMarg:0rem;--ec-tm-lineMarkerAccentWd:0.15rem;--ec-tm-lineMarkerLabelPadInl:0.2rem;--ec-tm-lineMarkerLabelCol:white;--ec-tm-lineDiffIndMargLeft:0.3rem;--ec-tm-inlMarkerBrdWd:1.5px;--ec-tm-inlMarkerBrdRad:0.2rem;--ec-tm-inlMarkerPad:0.15rem;--ec-tm-insDiffIndContent:&apos;+&apos;;--ec-tm-delDiffIndContent:&apos;-&apos;;--ec-tm-markBg:#264a8980;--ec-tm-markBrdCol:#5570b3d0;--ec-tm-insBg:#26561c80;--ec-tm-insBrdCol:#4e7e41d0;--ec-tm-insDiffIndCol:#7eb070d0;--ec-tm-delBg:#81322b80;--ec-tm-delBrdCol:#ae594fd0;--ec-tm-delDiffIndCol:#e68a7ed0;--ec-frm-shdCol:#0000005b;--ec-frm-frameBoxShdCssVal:none;--ec-frm-edActTabBg:var(--code-bg);--ec-frm-edActTabFg:var(--code-muted);--ec-frm-edActTabBrdCol:transparent;--ec-frm-edActTabIndHt:1.5px;--ec-frm-edActTabIndTopCol:transparent;--ec-frm-edActTabIndBtmCol:#0d1117;--ec-frm-edTabsMargInlStart:0;--ec-frm-edTabsMargBlkStart:0;--ec-frm-edTabBrdRad:0.75rem;--ec-frm-edTabBarBg:var(--code-bg);--ec-frm-edTabBarBrdCol:var(--code-line);--ec-frm-edTabBarBrdBtmCol:var(--code-line);--ec-frm-edBg:var(--code-bg);--ec-frm-trmTtbFg:var(--code-muted);--ec-frm-trmTtbDotsFg:var(--code-muted);--ec-frm-trmTtbDotsOpa:0.15;--ec-frm-trmTtbBg:var(--code-bg);--ec-frm-trmTtbBrdBtmCol:var(--code-line);--ec-frm-trmBg:var(--code-bg);--ec-frm-inlBtnBg:var(--code-ink);--ec-frm-inlBtnBgIdleOpa:0;--ec-frm-inlBtnBgHoverOrFocusOpa:0.2;--ec-frm-inlBtnBgActOpa:0.3;--ec-frm-inlBtnFg:var(--code-ink);--ec-frm-inlBtnBrd:var(--code-line);--ec-frm-inlBtnBrdOpa:0.4;--ec-frm-tooltipSuccessBg:var(--color-emerald);--ec-frm-tooltipSuccessFg:var(--color-bg);--ec-frm-copyIcon:url(&quot;data:image/svg+xml,%3Csvg%20xmlns%3D&apos;http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg&apos;%20viewBox%3D&apos;0%200%2024%2024&apos;%20fill%3D&apos;none&apos;%20stroke%3D&apos;black&apos;%20stroke-width%3D&apos;1.75&apos;%3E%3Cpath%20d%3D&apos;M3%2019a2%202%200%200%201-1-2V2a2%202%200%200%201%201-1h13a2%202%200%200%201%202%201&apos;%2F%3E%3Crect%20x%3D&apos;6&apos;%20y%3D&apos;5&apos;%20width%3D&apos;16&apos;%20height%3D&apos;18&apos;%20rx%3D&apos;1.5&apos;%20ry%3D&apos;1.5&apos;%2F%3E%3C%2Fsvg%3E&quot;);--ec-frm-trmIcon:url(&quot;data:image/svg+xml,%3Csvg%20xmlns%3D&apos;http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg&apos;%20viewBox%3D&apos;0%200%2060%2016&apos;%20preserveAspectRatio%3D&apos;xMidYMid%20meet&apos;%3E%3Ccircle%20cx%3D&apos;8&apos;%20cy%3D&apos;8&apos;%20r%3D&apos;8&apos;%2F%3E%3Ccircle%20cx%3D&apos;30&apos;%20cy%3D&apos;8&apos;%20r%3D&apos;8&apos;%2F%3E%3Ccircle%20cx%3D&apos;52&apos;%20cy%3D&apos;8&apos;%20r%3D&apos;8&apos;%2F%3E%3C%2Fsvg%3E&quot;)}.expressive-code .ec-line :where(span[style^=&apos;--&apos;]:not([class])){color:var(--0, inherit);background-color:var(--0bg, transparent);font-style:var(--0fs, inherit);font-weight:var(--0fw, inherit);text-decoration:var(--0td, inherit)}&lt;/style&gt;&lt;script type=&quot;module&quot; src=&quot;/_astro/ec.0vx5m.js&quot;&gt;&lt;/script&gt;&lt;figure class=&quot;frame has-title&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;SQL&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;sql&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#8B949E&quot;&gt;-- প্রডিউসার সার্ভিসের ডেটাবেজে Outbox টেবিল&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;CREATE&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;TABLE&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D2A8FF&quot;&gt;outbox_messages&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; (&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;id UUID &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;PRIMARY KEY&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;DEFAULT&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; gen_random_uuid(),&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;aggregate_type &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;VARCHAR&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;255&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;NOT NULL&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#8B949E&quot;&gt;-- যেমন: &apos;ORDER&apos;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;aggregate_id &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;VARCHAR&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;255&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;NOT NULL&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;,   &lt;/span&gt;&lt;span style=&quot;--0:#8B949E&quot;&gt;-- যেমন: Order ID&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;event_type &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;VARCHAR&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;255&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;NOT NULL&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;,     &lt;/span&gt;&lt;span style=&quot;--0:#8B949E&quot;&gt;-- যেমন: &apos;ORDER_CREATED&apos;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;payload JSONB &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;NOT NULL&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;,               &lt;/span&gt;&lt;span style=&quot;--0:#8B949E&quot;&gt;-- সম্পূর্ণ ইভেন্ট ডেটা&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;status&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;VARCHAR&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;50&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;DEFAULT&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;&apos;PENDING&apos;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#8B949E&quot;&gt;-- PENDING, PROCESSED, FAILED&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;retry_count &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;INT&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;DEFAULT&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;created_at &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;TIMESTAMP WITH TIME ZONE&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;DEFAULT&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; CURRENT_TIMESTAMP,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;processed_at &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;TIMESTAMP WITH TIME ZONE&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#8B949E&quot;&gt;-- কনজিউমার সার্ভিসের ডেটাবেজে Idempotency টেবিল&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;CREATE&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;TABLE&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D2A8FF&quot;&gt;idempotent_consumers&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; (&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;message_id UUID &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;PRIMARY KEY&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;,          &lt;/span&gt;&lt;span style=&quot;--0:#8B949E&quot;&gt;-- Outbox টেবিলের ID এখানে ইউনিক কি হিসেবে বসবে&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;processed_at &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;TIMESTAMP WITH TIME ZONE&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;DEFAULT&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; CURRENT_TIMESTAMP,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;status&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;VARCHAR&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;50&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;NOT NULL&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;           &lt;/span&gt;&lt;span style=&quot;--0:#8B949E&quot;&gt;-- SUCCESS বা FAILED&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;-- প্রডিউসার সার্ভিসের ডেটাবেজে Outbox টেবিলCREATE TABLE outbox_messages (    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),    aggregate_type VARCHAR(255) NOT NULL, -- যেমন: &amp;#x27;ORDER&amp;#x27;    aggregate_id VARCHAR(255) NOT NULL,   -- যেমন: Order ID    event_type VARCHAR(255) NOT NULL,     -- যেমন: &amp;#x27;ORDER_CREATED&amp;#x27;    payload JSONB NOT NULL,               -- সম্পূর্ণ ইভেন্ট ডেটা    status VARCHAR(50) DEFAULT &amp;#x27;PENDING&amp;#x27;, -- PENDING, PROCESSED, FAILED    retry_count INT DEFAULT 0,    created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP,    processed_at TIMESTAMP WITH TIME ZONE);-- কনজিউমার সার্ভিসের ডেটাবেজে Idempotency টেবিলCREATE TABLE idempotent_consumers (    message_id UUID PRIMARY KEY,          -- Outbox টেবিলের ID এখানে ইউনিক কি হিসেবে বসবে    processed_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP,    status VARCHAR(50) NOT NULL           -- SUCCESS বা FAILED);&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;ধাপ ২: Atomic Transaction-এর ইমপ্লিমেন্টেশন কোড&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;এখন আমরা Node.js এবং Prisma ORM ব্যবহার করে দেখব কীভাবে একটি একক ট্রানজেকশন ব্লকের ভেতরে অর্ডার ক্রিয়েট এবং আউটবক্স এন্ট্রি ইনসার্ট করা হয়। এখানে আমরা কোনো এক্সটার্নাল কাফকা বা নেটওয়ার্ক কল করব না।&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame has-title&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;TypeScript&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;typescript&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; { PrismaClient } &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;&apos;@prisma/client&apos;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; { randomUUID } &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;&apos;crypto&apos;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;prisma&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D2A8FF&quot;&gt;PrismaClient&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;async&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;function&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D2A8FF&quot;&gt;createOrderWithOutbox&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#FFA657&quot;&gt;userId&lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;string&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#FFA657&quot;&gt;totalAmount&lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;number&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#FFA657&quot;&gt;items&lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;any&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;[]) {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;orderId&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D2A8FF&quot;&gt;randomUUID&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;eventId&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D2A8FF&quot;&gt;randomUUID&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#8B949E&quot;&gt;// একটি একক Atomic Transaction শুরু করা হচ্ছে&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;try&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;result&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;await&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; prisma.&lt;/span&gt;&lt;span style=&quot;--0:#D2A8FF&quot;&gt;$transaction&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;async&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;--0:#FFA657&quot;&gt;tx&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;=&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;--0:#8B949E&quot;&gt;// ১. মূল বিজনেস টেবিলে অর্ডার সেভ করা&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;newOrder&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;await&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; tx.orders.&lt;/span&gt;&lt;span style=&quot;--0:#D2A8FF&quot;&gt;create&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;({&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;data: {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;          &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;id: orderId,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;          &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;userId: userId,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;          &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;totalAmount: totalAmount,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;          &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;status: &lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;&apos;CREATED&apos;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;},&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;});&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;--0:#8B949E&quot;&gt;// ২. আউটবক্স টেবিলে ইভেন্ট পেলোড সেভ করা&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;await&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; tx.outbox_messages.&lt;/span&gt;&lt;span style=&quot;--0:#D2A8FF&quot;&gt;create&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;({&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;data: {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;          &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;id: eventId,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;          &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;aggregate_type: &lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;&apos;ORDER&apos;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;          &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;aggregate_id: orderId,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;          &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;event_type: &lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;&apos;ORDER_CREATED&apos;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;          &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;payload: &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;JSON&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#D2A8FF&quot;&gt;stringify&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;({&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;orderId: newOrder.id,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;userId: newOrder.userId,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;amount: newOrder.totalAmount,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;items: items,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;          &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;}),&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;          &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;status: &lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;&apos;PENDING&apos;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;},&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;});&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; newOrder;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;});&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;console.&lt;/span&gt;&lt;span style=&quot;--0:#D2A8FF&quot;&gt;log&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;`Order and Outbox entry created atomically with ID: ${&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;result&lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;id&lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;}`&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; result;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;} &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;catch&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; (error) {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#8B949E&quot;&gt;// ডেটাবেজে কোনো সমস্যা হলে দুটি টেবিলের রাইট অপারেশনই একসাথে রোলব্যাক হয়ে যাবে&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;console.&lt;/span&gt;&lt;span style=&quot;--0:#D2A8FF&quot;&gt;error&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;&apos;Failed to execute atomic transaction, rollback completed.&apos;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;, error);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;throw&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; error;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;import { PrismaClient } from &amp;#x27;@prisma/client&amp;#x27;;import { randomUUID } from &amp;#x27;crypto&amp;#x27;;const prisma = new PrismaClient();async function createOrderWithOutbox(userId: string, totalAmount: number, items: any[]) {  const orderId = randomUUID();  const eventId = randomUUID();  // একটি একক Atomic Transaction শুরু করা হচ্ছে  try {    const result = await prisma.$transaction(async (tx) =&gt; {      // ১. মূল বিজনেস টেবিলে অর্ডার সেভ করা      const newOrder = await tx.orders.create({        data: {          id: orderId,          userId: userId,          totalAmount: totalAmount,          status: &amp;#x27;CREATED&amp;#x27;,        },      });      // ২. আউটবক্স টেবিলে ইভেন্ট পেলোড সেভ করা      await tx.outbox_messages.create({        data: {          id: eventId,          aggregate_type: &amp;#x27;ORDER&amp;#x27;,          aggregate_id: orderId,          event_type: &amp;#x27;ORDER_CREATED&amp;#x27;,          payload: JSON.stringify({            orderId: newOrder.id,            userId: newOrder.userId,            amount: newOrder.totalAmount,            items: items,          }),          status: &amp;#x27;PENDING&amp;#x27;,        },      });      return newOrder;    });    console.log(&amp;#x60;Order and Outbox entry created atomically with ID: ${result.id}&amp;#x60;);    return result;  } catch (error) {    // ডেটাবেজে কোনো সমস্যা হলে দুটি টেবিলের রাইট অপারেশনই একসাথে রোলব্যাক হয়ে যাবে    console.error(&amp;#x27;Failed to execute atomic transaction, rollback completed.&amp;#x27;, error);    throw error;  }}&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;div class=&quot;callout&quot; role=&quot;note&quot; data-type=&quot;warning&quot;&gt;
&lt;p class=&quot;callout-title&quot;&gt;Warning&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;External Network Calls Inside DB Transactions:&lt;/strong&gt; আপনার লোকাল ডেটাবেজ ট্রানজেকশনের ভেতরে কখনোই এক্সটার্নাল মেসেজ ব্রোকারের পাবলিশ কোড (যেমন: &lt;code&gt;await kafka.send()&lt;/code&gt;) রাখবেন না। এক্সটার্নাল নেটওয়ার্ক কল যদি কোনো কারণে স্লো হয় বা টাইমআউট হয়, তবে তা আপনার মূল ডেটাবেজের কানেকশন পুল লকিং পিরিয়ড বাড়িয়ে দেবে। এর ফলে অন্য ইউজাররা ডেটাবেজ কানেকশন পাবে না এবং পুরো অ্যাপ্লিকেশন ক্যাসকেডিং ফেইলরের মাধ্যমে ডাউন হয়ে যাবে।&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;ধাপ ৩: The Outbox Publisher (Poller vs CDC)&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;আমাদের ডেটাবেজে এখন ইভেন্টগুলো &lt;code&gt;PENDING&lt;/code&gt; স্টেটে জমা হচ্ছে। এগুলোকে মেসেজ ব্রোকারে পাঠানোর জন্য আমাদের একটি ব্যাকগ্রাউন্ড ওয়ার্কার প্রয়োজন। এই কাজটির জন্য মূলত দুটি মেকানিজম ব্যবহার করা হয়: Custom Polling এবং Change Data Capture (CDC)।&lt;/p&gt;
&lt;p&gt;কাস্টম পোলিং মেকানিজমে আপনার অ্যাপ্লিকেশনে একটি ক্রন-জব বা ব্যাকগ্রাউন্ড থ্রেড থাকে, যা প্রতি কয়েক মিলিসেকেন্ড পর পর ডেটাবেজে &lt;code&gt;SELECT * FROM outbox_messages WHERE status = &apos;PENDING&apos; ORDER BY created_at ASC LIMIT 100&lt;/code&gt; কুয়েরি চালায়। মেসেজগুলো রিড করে সে কাফকাতে পাঠায় এবং পাঠানোর পর ডেটাবেজে মেসেজের স্ট্যাটাস &lt;code&gt;PROCESSED&lt;/code&gt; করে দেয়। ছোট বা মাঝারি স্কেলের অ্যাপ্লিকেশনের জন্য এটি চমৎকার কাজ করে, কিন্তু হাই-থ্রুপুট সিস্টেমে এটি ডেটাবেজের উপর মারাত্মক রিড-রাইট প্রেসার তৈরি করে।&lt;/p&gt;
&lt;p&gt;এই সমস্যার প্রোডাকশন সমাধান হলো Change Data Capture (CDC) টুল ব্যবহার করা, যার মধ্যে Debezium সবচেয়ে জনপ্রিয়। Debezium সরাসরি আপনার ডেটাবেজে কোনো কুয়েরি চালায় না। এর পরিবর্তে সে আপনার ডেটাবেজ ইঞ্জিনের Write-Ahead Log (WAL) বা বাইনারি লগ ফাইলকে লো-লেভেল বাইট স্ট্রিম হিসেবে সরাসরি রিড করে। যখনই &lt;code&gt;outbox_messages&lt;/code&gt; টেবিলে কোনো নতুন রো ইনসার্ট হয়, Debezium সেই লগ ফাইল থেকে ইভেন্টটি ধরে ফেলে এবং মিলিসেকেন্ডের মধ্যে কোনো ডেটাবেজ লকিং ছাড়াই কাফকা ব্রোকারে পুশ করে দেয়।&lt;/p&gt;
&lt;p&gt;উপরে দেখানো টাইমলাইন ডায়াগ্রামটিতে আপনি ক্লায়েন্ট রিকোয়েস্ট আসার পর থেকে শুরু করে ডেটাবেজ কমিট, সিডিসি ইঞ্জিনের লগ রিডিং, কাফকা ব্রোকারে মেসেজ পাবলিশ এবং কনজিউমার সার্ভিসের ইডেমপোটেন্ট প্রসেসিং পর্যন্ত পুরো এক্সিকিউশন ফ্লোটির মিলিসেকেন্ড-লেভেল ট্রেস দেখতে পাচ্ছেন।&lt;/p&gt;
&lt;h2 id=&quot;৫-distributed-failure-modes-what-breaks-how-to-fix&quot;&gt;৫. Distributed Failure Modes (What Breaks &amp;#x26; How to Fix)&lt;/h2&gt;
&lt;p&gt;একটি আর্কিটেকচার কতটুকু শক্তিশালী তা বোঝা যায় সিস্টেম ফেইল করার সময় সে কেমন আচরণ করে তা দেখে। আসুন আমরা ডিস্ট্রিবিউটেড সিস্টেমের তিনটি বাস্তব ফেইলর সিনারিও এবং সেগুলোর আর্কিটেকচারাল সমাধান বিশ্লেষণ করি।&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;সিনারিও ১: মেসেজ ব্রোকার সম্পূর্ণ ডাউন (Broker Goes Down)&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;em&gt;The Architectural Disaster:&lt;/em&gt; আপনার আউটবক্স পাবলিশার বা সিডিসি ইঞ্জিন কাফকা ব্রোকারে মেসেজ পাঠানোর চেষ্টা করছে, কিন্তু ব্রোকার ক্র্যাশ করার কারণে কোনো কানেকশন তৈরি হচ্ছে না। ফলে আউটবক্স টেবিলে হাজার হাজার &lt;code&gt;PENDING&lt;/code&gt; মেসেজের ব্যাকলগ তৈরি হচ্ছে এবং ব্যাকগ্রাউন্ড ওয়ার্কার বারবার রিট্রাই করে ডেটাবেজের কানেকশন পুল এক্সজস্ট করে ফেলছে।&lt;/li&gt;
&lt;li&gt;&lt;em&gt;The Structural Solution:&lt;/em&gt; এই পরিস্থিতিতে আপনাকে Exponential Backoff with Jitter মেকানিজম ইমপ্লিমেন্ট করতে হবে। ব্যাকগ্রাউন্ড ওয়ার্কার ইমিডিয়েটলি রিট্রাই না করে প্রতিবার ফেইল করার পর অপেক্ষার সময় বাড়িয়ে দেবে (যেমন: ২ সেকেন্ড, ৪ সেকেন্ড, ৮ সেকেন্ড, ১৬ সেকেন্ড)। এর সাথে একটি রেন্ডম টাইম বা Jitter যোগ করতে হবে যাতে সমস্ত ওয়ার্কার একই সময়ে ডেটাবেজ বা ব্রোকারে হিট করে Thundering Herd প্রবলেম তৈরি না করে।&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;সিনারিও ২: ডুপ্লিকেট মেসেজ ডেলিভারি (Dual Message Delivery)&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;em&gt;The Structural Solution:&lt;/em&gt; এই সমস্যার সমাধান হলো কনজিউমার সার্ভিসে Idempotent Consumer Layer তৈরি করা। যখন কোনো মেসেজ কনজিউমারে আসবে, তখন সে সরাসরি বিজনেস লজিক এক্সিকিউট করবে না। সে প্রথমে মেসেজের ইউনিক &lt;code&gt;message_id&lt;/code&gt; নিয়ে নিজের ডেটাবেজের &lt;code&gt;idempotent_consumers&lt;/code&gt; টেবিলে চেক করবে। যদি আইডিটি আগে থেকেই থাকে, তবে সে অপারেশনটি স্কিপ করবে এবং কাফকাকে সাকসেস একনলেজমেন্ট পাঠিয়ে দেবে। আর যদি আইডিটি না থাকে, তবে সে একই ডেটাবেজ ট্রানজেকশনের ভেতরে বিজনেস লজিক এক্সিকিউট করবে এবং &lt;code&gt;idempotent_consumers&lt;/code&gt; টেবিলে সেই আইডিটি ইনসার্ট করবে।&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&quot;callout&quot; role=&quot;note&quot; data-type=&quot;tip&quot;&gt;
&lt;p class=&quot;callout-title&quot;&gt;Tip&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;High-Throughput Distributed Locking:&lt;/strong&gt; ইডেমপোটেন্সি চেক করার সময় যদি আপনার কনজিউমার সার্ভিসে প্রতি সেকেন্ডে লাখ লাখ রিকোয়েস্ট আসে, তবে বারবার ডেটাবেজে রিড-রাইট করা ডেটাবেজকে স্লো করতে পারে। এই ধরনের হাই-থ্রুপুট সিনারিওতে আপনি Redis Distributed Lock (যেমন: Redlock অ্যালগরিদম) ব্যবহার করে মেমোরি লেভেলেই ইডেমপোটেন্সি চেক সম্পন্ন করতে পারেন। তবে মনে রাখবেন, ফাইনাল সেফটি নেট হিসেবে ডেটাবেজ লেভেলে ইউনিক কনস্ট্রেইন্ট (Unique Key Constraint) রাখাটাই সবচেয়ে সেফ ডেটা গার্ড।&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;সিনারিও ৩: আউট-অফ-অর্ডার ইভেন্ট প্রসেসিং (Out-of-Order Events)&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;em&gt;The Architectural Disaster:&lt;/em&gt; নেটওয়ার্ক ল্যাটেন্সি বা কাফকা পার্টিশন রি-ব্যালেন্সিংয়ের কারণে মেসেজের ক্রম পরিবর্তন হয়ে গেছে। ধরুন, &lt;code&gt;Order_Created&lt;/code&gt; ইভেন্ট আসার আগেই কোনোভাবে &lt;code&gt;Order_Updated&lt;/code&gt; বা &lt;code&gt;Order_Cancelled&lt;/code&gt; ইভেন্ট কনজিউমার সার্ভিসে চলে এসেছে। কনজিউমার যদি এই ইভেন্টটি আগে প্রসেস করে, তবে সে ডেটাবেজে কোনো অর্ডার খুঁজে পাবে না এবং পুরো প্রসেস ফেইল করবে।&lt;/li&gt;
&lt;li&gt;&lt;em&gt;The Structural Solution:&lt;/em&gt; এই সমস্যা সমাধানের জন্য আপনার ইভেন্ট পেলোডে ডেটাবেজের Incremental Version বা Timestamp ট্র্যাকিং রাখতে হবে। কনজিউমার সার্ভিসে একটি State Machine লজিক থাকবে যা চেক করবে ইনকামিং ইভেন্টের ভার্সন কারেন্ট ডেটাবেজ রেকর্ডের ভার্সনের চেয়ে বড় কিনা। যদি কোনো ইভেন্ট আউট-অফ-অর্ডার আসে, তবে কনজিউমার সেটিকে একটি Dead Letter Queue (DLQ) বা সাময়িক বাফারে রেখে দেবে এবং সঠিক ক্রমের ইভেন্ট আসার পর সেটিকে রি-প্রসেস করবে।&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;৬-high-throughput-performance-tuning&quot;&gt;৬. High-Throughput Performance Tuning&lt;/h2&gt;
&lt;p&gt;যখন আপনার সিস্টেমে প্রতি সেকেন্ডে ১০,০০০ বা তার বেশি ইভেন্ট জেনারেট হয়, তখন সাধারণ ইমপ্লিমেন্টেশন খুব দ্রুত পারফরম্যান্স বটেলনেকে পরিণত হয়। এই লার্জ স্কেলে পারফরম্যান্স ড্রপ ছাড়াই সিস্টেম চালানোর জন্য কিছু লো-লেভেল অপ্টিমাইজেশন লজিক প্রয়োগ করতে হয়।&lt;/p&gt;
&lt;p&gt;প্রথমত, আমরা কেন প্রোডাকশনে কাস্টম পোলিংয়ের চেয়ে Change Data Capture (CDC) বা Debezium-কে বেছে নিই তার টেকনিক্যাল জাস্টিফিকেশন বোঝা দরকার। আপনি যখন প্রতি সেকেন্ডে শত শত বার &lt;code&gt;SELECT * FROM outbox_messages WHERE status = &apos;PENDING&apos;&lt;/code&gt; কুয়েরি চালান, তখন ডেটাবেজ ইঞ্জিনকে বারবার টেবিল স্ক্যান করতে হয়। এছাড়া, মেসেজ প্রসেস হওয়ার পর যখন আপনি হাজার হাজার রেকর্ডের স্ট্যাটাস আপডেট করেন (&lt;code&gt;UPDATE outbox_messages SET status = &apos;PROCESSED&apos;&lt;/code&gt;), তখন ডেটাবেজে Row-level Lock তৈরি হয়। এই লকিং এবং কনস্ট্যান্ট রিড-রাইট আপনার মূল বিজনেস ট্রানজেকশনকে মারাত্মকভাবে স্লো করে দেয়। অন্যদিকে, Debezium সরাসরি ডেটাবেজের স্টোরেজ ইঞ্জিনের বাইরে থেকে WAL ফাইল রিড করে। ফলে ডেটাবেজের উপর রিড বা লকিংয়ের কোনো প্রেসারই পড়ে না, এবং আপনার মূল অ্যাপ্লিকেশন সর্বোচ্চ পারফরম্যান্সে কাজ করতে পারে।&lt;/p&gt;
&lt;p&gt;দ্বিতীয়ত, যদি আপনি ছোট স্কেলে পোলিং মেকানিজম ব্যবহার করতেই চান, তবে আপনার ডেটাবেজে একটি অপ্টিমাইজড Indexing Strategy থাকতে হবে। আউটবক্স টেবিলে শুধুমাত্র &lt;code&gt;status&lt;/code&gt; কলামের উপর ইনডেক্স তৈরি করলে সেটি খুব একটা লাভজনক হয় না, কারণ টেবিলে বেশিরভাগ রেকর্ডের স্ট্যাটাসই একসময় &lt;code&gt;PROCESSED&lt;/code&gt; হয়ে যায় (Low Cardinality)। এর বদলে আপনাকে &lt;code&gt;(status, created_at)&lt;/code&gt; কলামের উপর একটি কম্পোজিট বি-ট্রি (B-Tree) ইনডেক্স তৈরি করতে হবে। এতে ডেটাবেজ ইঞ্জিন কোনো ফুল টেবিল স্ক্যান ছাড়াই একদম ও-অফ-লগ-এন &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:1em;vertical-align:-0.25em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0278em;&quot;&gt;O&lt;/span&gt;&lt;span class=&quot;mopen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mop&quot;&gt;lo&lt;span style=&quot;margin-right:0.0139em;&quot;&gt;g&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.1667em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;n&lt;/span&gt;&lt;span class=&quot;mclose&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; টাইম কমপ্লেক্সিটিতে দ্রুততম সময়ের মধ্যে সবচেয়ে পুরনো পেন্ডিং মেসেজগুলো খুঁজে বের করতে পারবে।&lt;/p&gt;
&lt;p&gt;তৃতীয়ত, মেসেজ ব্রোকারে ডেটা পাঠানোর সময় সিঙ্গেল নেটওয়ার্ক কলের বদলে Batching &amp;#x26; Pipelining ব্যবহার করতে হবে। প্রতিবার একটি মেসেজ রিড করে কাফকাতে পাঠানোর জন্য টিসিপি (TCP) হ্যান্ডশেক এবং নেটওয়ার্ক রাউন্ড-ট্রিপ টাইম (RTT) নষ্ট করা বোকামি। এর বদলে আপনি একবারে ৫০০ বা ১০০০ মেসেজ মেমোরি বাফারে রিড করবেন এবং কাফকা প্রডিউসারের ব্যাচিং এপিআই ব্যবহার করে সিঙ্গেল নেটওয়ার্ক রিকোয়েস্টে পুরো পে-লোডটি পাঠিয়ে দেবেন। এতে আপনার নেটওয়ার্ক থ্রুপুট বহুগুণ বেড়ে যাবে এবং সিস্টেম ল্যাটেন্সি ড্রাস্টিক্যালি কমে আসবে।&lt;/p&gt;
&lt;div class=&quot;callout&quot; role=&quot;note&quot; data-type=&quot;note&quot;&gt;
&lt;p class=&quot;callout-title&quot;&gt;Important&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Outbox Table Cleanup / Purge Policy:&lt;/strong&gt; আউটবক্স টেবিলকে কখনোই পার্মানেন্ট স্টোরেজ হিসেবে ব্যবহার করবেন না। মেসেজ সাকসেসফুলি ব্রোকারে পাবলিশ হওয়ার পর টেবিলটিতে কোটি কোটি &lt;code&gt;PROCESSED&lt;/code&gt; রেকর্ড জমে যেতে পারে। এই অতিরিক্ত ডেটা টেবিলের সাইজ বাড়িয়ে দেয় এবং ইনডেক্সগুলোকে স্লো করে ফেলে। একটি নির্দিষ্ট সময় পর পর (যেমন: প্রতিদিন রাত ৩টায়) পুরনো প্রসেসড রেকর্ডগুলো ডিলিট বা আর্কাইভ করার জন্য একটি ডেডিকেটেড ক্রন-জব বা Purge Policy চালু রাখা বাধ্যতামূলক।&lt;/p&gt;
&lt;/div&gt;
&lt;h2 id=&quot;৭-alternative-solutions-trade-off-matrix&quot;&gt;৭. Alternative Solutions &amp;#x26; Trade-off Matrix&lt;/h2&gt;
&lt;p&gt;একজন সিনিয়র আর্কিটেক্টের মূল দায়িত্ব হলো অন্ধভাবে কোনো প্যাটার্ন ইমপ্লিমেন্ট না করে বিভিন্ন সলিউশনের ট্রেড-অফ বা সুবিধা-অসুবিধা বিশ্লেষণ করা। আউটবক্স প্যাটার্ন ছাড়াও ইন্ডাস্ট্রিতে ডেটা কন্সিস্টেন্সি হ্যান্ডেল করার জন্য আরও কিছু পদ্ধতি রয়েছে। আসুন আমরা সেগুলোর সাথে একটি সরাসরি তুলনা দেখে নিই।&lt;/p&gt;
&lt;p&gt;টু-ফেজ কমিট (2PC) হলো একটি ক্লাসিক ডিস্ট্রিবিউটেড ট্রানজেকশন প্রটোকল, যেখানে একটি কোঅর্ডিনেটর সার্ভিস সমস্ত ডেটাবেজ এবং ব্রোকারকে প্রথমে ট্রানজেকশনের জন্য প্রস্তুত হতে বলে (Prepare Phase) এবং সবাই রাজি হলে একসাথে কমিট করার নির্দেশ দেয় (Commit Phase)। এটি স্ট্রং কন্সিস্টেন্সি গ্যারান্টি দেয়, কিন্তু এর সবচেয়ে বড় সমস্যা হলো এটি একটি ব্লকিং প্রটোকল। কোনো একটি নোড স্লো হলে পুরো সিস্টেমের সমস্ত ট্রানজেকশন লক হয়ে বসে থাকে, যা আধুনিক হাই-স্কেল মাইক্রোসার্ভিসে সম্পূর্ণ অচল।&lt;/p&gt;
&lt;p&gt;নিচের কম্প্যারিসন টেবিল থেকে আপনি বিভিন্ন আর্কিটেকচারাল অ্যাপ্রোচের ট্রেড-অফ খুব সহজেই বুঝতে পারবেন:&lt;/p&gt;
&lt;section class=&quot;table-wrap&quot; tabindex=&quot;0&quot; aria-label=&quot;Table 1&quot;&gt;




























&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Architectural Approach&lt;/th&gt;&lt;th&gt;Data Consistency&lt;/th&gt;&lt;th&gt;System Complexity&lt;/th&gt;&lt;th&gt;Performance / Latency&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Dual Write (Anti-Pattern)&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;Very Low (Partial failure prone)&lt;/td&gt;&lt;td&gt;Low&lt;/td&gt;&lt;td&gt;Low Latency (High Risk)&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Two-Phase Commit (2PC)&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;High (Strict synchronous)&lt;/td&gt;&lt;td&gt;Very High&lt;/td&gt;&lt;td&gt;High Latency (Blocking)&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Transactional Outbox&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;Guaranteed Eventual Consistency&lt;/td&gt;&lt;td&gt;Medium&lt;/td&gt;&lt;td&gt;Low Latency (Asynchronous)&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/section&gt;
&lt;p&gt;এই ম্যাট্রিক্স থেকে স্পষ্ট দেখা যাচ্ছে যে, আমরা যখন সিস্টেম কমপ্লেক্সিটি এবং ল্যাটেন্সির মধ্যে একটি সঠিক ব্যালেন্স চাই, তখন Transactional Outbox Pattern আমাদের সবচেয়ে নির্ভরযোগ্য এবং প্রোডাকশন-রেডি সমাধান প্রদান করে।&lt;/p&gt;
&lt;h2 id=&quot;৮-summary-production-decision-rules&quot;&gt;৮. Summary &amp;#x26; Production Decision Rules&lt;/h2&gt;
&lt;p&gt;পুরো Deep Dive সেশন থেকে আমরা যা শিখলাম, তা এখন আপনার দৈনন্দিন কোডিং এবং সিস্টেম ডিজাইনে প্রয়োগ করার সময় এসেছে। কিন্তু মনে রাখবেন, সব জায়গায় এই প্যাটার্ন ব্যবহার করার প্রয়োজন নেই। একটি সঠিক আর্কিটেকচারাল সিদ্ধান্ত নেওয়ার জন্য নিচের প্রোডাকশন ডিসিশন রুলসগুলো মেনে চলুন:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;কখন আউটবক্স প্যাটার্ন ব্যবহার করবেন:&lt;/strong&gt; যদি আপনার অ্যাপ্লিকেশনে এমন কোনো বিজনেস ট্রানজেকশন থাকে যেখানে ডেটা লস হওয়া বা ইনকন্সিস্টেন্ট হওয়া কোনোভাবেই গ্রহণযোগ্য নয়-যেমন ফাইনান্সিয়াল ট্রানজেকশন, পেমেন্ট প্রসেসিং, অর্ডার প্লেসমেন্ট, বা ইনভেন্টরি ম্যানেজমেন্ট-তবে সেখানে Transactional Outbox এবং Idempotency ব্যবহার করা বাধ্যতামূলক।&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;কখন সাধারণ ইভেন্ট পাবলিশিং যথেষ্ট:&lt;/strong&gt; যদি আপনার ইভেন্টটি শুধুমাত্র কোনো অ্যানালিটিক্স ডেটা, ইউজার অ্যাক্টিভিটি ট্র্যাকিং, বা নন-ক্রিটিক্যাল নোটিফিকেশন পাঠানোর জন্য হয়, যেখানে দুই-একটি মেসেজ হারিয়ে গেলে বা ডুপ্লিকেট হলে বিজনেসে কোনো ক্ষতি হবে না, সেখানে আপনি সরাসরি ব্রোকারে ইভেন্ট পাঠাতে পারেন। সেখানে আউটবক্স প্যাটার্নের অতিরিক্ত কমপ্লেক্সিটি যোগ করার কোনো প্রয়োজন নেই।&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;আর্কিটেক্ট মাইন্ডসেট শিফট:&lt;/strong&gt; একজন জুনিয়র বা মিড-লেভেল ডেভেলপার সবসময় মনে করে যে তার কোড এবং নেটওয়ার্ক সবসময় ১oo% পারফেক্টলি কাজ করবে। কিন্তু একজন সিনিয়র আর্কিটেক্ট কোড লেখার সময় ডিফল্টভাবেই ধরে নেন যে নেটওয়ার্ক ফেইল করবে, ডেটাবেজ স্লো হবে, এবং মেসেজ ডুপ্লিকেট হবে। এই মানসিকতার পরিবর্তনই আপনাকে একটি সাধারণ অ্যাপ্লিকেশন তৈরি করা থেকে একটি রেজিলিয়েন্ট, ফল্ট-টল্যারেন্ট ডিস্ট্রিবিউটেড সিস্টেম ডিজাইন করার দিকে এগিয়ে নিয়ে যাবে।&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;ডিস্ট্রিবিউটেড সিস্টেমের এই Under-the-hood মেকানিজমগুলো সঠিকভাবে বুঝতে পারলে এবং আপনার প্রোডাকশন আর্কিটেকচারে ইমপ্লিমেন্ট করতে পারলে, আপনার সিস্টেম যেকোনো হাই-ট্রাফিক লোড বা নেটওয়ার্ক ফেইলর অত্যন্ত সাবলীলভাবে হ্যান্ডেল করতে সক্ষম হবে।&lt;/p&gt;</content:encoded><category>System Design</category><category>Deep Dive</category><category>Distributed Systems</category><category>Microservices</category><category>Transactional Outbox</category><category>Idempotency</category><category>Kafka</category><category>System Architecture</category><category>Under the hood</category></item><item><title>Cloudflare WAF দিয়ে AI Crawlers ব্লক করুন (SEO ট্রাফিক ঠিক রেখে)</title><link>https://www.rafeuddaraj.me/bn/blog/block-ai-crawlers-cloudflare-waf-guide/</link><guid isPermaLink="true">https://www.rafeuddaraj.me/bn/blog/block-ai-crawlers-cloudflare-waf-guide/</guid><description>Cloudflare WAF Custom Rule এবং cf.client.bot ব্যবহার করে Google Search Console-এর 403 এরর ছাড়া AI Scrapers ব্লক করার পারফেক্ট গাইড।</description><pubDate>Sun, 12 Jul 2026 20:25:23 GMT</pubDate><content:encoded>&lt;p&gt;আজকালকার দিনে AI Scraper এবং LLM Crawlers (যেমন ChatGPT-User, ClaudeBot, Perplexity) কোনো পারমিশন ছাড়াই ওয়েবসাইটের পুরো কনটেন্ট স্ক্র্যাপ করে নিয়ে যাচ্ছে। এর ফলে আপনার সার্ভার রিসোর্স এবং Bandwidth অযথা নষ্ট হচ্ছে, কিন্তু সাইট কোনো অর্গানিক ট্রাফিক বা ক্রেডিট পাচ্ছে না। অনেকেই এই সমস্যা সমাধান করতে Cloudflare WAF-এ গিয়ে ঢালাওভাবে একটি Custom Rule বানিয়ে দেন। সমস্যা হলো, এই ভুল অ্যাপ্রোচের কারণে অনেক সময় Google Search Console (GSC)-এর &lt;code&gt;/sitemap.xml&lt;/code&gt; এবং legitimate SEO Crawlers (যেমন Googlebot, Bingbot) ব্লক হয়ে যায়। এর ফলে Google Search Console-এ &lt;code&gt;General HTTP error: 403&lt;/code&gt; এরর দেখায় এবং সাইটের অর্গানিক র‍্যাঙ্কিং ধসে পড়ে। আমাদের আজকের এন্ড গোল হলো এমন একটি Production-Grade, Resilient Cloudflare WAF Rule আর্কিটেক্ট করা, যা শুধুমাত্র Unverified AI Scrapers এবং Bots-দের ব্লক করবে, কিন্তু Google বা Bing-এর মতো Verified Search Engine এবং সাধারণ ভিজিটরদের কোনো বাধা ছাড়া smooth access দেবে।&lt;/p&gt;
&lt;p&gt;এই কনফিগারেশন শুরু করার আগে আপনার কিছু প্রাথমিক প্রস্তুতি ও Tooling দরকার হবে। প্রথমত, আপনার ডোমেইনের Cloudflare DNS এবং WAF Dashboard-এ Active Admin বা Operator access থাকতে হবে। দ্বিতীয়ত, টেস্টিংয়ের জন্য আপনার Terminal-এ &lt;code&gt;curl&lt;/code&gt; অথবা Postman এবং একটি Google Search Console (GSC) অ্যাকাউন্ট লাগবে। পাশাপাশি Cloudflare WAF-এর Expression Builder এবং HTTP Header (বিশেষ করে User-Agent) সম্পর্কে প্রাথমিক ধারণা থাকলে এই সেটআপটি বোঝা আপনার জন্য অনেক সহজ হবে।&lt;/p&gt;
&lt;p&gt;Edge Layer Blocking আসলে কীভাবে কাজ করে, তা বোঝার জন্য একটি বাস্তব অ্যানালজি চিন্তা করা যাক। যখন কোনো রিকোয়েস্ট আপনার সার্ভারে আসে, তখন অরিজিন সার্ভারে পৌঁছানোর আগেই Cloudflare-এর Edge Network সেই রিকোয়েস্ট ইন্টারসেপ্ট করে। ধরুন আপনার অফিসের গেইটে একজন সিকিউরিটি গার্ড দাঁড়িয়ে আছে। আপনি তাকে বললেন, &quot;কেউ যদি মুখে বলে সে পুলিশের লোক, তাকে ঢুকতে দিও না।&quot; এখন একজন আসল পুলিশ অফিসার এসে আইডি কার্ড দেখানোর পরেও যদি গার্ড তাকে শুধু মুখের কথার ওপর ভিত্তি করে আটকে দেয়, তবে বিপদ! সাধারণ User-Agent ব্লকিং ঠিক এই কাজটাই করে। আমাদের আজকের সলিউশন হলো সিকিউরিটি গার্ডকে শেখানো যে সে যেন মুখের কথা (User-Agent) বিশ্বাস না করে, বরং অফিসিয়াল ভেরিফায়েড আইডি ব্যাজ (&lt;code&gt;cf.client.bot&lt;/code&gt;) চেক করে আসল সার্চ ইঞ্জিন আর নকল AI স্ক্র্যাপারদের আলাদা করতে পারে।&lt;/p&gt;
&lt;figure&gt;&lt;img src=&quot;https://raw.githubusercontent.com/rafeuddaraj/rafes-blog-assets/refs/heads/block-ai-crawlers-cloudflare-waf-guide/assets/cloudflare-waf-edge-routing.svg&quot; alt=&quot;Cloudflare WAF Edge Routing Architecture&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;900&quot; height=&quot;550&quot;&gt;&lt;figcaption&gt;Cloudflare WAF Edge Routing Architecture&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;এবার আমরা Step-by-Step Implementation শুরু করব। প্রথম স্টেপে আপনাকে Cloudflare Dashboard-এ লগইন করে আপনার টার্গেট ডোমেইন সিলেক্ট করতে হবে। এরপর বাম পাশের সাইডবার থেকে &lt;strong&gt;Security &gt; Security rules&lt;/strong&gt; সেকশনে যান এবং &lt;strong&gt;Custom rules&lt;/strong&gt; ট্যাবে ক্লিক করুন। নতুন রুল তৈরি করার জন্য &lt;strong&gt;Create rule&lt;/strong&gt; বাটনে ক্লিক করুন। রুলের একটি মিনিংফুল নাম দিন, যেমন: &lt;code&gt;AI Crawl Control - Block Unverified Scrapers&lt;/code&gt;। রুলগুলোর মধ্যে অর্ডারিং ঠিক রাখুন, যেন এটি অন্যান্য নরমাল রাউটিং রুলের আগে এক্সিকিউট হয়। দ্বিতীয় স্টেপে আমরা Visual Expression Builder-এর পরিবর্তে কোড-লেভেল লজিক ব্যবহারের জন্য Advanced Editor ব্যবহার করব। Expression Preview বক্সের ডান পাশে থাকা নীল রঙের &lt;strong&gt;Edit expression&lt;/strong&gt; লিংকে ক্লিক করুন। এতে আপনি সরাসরি SQL-like syntax লেখার অপশন পাবেন।&lt;/p&gt;
&lt;p&gt;তৃতীয় স্টেপে আমরা Core AI Bot Blocking Logic ইনজেক্ট করব। নিচের এক্সপ্রেশনটি এডিটরে পেস্ট করুন। এটি মূলত পরিচিত AI Scraper-দের User-Agent টার্গেট করে এবং &lt;code&gt;/robots.txt&lt;/code&gt; ফাইলকে ব্লকিংয়ের বাইরে রাখে যাতে ক্রলাররা আপনার সাইটের নিয়ম পড়তে পারে:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;style&gt;.expressive-code{font-family:var(--ec-uiFontFml);font-size:var(--ec-uiFontSize);font-weight:var(--ec-uiFontWg);line-height:var(--ec-uiLineHt);text-size-adjust:none;-webkit-text-size-adjust:none}.expressive-code *:not(:is(svg, svg *)){all:revert;box-sizing:border-box}.expressive-code pre{display:flex;margin:0;padding:0;border:var(--ec-brdWd) solid var(--ec-brdCol);border-radius:calc(var(--ec-brdRad) + var(--ec-brdWd));background:var(--ec-codeBg)}.expressive-code pre:focus-visible{outline:3px solid var(--ec-focusBrd);outline-offset:-3px}.expressive-code pre &gt; code{all:unset;display:block;flex:1 0 100%;padding:var(--ec-codePadBlk) 0;color:var(--ec-codeFg);font-family:var(--ec-codeFontFml);font-size:var(--ec-codeFontSize);font-weight:var(--ec-codeFontWg);line-height:var(--ec-codeLineHt)}.expressive-code pre{overflow-x:auto}.expressive-code pre.wrap .ec-line .code{white-space:pre-wrap;overflow-wrap:break-word;min-width:min(20ch, var(--ecMaxLine, 20ch))}.expressive-code pre.wrap .ec-line .code span.indent{white-space:pre}.expressive-code pre::-webkit-scrollbar,.expressive-code pre::-webkit-scrollbar-track{background-color:inherit;border-radius:calc(var(--ec-brdRad) + var(--ec-brdWd));border-top-left-radius:0;border-top-right-radius:0}.expressive-code pre::-webkit-scrollbar-thumb{background-color:var(--ec-sbThumbCol);border:4px solid transparent;background-clip:content-box;border-radius:10px}.expressive-code pre::-webkit-scrollbar-thumb:hover{background-color:var(--ec-sbThumbHoverCol)}.expressive-code pre::-webkit-scrollbar-corner{background:transparent}.expressive-code .ec-line{direction:ltr;unicode-bidi:isolate;display:grid;grid-template-areas:&apos;gutter code&apos;;grid-template-columns:auto 1fr;position:relative}.expressive-code .ec-line .gutter{grid-area:gutter;color:var(--ec-gtrFg)}.expressive-code .ec-line .gutter &gt; *{pointer-events:none;user-select:none;-webkit-user-select:none}.expressive-code .ec-line .gutter ~ .code{--ecLineBrdCol:var(--ec-gtrBrdCol)}.expressive-code .ec-line.highlight .gutter{color:var(--ec-gtrHlFg)}.expressive-code .ec-line .code{grid-area:code;position:relative;box-sizing:content-box;padding-inline-start:calc(var(--ecIndent, 0ch) + var(--ec-codePadInl) - var(--ecGtrBrdWd));padding-inline-end:var(--ec-codePadInl);text-indent:calc(var(--ecIndent, 0ch) * -1)}.expressive-code .ec-line .code::before,.expressive-code .ec-line .code::after,.expressive-code .ec-line .code :where(*){text-indent:0}.expressive-code .ec-line .code{--ecGtrBrdWd:var(--ec-gtrBrdWd);border-inline-start:var(--ecGtrBrdWd) solid var(--ecLineBrdCol, transparent)}.expressive-code .sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0, 0, 0, 0);white-space:nowrap;border-width:0}.expressive-code .ec-line.mark{--tmLineBgCol:var(--ec-tm-markBg)}.expressive-code .ec-line.mark .code{--ecLineBrdCol:var(--ec-tm-markBrdCol)}.expressive-code .ec-line.ins{--tmLineBgCol:var(--ec-tm-insBg);--tmLabel:var(--ec-tm-insDiffIndContent)}.expressive-code .ec-line.ins .code{--ecLineBrdCol:var(--ec-tm-insBrdCol)}.expressive-code .ec-line.ins .code::before{color:var(--ec-tm-insDiffIndCol)}.expressive-code .ec-line.del{--tmLineBgCol:var(--ec-tm-delBg);--tmLabel:var(--ec-tm-delDiffIndContent)}.expressive-code .ec-line.del .code{--ecLineBrdCol:var(--ec-tm-delBrdCol)}.expressive-code .ec-line.del .code::before{color:var(--ec-tm-delDiffIndCol)}.expressive-code .ec-line.mark,.expressive-code .ec-line.ins,.expressive-code .ec-line.del{background:var(--tmLineBgCol)}.expressive-code .ec-line.mark .code,.expressive-code .ec-line.ins .code,.expressive-code .ec-line.del .code{--ecGtrBrdWd:var(--ec-tm-lineMarkerAccentWd)}.expressive-code .ec-line.mark .code::before,.expressive-code .ec-line.ins .code::before,.expressive-code .ec-line.del .code::before{display:block;position:absolute;left:0;box-sizing:border-box;content:var(--tmLabel, &apos; &apos;);padding-inline-start:var(--ec-tm-lineDiffIndMargLeft);text-align:center;white-space:pre}.expressive-code .ec-line.mark.tm-label .code::before,.expressive-code .ec-line.ins.tm-label .code::before,.expressive-code .ec-line.del.tm-label .code::before{background:var(--ecLineBrdCol);padding:0 calc(var(--ec-tm-lineMarkerLabelPadInl) + var(--ec-tm-lineMarkerAccentWd)) 0 var(--ec-tm-lineMarkerLabelPadInl);color:var(--ec-tm-lineMarkerLabelCol)}.expressive-code .ec-line mark{--tmInlineBgCol:var(--ec-tm-markBg);--tmInlineBrdCol:var(--ec-tm-markBrdCol)}.expressive-code .ec-line ins{--tmInlineBgCol:var(--ec-tm-insBg);--tmInlineBrdCol:var(--ec-tm-insBrdCol)}.expressive-code .ec-line del{--tmInlineBgCol:var(--ec-tm-delBg);--tmInlineBrdCol:var(--ec-tm-delBrdCol)}.expressive-code .ec-line mark,.expressive-code .ec-line ins,.expressive-code .ec-line del{all:unset;display:inline-block;position:relative;--tmBrdL:var(--ec-tm-inlMarkerBrdWd);--tmBrdR:var(--ec-tm-inlMarkerBrdWd);--tmRadL:var(--ec-tm-inlMarkerBrdRad);--tmRadR:var(--ec-tm-inlMarkerBrdRad);margin-inline:0.025rem;padding-inline:var(--ec-tm-inlMarkerPad);border-radius:var(--tmRadL) var(--tmRadR) var(--tmRadR) var(--tmRadL);background:var(--tmInlineBgCol);background-clip:padding-box}.expressive-code .ec-line mark.open-start,.expressive-code .ec-line ins.open-start,.expressive-code .ec-line del.open-start{margin-inline-start:0;padding-inline-start:0;--tmBrdL:0px;--tmRadL:0}.expressive-code .ec-line mark.open-end,.expressive-code .ec-line ins.open-end,.expressive-code .ec-line del.open-end{margin-inline-end:0;padding-inline-end:0;--tmBrdR:0px;--tmRadR:0}.expressive-code .ec-line mark::before,.expressive-code .ec-line ins::before,.expressive-code .ec-line del::before{content:&apos;&apos;;position:absolute;pointer-events:none;display:inline-block;inset:0;border-radius:var(--tmRadL) var(--tmRadR) var(--tmRadR) var(--tmRadL);border:var(--ec-tm-inlMarkerBrdWd) solid var(--tmInlineBrdCol);border-inline-width:var(--tmBrdL) var(--tmBrdR)}.expressive-code .frame{all:unset;position:relative;display:block;--header-border-radius:calc(var(--ec-brdRad) + var(--ec-brdWd));--tab-border-radius:calc(var(--ec-frm-edTabBrdRad) + var(--ec-brdWd));--button-spacing:0.4rem;--code-background:var(--ec-frm-edBg);border-radius:var(--header-border-radius);box-shadow:var(--ec-frm-frameBoxShdCssVal)}.expressive-code .frame .header{display:none;z-index:1;position:relative;border-radius:var(--header-border-radius) var(--header-border-radius) 0 0}.expressive-code .frame.has-title pre,.expressive-code .frame.has-title code,.expressive-code .frame.is-terminal pre,.expressive-code .frame.is-terminal code{border-top:none;border-top-left-radius:0;border-top-right-radius:0}.expressive-code .frame .title:empty:before{content:&apos;\a0&apos;}.expressive-code .frame.has-title:not(.is-terminal){--button-spacing:calc(1.9rem + 2 * (var(--ec-uiPadBlk) + var(--ec-frm-edActTabIndHt)))}.expressive-code .frame.has-title:not(.is-terminal) .title{position:relative;color:var(--ec-frm-edActTabFg);background:var(--ec-frm-edActTabBg);background-clip:padding-box;margin-block-start:var(--ec-frm-edTabsMargBlkStart);padding:calc(var(--ec-uiPadBlk) + var(--ec-frm-edActTabIndHt)) var(--ec-uiPadInl);border:var(--ec-brdWd) solid var(--ec-frm-edActTabBrdCol);border-radius:var(--tab-border-radius) var(--tab-border-radius) 0 0;border-bottom:none;overflow:hidden}.expressive-code .frame.has-title:not(.is-terminal) .title::after{content:&apos;&apos;;position:absolute;pointer-events:none;inset:0;border-top:var(--ec-frm-edActTabIndHt) solid var(--ec-frm-edActTabIndTopCol);border-bottom:var(--ec-frm-edActTabIndHt) solid var(--ec-frm-edActTabIndBtmCol)}.expressive-code .frame.has-title:not(.is-terminal) .header{display:flex;background:linear-gradient(to top, var(--ec-frm-edTabBarBrdBtmCol) var(--ec-brdWd), transparent var(--ec-brdWd)),linear-gradient(var(--ec-frm-edTabBarBg), var(--ec-frm-edTabBarBg));background-repeat:no-repeat;padding-inline-start:var(--ec-frm-edTabsMargInlStart)}.expressive-code .frame.has-title:not(.is-terminal) .header::before{content:&apos;&apos;;position:absolute;pointer-events:none;inset:0;border:var(--ec-brdWd) solid var(--ec-frm-edTabBarBrdCol);border-radius:inherit;border-bottom:none}.expressive-code .frame.is-terminal{--button-spacing:calc(1.9rem + var(--ec-brdWd) + 2 * var(--ec-uiPadBlk));--code-background:var(--ec-frm-trmBg)}.expressive-code .frame.is-terminal .header{display:flex;align-items:center;justify-content:center;padding-block:var(--ec-uiPadBlk);padding-block-end:calc(var(--ec-uiPadBlk) + var(--ec-brdWd));position:relative;font-weight:500;letter-spacing:0.025ch;color:var(--ec-frm-trmTtbFg);background:var(--ec-frm-trmTtbBg);border:var(--ec-brdWd) solid var(--ec-brdCol);border-bottom:none}.expressive-code .frame.is-terminal .header::before{content:&apos;&apos;;position:absolute;pointer-events:none;left:var(--ec-uiPadInl);width:2.1rem;height:0.56rem;line-height:0;background-color:var(--ec-frm-trmTtbDotsFg);opacity:var(--ec-frm-trmTtbDotsOpa);-webkit-mask-image:var(--ec-frm-trmIcon);-webkit-mask-repeat:no-repeat;mask-image:var(--ec-frm-trmIcon);mask-repeat:no-repeat}.expressive-code .frame.is-terminal .header::after{content:&apos;&apos;;position:absolute;pointer-events:none;inset:0;border-bottom:var(--ec-brdWd) solid var(--ec-frm-trmTtbBrdBtmCol)}.expressive-code .frame pre{background:var(--code-background)}.expressive-code .copy{display:flex;gap:0.25rem;flex-direction:row;position:absolute;inset-block-start:calc(var(--ec-brdWd) + var(--button-spacing));inset-inline-end:calc(var(--ec-brdWd) + var(--ec-uiPadInl) / 2)}@media (scripting: none){.expressive-code .copy{display:none}}.expressive-code .copy{direction:ltr;unicode-bidi:isolate}.expressive-code .copy button{position:relative;align-self:flex-end;margin:0;padding:0;border:none;border-radius:0.2rem;z-index:1;cursor:pointer;transition-property:opacity, background, border-color;transition-duration:0.2s;transition-timing-function:cubic-bezier(0.25, 0.46, 0.45, 0.94);width:2.5rem;height:2.5rem;background:var(--code-background);opacity:0.75}.expressive-code .copy button div{position:absolute;inset:0;border-radius:inherit;background:var(--ec-frm-inlBtnBg);opacity:var(--ec-frm-inlBtnBgIdleOpa);transition-property:inherit;transition-duration:inherit;transition-timing-function:inherit}.expressive-code .copy button::before{content:&apos;&apos;;position:absolute;pointer-events:none;inset:0;border-radius:inherit;border:var(--ec-brdWd) solid var(--ec-frm-inlBtnBrd);opacity:var(--ec-frm-inlBtnBrdOpa)}.expressive-code .copy button::after{content:&apos;&apos;;position:absolute;pointer-events:none;inset:0;background-color:var(--ec-frm-inlBtnFg);-webkit-mask-image:var(--ec-frm-copyIcon);-webkit-mask-repeat:no-repeat;mask-image:var(--ec-frm-copyIcon);mask-repeat:no-repeat;margin:0.475rem;line-height:0}.expressive-code .copy button:hover,.expressive-code .copy button:focus:focus-visible{opacity:1}.expressive-code .copy button:hover div,.expressive-code .copy button:focus:focus-visible div{opacity:var(--ec-frm-inlBtnBgHoverOrFocusOpa)}.expressive-code .copy button:active{opacity:1}.expressive-code .copy button:active div{opacity:var(--ec-frm-inlBtnBgActOpa)}.expressive-code .copy .feedback{--tooltip-arrow-size:0.35rem;--tooltip-bg:var(--ec-frm-tooltipSuccessBg);color:var(--ec-frm-tooltipSuccessFg);pointer-events:none;user-select:none;-webkit-user-select:none;position:relative;align-self:center;background-color:var(--tooltip-bg);z-index:99;padding:0.125rem 0.75rem;border-radius:0.2rem;margin-inline-end:var(--tooltip-arrow-size);opacity:0;transition-property:opacity, transform;transition-duration:0.2s;transition-timing-function:ease-in-out;transform:translate3d(0, 0.25rem, 0)}.expressive-code .copy .feedback::after{content:&apos;&apos;;position:absolute;pointer-events:none;top:calc(50% - var(--tooltip-arrow-size));inset-inline-end:calc(-2 * (var(--tooltip-arrow-size) - 0.5px));border:var(--tooltip-arrow-size) solid transparent;border-inline-start-color:var(--tooltip-bg)}.expressive-code .copy .feedback.show{opacity:1;transform:translate3d(0, 0, 0)}@media (hover: hover){.expressive-code{}.expressive-code .copy button{opacity:0;width:2rem;height:2rem}.expressive-code .frame:hover .copy button:not(:hover),.expressive-code .frame:focus-within :focus-visible ~ .copy button:not(:hover),.expressive-code .frame .copy .feedback.show ~ button:not(:hover){opacity:0.75}}.expressive-code :nth-child(1 of .ec-line) .code{padding-inline-end:calc(2rem + var(--ec-codePadInl))}:root{--ec-brdRad:0.75rem;--ec-brdWd:1.5px;--ec-brdCol:var(--code-line);--ec-codeFontFml:var(--font-code);--ec-codeFontSize:0.875rem;--ec-codeFontWg:400;--ec-codeLineHt:1.75;--ec-codePadBlk:1rem;--ec-codePadInl:1.125rem;--ec-codeBg:var(--code-bg);--ec-codeFg:#e6edf3;--ec-codeSelBg:#264f78;--ec-gtrFg:#6e7681;--ec-gtrBrdCol:#6e768133;--ec-gtrBrdWd:1.5px;--ec-gtrHlFg:#e6edf3;--ec-uiFontFml:var(--font-mono);--ec-uiFontSize:0.75rem;--ec-uiFontWg:400;--ec-uiLineHt:1.65;--ec-uiPadBlk:0.25rem;--ec-uiPadInl:1rem;--ec-uiSelBg:#6e768166;--ec-uiSelFg:#e6edf3;--ec-focusBrd:#1f6feb;--ec-sbThumbCol:#8b949e33;--ec-sbThumbHoverCol:#8b949e3d;--ec-tm-lineMarkerAccentMarg:0rem;--ec-tm-lineMarkerAccentWd:0.15rem;--ec-tm-lineMarkerLabelPadInl:0.2rem;--ec-tm-lineMarkerLabelCol:white;--ec-tm-lineDiffIndMargLeft:0.3rem;--ec-tm-inlMarkerBrdWd:1.5px;--ec-tm-inlMarkerBrdRad:0.2rem;--ec-tm-inlMarkerPad:0.15rem;--ec-tm-insDiffIndContent:&apos;+&apos;;--ec-tm-delDiffIndContent:&apos;-&apos;;--ec-tm-markBg:#264a8980;--ec-tm-markBrdCol:#5570b3d0;--ec-tm-insBg:#26561c80;--ec-tm-insBrdCol:#4e7e41d0;--ec-tm-insDiffIndCol:#7eb070d0;--ec-tm-delBg:#81322b80;--ec-tm-delBrdCol:#ae594fd0;--ec-tm-delDiffIndCol:#e68a7ed0;--ec-frm-shdCol:#0000005b;--ec-frm-frameBoxShdCssVal:none;--ec-frm-edActTabBg:var(--code-bg);--ec-frm-edActTabFg:var(--code-muted);--ec-frm-edActTabBrdCol:transparent;--ec-frm-edActTabIndHt:1.5px;--ec-frm-edActTabIndTopCol:transparent;--ec-frm-edActTabIndBtmCol:#0d1117;--ec-frm-edTabsMargInlStart:0;--ec-frm-edTabsMargBlkStart:0;--ec-frm-edTabBrdRad:0.75rem;--ec-frm-edTabBarBg:var(--code-bg);--ec-frm-edTabBarBrdCol:var(--code-line);--ec-frm-edTabBarBrdBtmCol:var(--code-line);--ec-frm-edBg:var(--code-bg);--ec-frm-trmTtbFg:var(--code-muted);--ec-frm-trmTtbDotsFg:var(--code-muted);--ec-frm-trmTtbDotsOpa:0.15;--ec-frm-trmTtbBg:var(--code-bg);--ec-frm-trmTtbBrdBtmCol:var(--code-line);--ec-frm-trmBg:var(--code-bg);--ec-frm-inlBtnBg:var(--code-ink);--ec-frm-inlBtnBgIdleOpa:0;--ec-frm-inlBtnBgHoverOrFocusOpa:0.2;--ec-frm-inlBtnBgActOpa:0.3;--ec-frm-inlBtnFg:var(--code-ink);--ec-frm-inlBtnBrd:var(--code-line);--ec-frm-inlBtnBrdOpa:0.4;--ec-frm-tooltipSuccessBg:var(--color-emerald);--ec-frm-tooltipSuccessFg:var(--color-bg);--ec-frm-copyIcon:url(&quot;data:image/svg+xml,%3Csvg%20xmlns%3D&apos;http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg&apos;%20viewBox%3D&apos;0%200%2024%2024&apos;%20fill%3D&apos;none&apos;%20stroke%3D&apos;black&apos;%20stroke-width%3D&apos;1.75&apos;%3E%3Cpath%20d%3D&apos;M3%2019a2%202%200%200%201-1-2V2a2%202%200%200%201%201-1h13a2%202%200%200%201%202%201&apos;%2F%3E%3Crect%20x%3D&apos;6&apos;%20y%3D&apos;5&apos;%20width%3D&apos;16&apos;%20height%3D&apos;18&apos;%20rx%3D&apos;1.5&apos;%20ry%3D&apos;1.5&apos;%2F%3E%3C%2Fsvg%3E&quot;);--ec-frm-trmIcon:url(&quot;data:image/svg+xml,%3Csvg%20xmlns%3D&apos;http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg&apos;%20viewBox%3D&apos;0%200%2060%2016&apos;%20preserveAspectRatio%3D&apos;xMidYMid%20meet&apos;%3E%3Ccircle%20cx%3D&apos;8&apos;%20cy%3D&apos;8&apos;%20r%3D&apos;8&apos;%2F%3E%3Ccircle%20cx%3D&apos;30&apos;%20cy%3D&apos;8&apos;%20r%3D&apos;8&apos;%2F%3E%3Ccircle%20cx%3D&apos;52&apos;%20cy%3D&apos;8&apos;%20r%3D&apos;8&apos;%2F%3E%3C%2Fsvg%3E&quot;)}.expressive-code .ec-line :where(span[style^=&apos;--&apos;]:not([class])){color:var(--0, inherit);background-color:var(--0bg, transparent);font-style:var(--0fs, inherit);font-weight:var(--0fw, inherit);text-decoration:var(--0td, inherit)}&lt;/style&gt;&lt;script type=&quot;module&quot; src=&quot;/_astro/ec.0vx5m.js&quot;&gt;&lt;/script&gt;&lt;figure class=&quot;frame has-title&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;SQL&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;sql&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;http&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;request&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;uri&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;path&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; ne &lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;&quot;/robots.txt&quot;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;and&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;http&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;user_agent&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; contains &lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;&quot;Applebot&quot;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;or&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;http&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;user_agent&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; contains &lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;&quot;archive.org_bot&quot;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;or&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;http&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;user_agent&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; contains &lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;&quot;ChatGPT-User&quot;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;or&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;http&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;user_agent&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; contains &lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;&quot;ClaudeBot&quot;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;or&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;http&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;user_agent&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; contains &lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;&quot;DuckAssistBot&quot;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;or&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;http&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;user_agent&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; contains &lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;&quot;MistralAI-User&quot;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;or&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;http&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;user_agent&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; contains &lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;&quot;OAI-SearchBot&quot;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;or&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;http&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;user_agent&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; contains &lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;&quot;Perplexity-User&quot;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;or&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;http&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;user_agent&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; contains &lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;&quot;PerplexityBot&quot;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;))&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;(http.request.uri.path ne &amp;#x22;/robots.txt&amp;#x22; and (http.user_agent contains &amp;#x22;Applebot&amp;#x22; or http.user_agent contains &amp;#x22;archive.org_bot&amp;#x22; or http.user_agent contains &amp;#x22;ChatGPT-User&amp;#x22; or http.user_agent contains &amp;#x22;ClaudeBot&amp;#x22; or http.user_agent contains &amp;#x22;DuckAssistBot&amp;#x22; or http.user_agent contains &amp;#x22;MistralAI-User&amp;#x22; or http.user_agent contains &amp;#x22;OAI-SearchBot&amp;#x22; or http.user_agent contains &amp;#x22;Perplexity-User&amp;#x22; or http.user_agent contains &amp;#x22;PerplexityBot&amp;#x22;))&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;চতুর্থ স্টেপে আমরা এই রুলটিকে Verified Bot Protection দিয়ে আপগ্রেড করব। শুধু User-Agent ব্লক করা নিরাপদ নয়, কারণ চালাক Scraper-রা নিজেদের Googlebot হিসেবে স্পুফ (Spoof) করতে পারে। আবার আমরা যদি ম্যানুয়ালি Googlebot বাদ দিতে যাই, তবে ভুল হওয়ার সম্ভাবনা থাকে। তাই আমরা Cloudflare-এর নেটিভ &lt;code&gt;cf.client.bot&lt;/code&gt; ফিল্ড ইন্টিগ্রেট করব। Cloudflare নিজে Reverse DNS এবং IP Reputation দিয়ে ভেরিফাই করে কারা আসল সার্চ ইঞ্জিন। আপনার এক্সপ্রেশনের শুরুতে &lt;code&gt;not cf.client.bot and&lt;/code&gt; যোগ করে ফাইনাল কোডটি এভাবে সেট করুন:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame has-title&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;SQL&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;sql&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;not&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;cf&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;client&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;.bot &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;and&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;http&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;request&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;uri&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;path&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; ne &lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;&quot;/robots.txt&quot;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;and&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;http&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;user_agent&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; contains &lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;&quot;Applebot&quot;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;or&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;http&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;user_agent&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; contains &lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;&quot;archive.org_bot&quot;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;or&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;http&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;user_agent&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; contains &lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;&quot;ChatGPT-User&quot;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;or&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;http&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;user_agent&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; contains &lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;&quot;ClaudeBot&quot;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;or&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;http&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;user_agent&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; contains &lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;&quot;DuckAssistBot&quot;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;or&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;http&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;user_agent&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; contains &lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;&quot;MistralAI-User&quot;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;or&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;http&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;user_agent&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; contains &lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;&quot;OAI-SearchBot&quot;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;or&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;http&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;user_agent&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; contains &lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;&quot;Perplexity-User&quot;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;or&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;http&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;user_agent&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; contains &lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;&quot;PerplexityBot&quot;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;))&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;(not cf.client.bot and http.request.uri.path ne &amp;#x22;/robots.txt&amp;#x22; and (http.user_agent contains &amp;#x22;Applebot&amp;#x22; or http.user_agent contains &amp;#x22;archive.org_bot&amp;#x22; or http.user_agent contains &amp;#x22;ChatGPT-User&amp;#x22; or http.user_agent contains &amp;#x22;ClaudeBot&amp;#x22; or http.user_agent contains &amp;#x22;DuckAssistBot&amp;#x22; or http.user_agent contains &amp;#x22;MistralAI-User&amp;#x22; or http.user_agent contains &amp;#x22;OAI-SearchBot&amp;#x22; or http.user_agent contains &amp;#x22;Perplexity-User&amp;#x22; or http.user_agent contains &amp;#x22;PerplexityBot&amp;#x22;))&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;নিচে Action সেকশন থেকে &lt;strong&gt;Block&lt;/strong&gt; সিলেক্ট করুন এবং &lt;strong&gt;Deploy&lt;/strong&gt; বাটনে ক্লিক করে রুলটি লাইভ করুন।&lt;/p&gt;
&lt;div class=&quot;callout&quot; role=&quot;note&quot; data-type=&quot;note&quot;&gt;
&lt;p class=&quot;callout-title&quot;&gt;Important&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;কেন &lt;code&gt;not cf.client.bot&lt;/code&gt; ব্যবহার করবেন?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;কোনো Scraper যদি তার User-Agent-এ &lt;code&gt;Googlebot&lt;/code&gt; লিখে আপনার সার্ভারে হিট করে, Cloudflare ব্যাকএন্ডে চেক করে দেখবে আইপিটি সত্যিই গুগলের কি না। যদি না হয়, তবে &lt;code&gt;cf.client.bot&lt;/code&gt; false রিটার্ন করবে এবং Scraper-টি সাথে সাথে ব্লক হয়ে যাবে। এটি আপনার সাইটকে স্পুফিং অ্যাটাক থেকে 100% সুরক্ষিত রাখবে।&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;ডেপ্লয়মেন্ট শেষ হলে এবার Verification এবং Testing-এর পালা। প্রথমত, আপনার টার্মিনাল ওপেন করুন এবং একটি AI Bot-এর User-Agent সাজিয়ে সাইটে রিকোয়েস্ট পাঠান। আপনি &lt;strong&gt;403 Forbidden&lt;/strong&gt; রেসপন্স পাবেন:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame is-terminal has-title&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;Terminal&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FFA657&quot;&gt;curl&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;-I&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;-A&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;&quot;Mozilla/5.0 AppleWebKit/537.36 (KHTML, like Gecko); compatible; ChatGPT-User/1.0; +https://openai.com/bot&quot;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;https://yourdomain.com/sitemap.xml&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;curl -I -A &amp;#x22;Mozilla/5.0 AppleWebKit/537.36 (KHTML, like Gecko); compatible; ChatGPT-User/1.0; +https://openai.com/bot&amp;#x22; https://yourdomain.com/sitemap.xml&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;এবার একটি নরমাল ব্রাউজার User-Agent দিয়ে টেস্ট করুন। আপনি &lt;strong&gt;200 OK&lt;/strong&gt; স্ট্যাটাস দেখতে পাবেন:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame is-terminal has-title&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;Terminal&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FFA657&quot;&gt;curl&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;-I&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;-A&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;&quot;Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36&quot;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;https://yourdomain.com&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;curl -I -A &amp;#x22;Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36&amp;#x22; https://yourdomain.com&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;দ্বিতীয়ত, Cloudflare Dashboard থেকে &lt;strong&gt;Security &gt; Events&lt;/strong&gt;-এ যান। অ্যাক্টিভিটি লগে দেখুন আপনার সদ্য তৈরি করা রুলটি ট্রিগার হচ্ছে কি না। সেখানে ব্লক হওয়া রিকোয়েস্টগুলোর IP, User-Agent এবং Action status (Block) ভেরিফাই করুন। তৃতীয়ত, সরাসরি Google Search Console-এ যান এবং আপনার সাইটের &lt;strong&gt;Sitemaps&lt;/strong&gt; সেকশনে ক্লিক করুন। আপনার &lt;code&gt;/sitemap.xml&lt;/code&gt; ফাইলটি রিসিঙ্ক বা পুনরায় সাবমিট করুন। কিছুক্ষণের মধ্যেই দেখবেন স্ট্যাটাস &lt;strong&gt;Success&lt;/strong&gt; হয়ে গেছে এবং কোনো 403 এরর আর আসছে না।&lt;/p&gt;
&lt;div class=&quot;callout&quot; role=&quot;note&quot; data-type=&quot;warning&quot;&gt;
&lt;p class=&quot;callout-title&quot;&gt;Warning&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;কমন ডিবাগিং টিপ:&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;রুল ডেপ্লয় করার পরেও যদি Google Search Console-এ 403 এরর পান, তবে চেক করুন আপনার রুলে কোথাও ভুলবশত &lt;code&gt;not cf.client.bot&lt;/code&gt; বাদ পড়েছে কি না অথবা অন্য কোনো পুরনো Firewalls বা Rate Limiting রুল গুগলকে ব্লক করছে কি না।&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;পরিশেষে, এই রুলটি অ্যাপ্লাই করার কিছু ট্রেড-অফ (Trade-offs) মাথায় রাখা জরুরি। আপনার ইউজাররা যদি কখনো সরাসরি আপনার সাইটের কোনো লিংক ChatGPT বা Perplexity-র চ্যাটবক্সে দিয়ে সামারাইজ বা অ্যানালাইজ করতে বলে, তবে AI সেটি পড়তে পারবে না (কারণ AI ক্রলার ব্লক খাবে)। আপনার বিজনেস মডেল যদি AI-driven ডিরেক্ট লিংক রিডিংয়ের ওপর নির্ভরশীল হয়, তবে এই ব্লক না রাখাই ভালো। ফিউচার স্কেলিং ও মেইনটেন্যান্সের জন্য মনে রাখবেন, AI ইন্ডাস্ট্রি খুব দ্রুত পরিবর্তন হচ্ছে এবং নতুন নতুন বট প্রতিদিন তৈরি হচ্ছে। প্রতি মাসে একবার Cloudflare-এর &lt;strong&gt;Security &gt; Events&lt;/strong&gt; লগ চেক করে নতুন কোনো Unverified Scraper চোখে পড়লে তাদের User-Agent আপনার WAF এক্সপ্রেশনে অ্যাড করে নেবেন। প্রয়োজনে প্রিমিয়াম Cloudflare Bot Management ফিচারও এক্সপ্লোর করতে পারেন।&lt;/p&gt;</content:encoded><category>Web Security</category><category>Cloudflare</category><category>WAF</category><category>Security</category><category>SEO</category><category>AI Scrapers</category><category>Tutorial</category><category>How-To</category><category>Web Development</category></item><item><title>Distributed Sagas এবং Compensating Transactions আসলে Under-the-Hood কীভাবে কাজ করে?</title><link>https://www.rafeuddaraj.me/bn/blog/distributed-sagas-compensating-transactions-deep-dive/</link><guid isPermaLink="true">https://www.rafeuddaraj.me/bn/blog/distributed-sagas-compensating-transactions-deep-dive/</guid><description>Microservices আর্কিটেকচারে 2PC কেন মৃত এবং Distributed Saga কীভাবে কাজ করে তার প্রোডাকশন গাইড। জানুন Orchestration, Choreography, WAL Replay এবং Concurrency Anomalies-এর লো-লেভেল মেকানিজম।</description><pubDate>Thu, 09 Jul 2026 16:47:36 GMT</pubDate><content:encoded>&lt;p&gt;মনোলিথিক আর্কিটেকচার ছেড়ে মাইক্রোসার্ভিসে আসার পর আমরা যে সবচেয়ে কঠিন বাস্তবতার মুখোমুখি হই, তা হলো ডেটাবেজ ট্রানজেকশনের বিলুপ্তি। মনোলিথে একটি সিঙ্গেল ডেটাবেজ থাকে, যেখানে আমরা খুব সহজেই ACID (Atomicity, Consistency, Isolation, Durability) প্রোপার্টি ব্যবহার করে ডেটা ব্যালেন্সড রাখতে পারি। কিন্তু যখন আমাদের সিস্টেম ডিস্ট্রিবিউটেড হয়ে যায়, যেখানে প্রতিটি মাইক্রোসার্ভিসের নিজস্ব ডেটাবেজ থাকে, তখন গ্লোবাল ট্রানজেকশন মেইনটেইন করা একটি দুঃস্বপ্নে পরিণত হয়।&lt;/p&gt;
&lt;p&gt;অনেকেই মনে করেন প্রথাগত Two-Phase Commit বা 2PC প্রটোকল ব্যবহার করে এই সমস্যার সমাধান করা সম্ভব। কিন্তু হাই-স্কেল প্রোডাকশন রিয়েলিটিতে 2PC একটি মৃত আর্কিটেকচার। আজ আমরা একদম হোয়াইটবোর্ড সেশনের মতো লো-লেভেল থেকে বিশ্লেষণ করব কেন ডিস্ট্রিবিউটেড লকিং সিস্টেমে ফেইল করে, এবং কীভাবে Distributed Saga ও Compensating Transactions-এর মেকানিজম ব্যবহার করে আমরা একটি রেজিলিয়েন্ট, প্রোডাকশন-গ্রেড স্টেট মেশিন তৈরি করতে পারি।&lt;/p&gt;
&lt;h2 id=&quot;১-the-core-distributed-nightmare-এবং-why-it-matters&quot;&gt;১. The Core Distributed Nightmare এবং Why It Matters&lt;/h2&gt;
&lt;p&gt;Two-Phase Commit (2PC) আর্কিটেকচারের সবচেয়ে বড় দুর্বলতা হলো এর Synchronous Lock Trap। 2PC প্রটোকলে একটি সেন্ট্রাল কোঅর্ডিনেটর সমস্ত ডেটাবেজকে প্রথমে ট্রানজেকশনের জন্য প্রস্তুত হতে বলে (Prepare Phase)। এই সময় প্রতিটি ডেটাবেজ তার নিজের রেকর্ডের উপর Distributed Lock বসিয়ে রাখে। যতক্ষণ না কোঅর্ডিনেটর ফাইনাল কমিট নির্দেশ (Commit Phase) দিচ্ছে, ততক্ষণ এই লকগুলো রিলিজ হয় না। এখন চিন্তা করুন, যদি আপনার সিস্টেমে পাঁচটি মাইক্রোসার্ভিস থাকে এবং তাদের মধ্যে একটি সার্ভিসের নেটওয়ার্ক রেসপন্স দিতে মাত্র ২০০ মিলিসেকেন্ড দেরি করে, তবে পুরো সিস্টেমের সমস্ত ডেটাবেজ থ্রেড সেই ২০০ মিলিসেকেন্ড ব্লক হয়ে বসে থাকবে। হাই-থ্রুপুট সিস্টেমে এই ব্লকিং বিহেভিয়ার আপনার ডেটাবেজ কানেকশন পুল মুহূর্তের মধ্যে শেষ করে দেয় এবং সিস্টেমের Latency বাড়িয়ে থ্রুপুট শূন্যে নামিয়ে আনে।&lt;/p&gt;
&lt;p&gt;এই কারণেই আধুনিক ক্লাউড-নেটিভ আর্কিটেকচারে আমরা ACID-এর Strict Isolation (I) প্রোপার্টি পুরোপুরি বাদ দিয়ে BASE (Basically Available, Soft state, Eventual consistency) মডেল আপন করে নিই। ডিস্ট্রিবিউটেড সিস্টেমে পারফেক্ট আইসোলেশন ধরে রাখা ম্যাথমেটিক্যালি এবং প্র্যাক্টিক্যালি অসম্ভব। আমাদের মেনে নিতে হয় যে সিস্টেমের স্টেট কিছু সময়ের জন্য আন-সিঙ্ক বা Soft state-এ থাকবে, কিন্তু একটি নির্দিষ্ট সময় পর সমস্ত ডেটা ইভেনচুয়ালি কন্সিস্টেন্ট বা সামঞ্জস্যপূর্ণ হয়ে যাবে।&lt;/p&gt;
&lt;p&gt;কিন্তু এখানে একটি মারাত্মক Linear Execution Problem তৈরি হয়। ধরুন, আপনার একটি ই-কমার্স অর্ডার চেইন আছে: Order Service থেকে ডেটা যায় Payment Service-এ, এবং সেখান থেকে যায় Inventory Service-এ। এখন পেমেন্ট সফল হওয়ার পর যদি ইনভেন্টরি সার্ভিস কোনো কারণে ক্র্যাশ করে বা আউট অফ স্টক এরর দেয়, তবে কী হবে? মনোলিথে আমরা একটি &lt;code&gt;ROLLBACK&lt;/code&gt; কমান্ড দিলেই সব আগের মতো হয়ে যেত। কিন্তু এখানে পেমেন্ট সার্ভিসের ডেটাবেজ ট্রানজেকশন ইতোমধ্যে কমিট হয়ে গেছে এবং মেমোরি থেকে তার আগের স্টেট মুছে গেছে। এই ডাউনস্ট্রিম ফেইলরের কারণে আপনার ইউজারের টাকা কেটে নেওয়া হলো অথচ সে প্রোডাক্ট পেল না। এই সাইলেন্ট ডেটা করাপশন ঠেকানোর জন্যই আমাদের Distributed Saga আর্কিটেকচারের প্রয়োজন।&lt;/p&gt;
&lt;h2 id=&quot;২-the-foundational-mental-model-এবং-analogy&quot;&gt;২. The Foundational Mental Model এবং Analogy&lt;/h2&gt;
&lt;p&gt;Distributed Saga-র কোর কনসেপ্ট অত্যন্ত শক্তিশালী এবং লজিক্যাল। এখানে আমরা পুরো প্রসেসটিকে একটি গ্লোবাল ডেটাবেজ লকের ভেতরে না রেখে, একাধিক স্বাধীন Local Transaction-এর একটি সিকোয়েন্সে বা চেইনে ভাগ করে ফেলি। প্রতিটি সার্ভিস তার নিজের ডেটাবেজে কাজ সম্পন্ন করে কমিট করে দেয়, এবং একটি Asynchronous Message বা Event পাবলিশ করে পরবর্তী সার্ভিসকে কাজ শুরু করার নির্দেশ দেয়।&lt;/p&gt;
&lt;p&gt;বিষয়টি পরিষ্কার করার জন্য আমরা একটি রিয়াল-ওয়ার্ল্ড Analogy (অ্যানালজি) বিবেচনা করতে পারি। ধরুন, আপনি একটি ট্রাভেল এজেন্সির মাধ্যমে ঢাকা থেকে প্যারিস যাওয়ার একটি মাল্টি-সিটি ট্যুর প্যাকেজ বুক করছেন। এই প্যাকেজে তিনটি কাজ আছে: ফ্লাইট বুকিং, হোটেল বুকিং এবং কার রেন্টাল। ট্রাভেল এজেন্ট কিন্তু তিনটি কোম্পানির সার্ভার একসাথে লক করে বসে থাকে না। সে প্রথমে এয়ারলাইন্সের সিস্টেমে ঢুকে ফ্লাইট বুক করে এবং একটি কনফার্মেশন টোকেন নেয়। এরপর সে হোটেল বুক করে। এখন ধরুন, কার রেন্টাল বুক করতে গিয়ে দেখা গেল কোনো গাড়ি ফাঁকা নেই। এজেন্ট কি এখন এয়ারলাইন্সের ডেটাবেজে ঢুকে আগের বুকিং ডিলিট করতে পারবে? অবশ্যই না, কারণ সেই ট্রানজেকশন ইতোমধ্যে শেষ। এজেন্ট এখন যা করবে তা হলো: সে এয়ারলাইন্স এবং হোটেলে একটি নতুন ক্যানসেলেশন রিকোয়েস্ট পাঠাবে।&lt;/p&gt;
&lt;p&gt;ডিস্ট্রিবিউটেড সিস্টেমে এই মানসিক মডেলটিকে আমরা বলি Eventual Consistency বাউন্ডারি। আমরা জানি যে ট্রানজেকশন চলাকালীন কিছু মিলিসেকেন্ড বা সেকেন্ডের জন্য আমাদের সিস্টেম একটি ইন-ফ্লাইট স্টেটে থাকবে। কিন্তু আমাদের আর্কিটেকচার এমনভাবে ডিজাইন করা থাকে যে শেষ পর্যন্ত হয় পুরো প্যাকেজ বুক হবে, অথবা সমস্ত লোকাল স্টেপ একে একে রিভার্স হয়ে সিস্টেম একদম প্রাথমিক ব্যালেন্সড স্টেটে ফিরে আসবে।&lt;/p&gt;
&lt;h2 id=&quot;৩-structural-typology-orchestration-vs-choreography-under-the-hood&quot;&gt;৩. Structural Typology: Orchestration vs Choreography (Under-the-Hood)&lt;/h2&gt;
&lt;p&gt;সাগা প্যাটার্ন ইমপ্লিমেন্ট করার জন্য ইন্ডাস্ট্রিতে দুটি প্রধান আর্কিটেকচারাল প্যাটার্ন ব্যবহার করা হয়: Orchestration এবং Choreography। আসুন দেখি লো-লেভেল মেমোরি এবং নেটওয়ার্ক লেভেলে এরা কীভাবে কাজ করে।&lt;/p&gt;
&lt;p&gt;Orchestration মডেলে একটি সেন্ট্রাল ব্রেন বা কোঅর্ডিনেটর থাকে, যাকে আমরা বলি Orchestrator Engine (যেমন: Temporal বা Camunda)। এই ইঞ্জিনটি পুরো সাগা ওয়ার্কফ্লো-এর একটি স্টেট মেশিন নিজের মেমোরিতে এবং ডেটাবেজে মেইনটেইন করে। যখন কোনো অর্ডার আসে, অর্কেস্ট্রেটর প্রথমে পেমেন্ট সার্ভিসকে কমান্ড পাঠায়। পেমেন্ট সফল হলে সেই উত্তর অর্কেস্ট্রেটরের কাছে ফেরে, এবং অর্কেস্ট্রেটর তখন ইনভেন্টরি সার্ভিসকে কমান্ড পাঠায়।&lt;/p&gt;
&lt;p&gt;এখানে একটি চমৎকার Under-the-hood মেকানিজম কাজ করে, যাকে বলা হয় Event Sourcing Mechanism। ধরুন, পেমেন্ট সফল হওয়ার পর অর্কেস্ট্রেটর ইঞ্জিন নিজেই ক্র্যাশ করল। রিস্টার্ট হওয়ার পর সে কীভাবে জানবে ট্রানজেকশন কোন স্টেপ পর্যন্ত এসেছিল? অর্কেস্ট্রেটর তার কারেন্ট স্টেট কখনোই সরাসরি আপডেট করে না। এর বদলে সে একটি Write-Ahead Log (WAL) বা ইভেন্ট স্টোরে প্রতিটি স্টেপের ইভেন্ট সিকোয়েনশিয়ালি লিখে রাখে (&lt;code&gt;OrderStarted&lt;/code&gt;, &lt;code&gt;PaymentCommandSent&lt;/code&gt;, &lt;code&gt;PaymentSucceeded&lt;/code&gt;)। সার্ভার রিস্টার্ট হলে সে শূন্য থেকে এই ইভেন্ট লগগুলো রিপ্লে (Replay) করে নিজের ইন-মেমোরি স্টেট মেশিনকে ঠিক আগের মুহূর্তে রিকনস্ট্রাক্ট করে নেয়।&lt;/p&gt;
&lt;figure&gt;&lt;img src=&quot;https://raw.githubusercontent.com/rafeuddaraj/rafes-blog-assets/refs/heads/distributed-sagas-compensating-transactions-deep-dive/assets/saga-orchestrator-state-flow.svg&quot; alt=&quot;Saga Orchestrator State Flow&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1000&quot; height=&quot;520&quot;&gt;&lt;figcaption&gt;Saga Orchestrator State Flow&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;অন্যদিকে, Choreography মডেলে কোনো সেন্ট্রাল ব্রেন থাকে না। এটি সম্পূর্ণ ডিসেন্ট্রালাইজড এবং Event-Driven Architecture। এখানে প্রতিটি সার্ভিস মেসেজ ব্রোকারের (যেমন: Kafka বা RabbitMQ) নির্দিষ্ট টপিক থেকে ইভেন্ট শোনে, নিজের লোকাল ডেটাবেজে কাজ করে, এবং আরেকটি নতুন ইভেন্ট ব্রোকারে ছেড়ে দেয়। যেমন: Order Service একটি &lt;code&gt;OrderCreated&lt;/code&gt; ইভেন্ট ছাড়ল, সেটি শুনে Payment Service টাকা কেটে &lt;code&gt;PaymentBilled&lt;/code&gt; ইভেন্ট ছাড়ল, যা শুনে Inventory Service স্টক আপডেট করল।&lt;/p&gt;
&lt;p&gt;কিন্তু কোরিওগ্রাফি মডেলে একটি মারাত্মক Cyclic Dependency Loop Dilemma তৈরি হওয়ার ঝুঁকি থাকে। ধরুন, সার্ভিস A ইভেন্ট পাঠায় B-কে, B পাঠায় C-কে, এবং কোনো রাউটিং এরর বা বিজনেস লজিকের কারণে C আবার একটি ইভেন্ট পাঠিয়ে দেয় A-কে। সিস্টেমে ট্রাফিক বাড়লে এই ডিসেন্ট্রালাইজড ইভেন্ট চেইন একটি ইনফিনিট লুপ বা ডেডলক তৈরি করে ব্রোকারের মেমোরি বাফার সম্পূর্ণ ক্র্যাশ করিয়ে দেয়। এই কারণে পাঁচটি সার্ভিসের বেশি জটিল ওয়ার্কফ্লো হলে আমরা সবসময় Orchestration মডেল বেছে নিই।&lt;/p&gt;
&lt;h2 id=&quot;৪-anatomy-of-a-saga-transaction-the-tri-partition-rule&quot;&gt;৪. Anatomy of a Saga Transaction: The Tri-Partition Rule&lt;/h2&gt;
&lt;p&gt;একটি ডিস্ট্রিবিউটেড সাগার প্রতিটি লোকাল ট্রানজেকশনকে সমান চোখে দেখা একটি বড় আর্কিটেকচারাল ভুল। সিস্টেম ডিজাইন করার সময় প্রতিটি সাগা চেইনকে তিনটি সুনির্দিষ্ট ফেইলর বাউন্ডারিতে ভাগ করতে হয়, যাকে আমরা বলি Tri-Partition Rule:&lt;/p&gt;
&lt;p&gt;১. &lt;strong&gt;Compensable Transactions:&lt;/strong&gt; সাগা সিকোয়েন্সের একদম শুরুর দিকের ট্রানজেকশনগুলো, যেগুলোকে ফেইলর হলে রিভার্স করা সম্ভব। যেমন: ইউজারের অ্যাকাউন্ট থেকে সাময়িক ব্যালেন্স হোল্ড করা বা ইনভেন্টরি রিভার্ভ করা। এই স্টেপগুলোতে সমস্যা হলে আমরা বিপরীত কমান্ড পাঠিয়ে ডেটা আগের অবস্থায় ফিরিয়ে আনতে পারি।&lt;/p&gt;
&lt;p&gt;২. &lt;strong&gt;The Pivot Transaction:&lt;/strong&gt; এটি পুরো সাগা ওয়ার্কফ্লো-এর সবচেয়ে ক্রিটিক্যাল পয়েন্ট বা পয়েন্ট অফ নো রিটার্ন। যদি এই ট্রানজেকশনটি সফল হয়ে যায়, তবে সাগা আর কোনোভাবেই পেছনে ফিরবে না। এর পরে আর কোনো Backward Recovery বা রোলব্যাক করার সুযোগ থাকে না। যেমন: থার্ড-পার্টি পেমেন্ট গেটওয়ে (Stripe বা PayPal) থেকে ফাইনাল পেমেন্ট ক্যাপচার হওয়া। টাকা একবার ব্যাংক থেকে কেটে বের হয়ে গেলে সেটিকে আর ডেটাবেজ রোলব্যাক দিয়ে ফেরানো যায় না।&lt;/p&gt;
&lt;p&gt;৩. &lt;strong&gt;Retriable Transactions:&lt;/strong&gt; পিভট ট্রানজেকশন সফল হওয়ার পর যে ডাউনস্ট্রিম স্টেপগুলো আসে, সেগুলো হলো Retriable Transactions। আর্কিটেকচারালি এই স্টেপগুলো কখনই স্থায়ীভাবে ফেইল করতে পারবে না। যেমন: ইউজারকে ইমেইল বা এসএমএস নোটিফিকেশন পাঠানো, অথবা ইনভেন্টরির স্ট্যাটাস &apos;Reserved&apos; থেকে &apos;Sold&apos;-এ পরিবর্তন করা। যদি নোটিফিকেশন সার্ভিসের নেটওয়ার্ক ড্রপ করে, তবে সিস্টেম ফেইল না করে Exponential Backoff দিয়ে ইনফিনিট রিট্রাই চালাতে থাকবে যতক্ষণ না কাজ সম্পন্ন হয় (Forward Recovery)।&lt;/p&gt;
&lt;h2 id=&quot;৫-the-reverse-engine-compensating-transactions-এবং-recovery-patterns&quot;&gt;৫. The Reverse Engine: Compensating Transactions এবং Recovery Patterns&lt;/h2&gt;
&lt;p&gt;মনোলিথিক ডেটাবেজে &lt;code&gt;ROLLBACK&lt;/code&gt; কমান্ড দিলে স্টোরেজ ইঞ্জিন ডিস্কের আন-কমিটেড পেজগুলো মুছে ফেলে আগের স্ন্যাপশটে ফিরে যায়। কিন্তু মাইক্রোসার্ভিসে এটি অসম্ভব, কারণ আপনার ট্রানজেকশন ইতোমধ্যে ডেটাবেজে কমিট হয়ে গেছে এবং অন্য কোনো থ্রেড হয়তো সেই ডেটা রিডও করে ফেলেছে। তাই এখানে আমাদের Semantic Rollback মেকানিজম ব্যবহার করতে হয়।&lt;/p&gt;
&lt;p&gt;Semantic Rollback হলো এমন একটি প্রক্রিয়া যেখানে আমরা আগের ডেটা ডিলিট না করে, একটি নতুন বিপরীত এন্ট্রি বা Compensating Transaction ডেটাবেজে ইনসার্ট করি যা আগের ট্রানজেকশনের প্রভাবকে গাণিতিকভাবে শূন্য করে দেয়। উদাহরণস্বরূপ, যদি আপনার লোকাল ট্রানজেকশন হয় &lt;code&gt;UPDATE accounts SET balance = balance - 500 WHERE id = 1&lt;/code&gt;, তবে এর কম্পেনসেটিং ট্রানজেকশন হবে &lt;code&gt;UPDATE accounts SET balance = balance + 500 WHERE id = 1&lt;/code&gt;। আমরা ডেটাবেজে একটি ডেবিট এন্ট্রির বিপরীতে একটি ক্রেডিট এন্ট্রি তৈরি করে লেজার ব্যালেন্সড করি।&lt;/p&gt;
&lt;p&gt;সাগা প্যাটার্নে দুটি প্রধান রিকভারি ওয়ার্কফ্লো কাজ করে:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Backward Recovery Workflow:&lt;/strong&gt; যদি পিভট ট্রানজেকশনে পৌঁছানোর আগেই কোনো স্টেপ ফেইল করে, তবে সিস্টেম পেছনের দিকে হাঁটা শুরু করে। ধরুন আপনার সিকোয়েন্স ছিল &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.8333em;vertical-align:-0.15em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.1389em;&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.3011em;&quot;&gt;&lt;span style=&quot;top:-2.55em;margin-left:-0.1389em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mtight&quot;&gt;1&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.15em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mrel&quot;&gt;→&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.8333em;vertical-align:-0.15em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.1389em;&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.3011em;&quot;&gt;&lt;span style=&quot;top:-2.55em;margin-left:-0.1389em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mtight&quot;&gt;2&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.15em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mrel&quot;&gt;→&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.8333em;vertical-align:-0.15em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.1389em;&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.3011em;&quot;&gt;&lt;span style=&quot;top:-2.55em;margin-left:-0.1389em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mtight&quot;&gt;3&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.15em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;। যদি &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.8333em;vertical-align:-0.15em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.1389em;&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.3011em;&quot;&gt;&lt;span style=&quot;top:-2.55em;margin-left:-0.1389em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mtight&quot;&gt;3&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.15em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; স্টেপে এসে এরর হয়, তবে অর্কেস্ট্রেটর রিভার্স অর্ডারে কম্পেনসেটিং কমান্ড ফায়ার করবে: &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.8333em;vertical-align:-0.15em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0715em;&quot;&gt;C&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.3011em;&quot;&gt;&lt;span style=&quot;top:-2.55em;margin-left:-0.0715em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mtight&quot;&gt;2&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.15em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mrel&quot;&gt;→&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.8333em;vertical-align:-0.15em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0715em;&quot;&gt;C&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.3011em;&quot;&gt;&lt;span style=&quot;top:-2.55em;margin-left:-0.0715em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mtight&quot;&gt;1&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.15em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;। মনে রাখবেন, যে স্টেপ ফেইল করেছে (&lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.8333em;vertical-align:-0.15em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.1389em;&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.3011em;&quot;&gt;&lt;span style=&quot;top:-2.55em;margin-left:-0.1389em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mtight&quot;&gt;3&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.15em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;), তার কোনো কম্পেনসেটিং কমান্ড ফায়ার হবে না, কারণ সে তো সফলই হয়নি।&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Forward Recovery Workflow:&lt;/strong&gt; যদি পিভট ট্রানজেকশন পার হওয়ার পর কোনো স্টেপে এরর দেখা দেয়, তবে সিস্টেম আর পেছনে ফেরে না। সে রোলব্যাক না করে সামনের দিকে এগোতে থাকে। সে ফেইলড স্টেপটিকে একটি বাফারে রেখে বারবার রিট্রাই চালিয়ে যায় যাতে পুরো প্রসেসটি এন্ড-টু-এন্ড কমপ্লিট হতে পারে।&lt;/li&gt;
&lt;/ul&gt;
&lt;figure&gt;&lt;img src=&quot;https://raw.githubusercontent.com/rafeuddaraj/rafes-blog-assets/refs/heads/distributed-sagas-compensating-transactions-deep-dive/assets/choreography-event-mesh-timings.svg&quot; alt=&quot;Choreography Event Mesh Timings&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1000&quot; height=&quot;480&quot;&gt;&lt;figcaption&gt;Choreography Event Mesh Timings&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;উপরে দেখানো টাইমলাইন ডায়াগ্রামটিতে আপনি দেখতে পাচ্ছেন কীভাবে বিভিন্ন মাইক্রোসার্ভিসের মধ্যে ইভেন্টগুলো প্যারালালি পাস হচ্ছে, এবং একটি ডাউনস্ট্রিম ফেইলর ঘটার সাথে সাথে কীভাবে ক্যাসকেডিং রিভার্স ইভেন্ট বা কম্পেনসেটিং ট্রানজেকশন ট্রিগার হয়ে সিস্টেমকে সামঞ্জস্যপূর্ণ অবস্থায় ফিরিয়ে আনছে।&lt;/p&gt;
&lt;h2 id=&quot;৬-step-by-step-execution-trace-এবং-code-mechanics&quot;&gt;৬. Step-by-Step Execution Trace এবং Code Mechanics&lt;/h2&gt;
&lt;p&gt;একটি প্রোডাকশন-গ্রেড সাগা অর্কেস্ট্রেটর কীভাবে কোড লেভেলে কাজ করে, তা বোঝার জন্য আমরা Node.js এবং TypeScript ব্যবহার করে একটি মেমোরি-সেফ কোঅর্ডিনেটর ইঞ্জিনের ব্লুপ্রিন্ট তৈরি করব। এই কোডটি প্রতিটি স্টেপ এক্সিকিউট করবে এবং ফেইলর হলে স্বয়ংক্রিয়ভাবে রিভার্স অর্ডারে কম্পেনসেটিং ফাংশনগুলো কল করবে।&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;ধাপ ১: The Orchestrator Coordinator Code Structure&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;আমরা এমন একটি ক্লাস তৈরি করব যা ট্রানজেকশন স্টেপ এবং তাদের রেস্পেক্টিভ কম্পেনসেটিং ফাংশনগুলোর ম্যাপ হোল্ড করবে।&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;style&gt;.expressive-code{font-family:var(--ec-uiFontFml);font-size:var(--ec-uiFontSize);font-weight:var(--ec-uiFontWg);line-height:var(--ec-uiLineHt);text-size-adjust:none;-webkit-text-size-adjust:none}.expressive-code *:not(:is(svg, svg *)){all:revert;box-sizing:border-box}.expressive-code pre{display:flex;margin:0;padding:0;border:var(--ec-brdWd) solid var(--ec-brdCol);border-radius:calc(var(--ec-brdRad) + var(--ec-brdWd));background:var(--ec-codeBg)}.expressive-code pre:focus-visible{outline:3px solid var(--ec-focusBrd);outline-offset:-3px}.expressive-code pre &gt; code{all:unset;display:block;flex:1 0 100%;padding:var(--ec-codePadBlk) 0;color:var(--ec-codeFg);font-family:var(--ec-codeFontFml);font-size:var(--ec-codeFontSize);font-weight:var(--ec-codeFontWg);line-height:var(--ec-codeLineHt)}.expressive-code pre{overflow-x:auto}.expressive-code pre.wrap .ec-line .code{white-space:pre-wrap;overflow-wrap:break-word;min-width:min(20ch, var(--ecMaxLine, 20ch))}.expressive-code pre.wrap .ec-line .code span.indent{white-space:pre}.expressive-code pre::-webkit-scrollbar,.expressive-code pre::-webkit-scrollbar-track{background-color:inherit;border-radius:calc(var(--ec-brdRad) + var(--ec-brdWd));border-top-left-radius:0;border-top-right-radius:0}.expressive-code pre::-webkit-scrollbar-thumb{background-color:var(--ec-sbThumbCol);border:4px solid transparent;background-clip:content-box;border-radius:10px}.expressive-code pre::-webkit-scrollbar-thumb:hover{background-color:var(--ec-sbThumbHoverCol)}.expressive-code pre::-webkit-scrollbar-corner{background:transparent}.expressive-code .ec-line{direction:ltr;unicode-bidi:isolate;display:grid;grid-template-areas:&apos;gutter code&apos;;grid-template-columns:auto 1fr;position:relative}.expressive-code .ec-line .gutter{grid-area:gutter;color:var(--ec-gtrFg)}.expressive-code .ec-line .gutter &gt; *{pointer-events:none;user-select:none;-webkit-user-select:none}.expressive-code .ec-line .gutter ~ .code{--ecLineBrdCol:var(--ec-gtrBrdCol)}.expressive-code .ec-line.highlight .gutter{color:var(--ec-gtrHlFg)}.expressive-code .ec-line .code{grid-area:code;position:relative;box-sizing:content-box;padding-inline-start:calc(var(--ecIndent, 0ch) + var(--ec-codePadInl) - var(--ecGtrBrdWd));padding-inline-end:var(--ec-codePadInl);text-indent:calc(var(--ecIndent, 0ch) * -1)}.expressive-code .ec-line .code::before,.expressive-code .ec-line .code::after,.expressive-code .ec-line .code :where(*){text-indent:0}.expressive-code .ec-line .code{--ecGtrBrdWd:var(--ec-gtrBrdWd);border-inline-start:var(--ecGtrBrdWd) solid var(--ecLineBrdCol, transparent)}.expressive-code .sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0, 0, 0, 0);white-space:nowrap;border-width:0}.expressive-code .ec-line.mark{--tmLineBgCol:var(--ec-tm-markBg)}.expressive-code .ec-line.mark .code{--ecLineBrdCol:var(--ec-tm-markBrdCol)}.expressive-code .ec-line.ins{--tmLineBgCol:var(--ec-tm-insBg);--tmLabel:var(--ec-tm-insDiffIndContent)}.expressive-code .ec-line.ins .code{--ecLineBrdCol:var(--ec-tm-insBrdCol)}.expressive-code .ec-line.ins .code::before{color:var(--ec-tm-insDiffIndCol)}.expressive-code .ec-line.del{--tmLineBgCol:var(--ec-tm-delBg);--tmLabel:var(--ec-tm-delDiffIndContent)}.expressive-code .ec-line.del .code{--ecLineBrdCol:var(--ec-tm-delBrdCol)}.expressive-code .ec-line.del .code::before{color:var(--ec-tm-delDiffIndCol)}.expressive-code .ec-line.mark,.expressive-code .ec-line.ins,.expressive-code .ec-line.del{background:var(--tmLineBgCol)}.expressive-code .ec-line.mark .code,.expressive-code .ec-line.ins .code,.expressive-code .ec-line.del .code{--ecGtrBrdWd:var(--ec-tm-lineMarkerAccentWd)}.expressive-code .ec-line.mark .code::before,.expressive-code .ec-line.ins .code::before,.expressive-code .ec-line.del .code::before{display:block;position:absolute;left:0;box-sizing:border-box;content:var(--tmLabel, &apos; &apos;);padding-inline-start:var(--ec-tm-lineDiffIndMargLeft);text-align:center;white-space:pre}.expressive-code .ec-line.mark.tm-label .code::before,.expressive-code .ec-line.ins.tm-label .code::before,.expressive-code .ec-line.del.tm-label .code::before{background:var(--ecLineBrdCol);padding:0 calc(var(--ec-tm-lineMarkerLabelPadInl) + var(--ec-tm-lineMarkerAccentWd)) 0 var(--ec-tm-lineMarkerLabelPadInl);color:var(--ec-tm-lineMarkerLabelCol)}.expressive-code .ec-line mark{--tmInlineBgCol:var(--ec-tm-markBg);--tmInlineBrdCol:var(--ec-tm-markBrdCol)}.expressive-code .ec-line ins{--tmInlineBgCol:var(--ec-tm-insBg);--tmInlineBrdCol:var(--ec-tm-insBrdCol)}.expressive-code .ec-line del{--tmInlineBgCol:var(--ec-tm-delBg);--tmInlineBrdCol:var(--ec-tm-delBrdCol)}.expressive-code .ec-line mark,.expressive-code .ec-line ins,.expressive-code .ec-line del{all:unset;display:inline-block;position:relative;--tmBrdL:var(--ec-tm-inlMarkerBrdWd);--tmBrdR:var(--ec-tm-inlMarkerBrdWd);--tmRadL:var(--ec-tm-inlMarkerBrdRad);--tmRadR:var(--ec-tm-inlMarkerBrdRad);margin-inline:0.025rem;padding-inline:var(--ec-tm-inlMarkerPad);border-radius:var(--tmRadL) var(--tmRadR) var(--tmRadR) var(--tmRadL);background:var(--tmInlineBgCol);background-clip:padding-box}.expressive-code .ec-line mark.open-start,.expressive-code .ec-line ins.open-start,.expressive-code .ec-line del.open-start{margin-inline-start:0;padding-inline-start:0;--tmBrdL:0px;--tmRadL:0}.expressive-code .ec-line mark.open-end,.expressive-code .ec-line ins.open-end,.expressive-code .ec-line del.open-end{margin-inline-end:0;padding-inline-end:0;--tmBrdR:0px;--tmRadR:0}.expressive-code .ec-line mark::before,.expressive-code .ec-line ins::before,.expressive-code .ec-line del::before{content:&apos;&apos;;position:absolute;pointer-events:none;display:inline-block;inset:0;border-radius:var(--tmRadL) var(--tmRadR) var(--tmRadR) var(--tmRadL);border:var(--ec-tm-inlMarkerBrdWd) solid var(--tmInlineBrdCol);border-inline-width:var(--tmBrdL) var(--tmBrdR)}.expressive-code .frame{all:unset;position:relative;display:block;--header-border-radius:calc(var(--ec-brdRad) + var(--ec-brdWd));--tab-border-radius:calc(var(--ec-frm-edTabBrdRad) + var(--ec-brdWd));--button-spacing:0.4rem;--code-background:var(--ec-frm-edBg);border-radius:var(--header-border-radius);box-shadow:var(--ec-frm-frameBoxShdCssVal)}.expressive-code .frame .header{display:none;z-index:1;position:relative;border-radius:var(--header-border-radius) var(--header-border-radius) 0 0}.expressive-code .frame.has-title pre,.expressive-code .frame.has-title code,.expressive-code .frame.is-terminal pre,.expressive-code .frame.is-terminal code{border-top:none;border-top-left-radius:0;border-top-right-radius:0}.expressive-code .frame .title:empty:before{content:&apos;\a0&apos;}.expressive-code .frame.has-title:not(.is-terminal){--button-spacing:calc(1.9rem + 2 * (var(--ec-uiPadBlk) + var(--ec-frm-edActTabIndHt)))}.expressive-code .frame.has-title:not(.is-terminal) .title{position:relative;color:var(--ec-frm-edActTabFg);background:var(--ec-frm-edActTabBg);background-clip:padding-box;margin-block-start:var(--ec-frm-edTabsMargBlkStart);padding:calc(var(--ec-uiPadBlk) + var(--ec-frm-edActTabIndHt)) var(--ec-uiPadInl);border:var(--ec-brdWd) solid var(--ec-frm-edActTabBrdCol);border-radius:var(--tab-border-radius) var(--tab-border-radius) 0 0;border-bottom:none;overflow:hidden}.expressive-code .frame.has-title:not(.is-terminal) .title::after{content:&apos;&apos;;position:absolute;pointer-events:none;inset:0;border-top:var(--ec-frm-edActTabIndHt) solid var(--ec-frm-edActTabIndTopCol);border-bottom:var(--ec-frm-edActTabIndHt) solid var(--ec-frm-edActTabIndBtmCol)}.expressive-code .frame.has-title:not(.is-terminal) .header{display:flex;background:linear-gradient(to top, var(--ec-frm-edTabBarBrdBtmCol) var(--ec-brdWd), transparent var(--ec-brdWd)),linear-gradient(var(--ec-frm-edTabBarBg), var(--ec-frm-edTabBarBg));background-repeat:no-repeat;padding-inline-start:var(--ec-frm-edTabsMargInlStart)}.expressive-code .frame.has-title:not(.is-terminal) .header::before{content:&apos;&apos;;position:absolute;pointer-events:none;inset:0;border:var(--ec-brdWd) solid var(--ec-frm-edTabBarBrdCol);border-radius:inherit;border-bottom:none}.expressive-code .frame.is-terminal{--button-spacing:calc(1.9rem + var(--ec-brdWd) + 2 * var(--ec-uiPadBlk));--code-background:var(--ec-frm-trmBg)}.expressive-code .frame.is-terminal .header{display:flex;align-items:center;justify-content:center;padding-block:var(--ec-uiPadBlk);padding-block-end:calc(var(--ec-uiPadBlk) + var(--ec-brdWd));position:relative;font-weight:500;letter-spacing:0.025ch;color:var(--ec-frm-trmTtbFg);background:var(--ec-frm-trmTtbBg);border:var(--ec-brdWd) solid var(--ec-brdCol);border-bottom:none}.expressive-code .frame.is-terminal .header::before{content:&apos;&apos;;position:absolute;pointer-events:none;left:var(--ec-uiPadInl);width:2.1rem;height:0.56rem;line-height:0;background-color:var(--ec-frm-trmTtbDotsFg);opacity:var(--ec-frm-trmTtbDotsOpa);-webkit-mask-image:var(--ec-frm-trmIcon);-webkit-mask-repeat:no-repeat;mask-image:var(--ec-frm-trmIcon);mask-repeat:no-repeat}.expressive-code .frame.is-terminal .header::after{content:&apos;&apos;;position:absolute;pointer-events:none;inset:0;border-bottom:var(--ec-brdWd) solid var(--ec-frm-trmTtbBrdBtmCol)}.expressive-code .frame pre{background:var(--code-background)}.expressive-code .copy{display:flex;gap:0.25rem;flex-direction:row;position:absolute;inset-block-start:calc(var(--ec-brdWd) + var(--button-spacing));inset-inline-end:calc(var(--ec-brdWd) + var(--ec-uiPadInl) / 2)}@media (scripting: none){.expressive-code .copy{display:none}}.expressive-code .copy{direction:ltr;unicode-bidi:isolate}.expressive-code .copy button{position:relative;align-self:flex-end;margin:0;padding:0;border:none;border-radius:0.2rem;z-index:1;cursor:pointer;transition-property:opacity, background, border-color;transition-duration:0.2s;transition-timing-function:cubic-bezier(0.25, 0.46, 0.45, 0.94);width:2.5rem;height:2.5rem;background:var(--code-background);opacity:0.75}.expressive-code .copy button div{position:absolute;inset:0;border-radius:inherit;background:var(--ec-frm-inlBtnBg);opacity:var(--ec-frm-inlBtnBgIdleOpa);transition-property:inherit;transition-duration:inherit;transition-timing-function:inherit}.expressive-code .copy button::before{content:&apos;&apos;;position:absolute;pointer-events:none;inset:0;border-radius:inherit;border:var(--ec-brdWd) solid var(--ec-frm-inlBtnBrd);opacity:var(--ec-frm-inlBtnBrdOpa)}.expressive-code .copy button::after{content:&apos;&apos;;position:absolute;pointer-events:none;inset:0;background-color:var(--ec-frm-inlBtnFg);-webkit-mask-image:var(--ec-frm-copyIcon);-webkit-mask-repeat:no-repeat;mask-image:var(--ec-frm-copyIcon);mask-repeat:no-repeat;margin:0.475rem;line-height:0}.expressive-code .copy button:hover,.expressive-code .copy button:focus:focus-visible{opacity:1}.expressive-code .copy button:hover div,.expressive-code .copy button:focus:focus-visible div{opacity:var(--ec-frm-inlBtnBgHoverOrFocusOpa)}.expressive-code .copy button:active{opacity:1}.expressive-code .copy button:active div{opacity:var(--ec-frm-inlBtnBgActOpa)}.expressive-code .copy .feedback{--tooltip-arrow-size:0.35rem;--tooltip-bg:var(--ec-frm-tooltipSuccessBg);color:var(--ec-frm-tooltipSuccessFg);pointer-events:none;user-select:none;-webkit-user-select:none;position:relative;align-self:center;background-color:var(--tooltip-bg);z-index:99;padding:0.125rem 0.75rem;border-radius:0.2rem;margin-inline-end:var(--tooltip-arrow-size);opacity:0;transition-property:opacity, transform;transition-duration:0.2s;transition-timing-function:ease-in-out;transform:translate3d(0, 0.25rem, 0)}.expressive-code .copy .feedback::after{content:&apos;&apos;;position:absolute;pointer-events:none;top:calc(50% - var(--tooltip-arrow-size));inset-inline-end:calc(-2 * (var(--tooltip-arrow-size) - 0.5px));border:var(--tooltip-arrow-size) solid transparent;border-inline-start-color:var(--tooltip-bg)}.expressive-code .copy .feedback.show{opacity:1;transform:translate3d(0, 0, 0)}@media (hover: hover){.expressive-code{}.expressive-code .copy button{opacity:0;width:2rem;height:2rem}.expressive-code .frame:hover .copy button:not(:hover),.expressive-code .frame:focus-within :focus-visible ~ .copy button:not(:hover),.expressive-code .frame .copy .feedback.show ~ button:not(:hover){opacity:0.75}}.expressive-code :nth-child(1 of .ec-line) .code{padding-inline-end:calc(2rem + var(--ec-codePadInl))}:root{--ec-brdRad:0.75rem;--ec-brdWd:1.5px;--ec-brdCol:var(--code-line);--ec-codeFontFml:var(--font-code);--ec-codeFontSize:0.875rem;--ec-codeFontWg:400;--ec-codeLineHt:1.75;--ec-codePadBlk:1rem;--ec-codePadInl:1.125rem;--ec-codeBg:var(--code-bg);--ec-codeFg:#e6edf3;--ec-codeSelBg:#264f78;--ec-gtrFg:#6e7681;--ec-gtrBrdCol:#6e768133;--ec-gtrBrdWd:1.5px;--ec-gtrHlFg:#e6edf3;--ec-uiFontFml:var(--font-mono);--ec-uiFontSize:0.75rem;--ec-uiFontWg:400;--ec-uiLineHt:1.65;--ec-uiPadBlk:0.25rem;--ec-uiPadInl:1rem;--ec-uiSelBg:#6e768166;--ec-uiSelFg:#e6edf3;--ec-focusBrd:#1f6feb;--ec-sbThumbCol:#8b949e33;--ec-sbThumbHoverCol:#8b949e3d;--ec-tm-lineMarkerAccentMarg:0rem;--ec-tm-lineMarkerAccentWd:0.15rem;--ec-tm-lineMarkerLabelPadInl:0.2rem;--ec-tm-lineMarkerLabelCol:white;--ec-tm-lineDiffIndMargLeft:0.3rem;--ec-tm-inlMarkerBrdWd:1.5px;--ec-tm-inlMarkerBrdRad:0.2rem;--ec-tm-inlMarkerPad:0.15rem;--ec-tm-insDiffIndContent:&apos;+&apos;;--ec-tm-delDiffIndContent:&apos;-&apos;;--ec-tm-markBg:#264a8980;--ec-tm-markBrdCol:#5570b3d0;--ec-tm-insBg:#26561c80;--ec-tm-insBrdCol:#4e7e41d0;--ec-tm-insDiffIndCol:#7eb070d0;--ec-tm-delBg:#81322b80;--ec-tm-delBrdCol:#ae594fd0;--ec-tm-delDiffIndCol:#e68a7ed0;--ec-frm-shdCol:#0000005b;--ec-frm-frameBoxShdCssVal:none;--ec-frm-edActTabBg:var(--code-bg);--ec-frm-edActTabFg:var(--code-muted);--ec-frm-edActTabBrdCol:transparent;--ec-frm-edActTabIndHt:1.5px;--ec-frm-edActTabIndTopCol:transparent;--ec-frm-edActTabIndBtmCol:#0d1117;--ec-frm-edTabsMargInlStart:0;--ec-frm-edTabsMargBlkStart:0;--ec-frm-edTabBrdRad:0.75rem;--ec-frm-edTabBarBg:var(--code-bg);--ec-frm-edTabBarBrdCol:var(--code-line);--ec-frm-edTabBarBrdBtmCol:var(--code-line);--ec-frm-edBg:var(--code-bg);--ec-frm-trmTtbFg:var(--code-muted);--ec-frm-trmTtbDotsFg:var(--code-muted);--ec-frm-trmTtbDotsOpa:0.15;--ec-frm-trmTtbBg:var(--code-bg);--ec-frm-trmTtbBrdBtmCol:var(--code-line);--ec-frm-trmBg:var(--code-bg);--ec-frm-inlBtnBg:var(--code-ink);--ec-frm-inlBtnBgIdleOpa:0;--ec-frm-inlBtnBgHoverOrFocusOpa:0.2;--ec-frm-inlBtnBgActOpa:0.3;--ec-frm-inlBtnFg:var(--code-ink);--ec-frm-inlBtnBrd:var(--code-line);--ec-frm-inlBtnBrdOpa:0.4;--ec-frm-tooltipSuccessBg:var(--color-emerald);--ec-frm-tooltipSuccessFg:var(--color-bg);--ec-frm-copyIcon:url(&quot;data:image/svg+xml,%3Csvg%20xmlns%3D&apos;http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg&apos;%20viewBox%3D&apos;0%200%2024%2024&apos;%20fill%3D&apos;none&apos;%20stroke%3D&apos;black&apos;%20stroke-width%3D&apos;1.75&apos;%3E%3Cpath%20d%3D&apos;M3%2019a2%202%200%200%201-1-2V2a2%202%200%200%201%201-1h13a2%202%200%200%201%202%201&apos;%2F%3E%3Crect%20x%3D&apos;6&apos;%20y%3D&apos;5&apos;%20width%3D&apos;16&apos;%20height%3D&apos;18&apos;%20rx%3D&apos;1.5&apos;%20ry%3D&apos;1.5&apos;%2F%3E%3C%2Fsvg%3E&quot;);--ec-frm-trmIcon:url(&quot;data:image/svg+xml,%3Csvg%20xmlns%3D&apos;http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg&apos;%20viewBox%3D&apos;0%200%2060%2016&apos;%20preserveAspectRatio%3D&apos;xMidYMid%20meet&apos;%3E%3Ccircle%20cx%3D&apos;8&apos;%20cy%3D&apos;8&apos;%20r%3D&apos;8&apos;%2F%3E%3Ccircle%20cx%3D&apos;30&apos;%20cy%3D&apos;8&apos;%20r%3D&apos;8&apos;%2F%3E%3Ccircle%20cx%3D&apos;52&apos;%20cy%3D&apos;8&apos;%20r%3D&apos;8&apos;%2F%3E%3C%2Fsvg%3E&quot;)}.expressive-code .ec-line :where(span[style^=&apos;--&apos;]:not([class])){color:var(--0, inherit);background-color:var(--0bg, transparent);font-style:var(--0fs, inherit);font-weight:var(--0fw, inherit);text-decoration:var(--0td, inherit)}&lt;/style&gt;&lt;script type=&quot;module&quot; src=&quot;/_astro/ec.0vx5m.js&quot;&gt;&lt;/script&gt;&lt;figure class=&quot;frame has-title&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;TypeScript&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;typescript&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;type&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FFA657&quot;&gt;SagaStep&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#FFA657&quot;&gt;name&lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;string&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#D2A8FF&quot;&gt;action&lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; () &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;=&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FFA657&quot;&gt;Promise&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;any&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#D2A8FF&quot;&gt;compensate&lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; () &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;=&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FFA657&quot;&gt;Promise&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;any&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;};&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;export&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FFA657&quot;&gt;SagaOrchestrator&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;private&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FFA657&quot;&gt;steps&lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FFA657&quot;&gt;SagaStep&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;[] &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; [];&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;private&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FFA657&quot;&gt;executedSteps&lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FFA657&quot;&gt;SagaStep&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;[] &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; [];&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#8B949E&quot;&gt;// সাগাতে নতুন স্টেপ এবং তার রিভার্স লজিক রেজিস্টার করা&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D2A8FF&quot;&gt;addStep&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#FFA657&quot;&gt;name&lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;string&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#D2A8FF&quot;&gt;action&lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; () &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;=&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FFA657&quot;&gt;Promise&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;any&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#D2A8FF&quot;&gt;compensate&lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; () &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;=&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FFA657&quot;&gt;Promise&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;any&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;&gt;)&lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;void&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;this&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;.steps.&lt;/span&gt;&lt;span style=&quot;--0:#D2A8FF&quot;&gt;push&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;({ name, action, compensate });&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#8B949E&quot;&gt;// সাগা এক্সিকিউট করা এবং ফেইলর হলে ব্যাকওয়ার্ড রিকভারি চালানো&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;async&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D2A8FF&quot;&gt;execute&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#FFA657&quot;&gt;sagaId&lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;string&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FFA657&quot;&gt;Promise&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;boolean&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;console.&lt;/span&gt;&lt;span style=&quot;--0:#D2A8FF&quot;&gt;log&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;`[Saga Engine] Starting Saga Execution: ${&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;sagaId&lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;}`&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;for&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;step&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;of&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;this&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;.steps) {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;try&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;console.&lt;/span&gt;&lt;span style=&quot;--0:#D2A8FF&quot;&gt;log&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;`[Saga Engine] Executing Step: ${&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;step&lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;name&lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;}`&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;await&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; step.&lt;/span&gt;&lt;span style=&quot;--0:#D2A8FF&quot;&gt;action&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#8B949E&quot;&gt;// সফল হলে স্টেপটি এক্সিকিউটেড লিস্টে জমা করা হবে&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;this&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;.executedSteps.&lt;/span&gt;&lt;span style=&quot;--0:#D2A8FF&quot;&gt;push&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;(step);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;} &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;catch&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; (error) {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;console.&lt;/span&gt;&lt;span style=&quot;--0:#D2A8FF&quot;&gt;error&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;`[Saga Engine] Step Failed: ${&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;step&lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;name&lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;}. Triggering Backward Recovery!`&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;, error);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;await&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;this&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#D2A8FF&quot;&gt;rollback&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;(sagaId);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;false&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;console.&lt;/span&gt;&lt;span style=&quot;--0:#D2A8FF&quot;&gt;log&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;`[Saga Engine] Saga Execution Completed Successfully: ${&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;sagaId&lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;}`&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;true&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#8B949E&quot;&gt;// রিভার্স অর্ডারে কম্পেনসেটিং ট্রানজেকশন চালানো&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;private&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;async&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D2A8FF&quot;&gt;rollback&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#FFA657&quot;&gt;sagaId&lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;string&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FFA657&quot;&gt;Promise&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;void&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;console.&lt;/span&gt;&lt;span style=&quot;--0:#D2A8FF&quot;&gt;log&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;`[Saga Engine] Starting Rollback for Saga: ${&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;sagaId&lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;}`&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#8B949E&quot;&gt;// এক্সিকিউটেড লিস্ট রিভার্স করে শেষের স্টেপ থেকে শুরুতে আসা&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;reversedSteps&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; [&lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;...&lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;this&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;.executedSteps].&lt;/span&gt;&lt;span style=&quot;--0:#D2A8FF&quot;&gt;reverse&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;for&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;step&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;of&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; reversedSteps) {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;try&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;console.&lt;/span&gt;&lt;span style=&quot;--0:#D2A8FF&quot;&gt;log&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;`[Saga Engine] Compensating Step: ${&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;step&lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;name&lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;}`&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;await&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; step.&lt;/span&gt;&lt;span style=&quot;--0:#D2A8FF&quot;&gt;compensate&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;} &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;catch&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; (compensateError) {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#8B949E&quot;&gt;// কম্পেনসেটিং স্টেপ ফেইল করলে এটি Dead Letter Queue (DLQ)-তে পাঠাতে হবে&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;console.&lt;/span&gt;&lt;span style=&quot;--0:#D2A8FF&quot;&gt;error&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;`[CRITICAL] Compensation Failed for Step: ${&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;step&lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;name&lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;}. Manual intervention required!`&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;, compensateError);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;type SagaStep = {  name: string;  action: () =&gt; Promise&lt;any&gt;;  compensate: () =&gt; Promise&lt;any&gt;;};export class SagaOrchestrator {  private steps: SagaStep[] = [];  private executedSteps: SagaStep[] = [];  // সাগাতে নতুন স্টেপ এবং তার রিভার্স লজিক রেজিস্টার করা  public addStep(name: string, action: () =&gt; Promise&lt;any&gt;, compensate: () =&gt; Promise&lt;any&gt;): void {    this.steps.push({ name, action, compensate });  }  // সাগা এক্সিকিউট করা এবং ফেইলর হলে ব্যাকওয়ার্ড রিকভারি চালানো  public async execute(sagaId: string): Promise&lt;boolean&gt; {    console.log(&amp;#x60;[Saga Engine] Starting Saga Execution: ${sagaId}&amp;#x60;);    for (const step of this.steps) {      try {        console.log(&amp;#x60;[Saga Engine] Executing Step: ${step.name}&amp;#x60;);        await step.action();        // সফল হলে স্টেপটি এক্সিকিউটেড লিস্টে জমা করা হবে        this.executedSteps.push(step);      } catch (error) {        console.error(&amp;#x60;[Saga Engine] Step Failed: ${step.name}. Triggering Backward Recovery!&amp;#x60;, error);        await this.rollback(sagaId);        return false;      }    }    console.log(&amp;#x60;[Saga Engine] Saga Execution Completed Successfully: ${sagaId}&amp;#x60;);    return true;  }  // রিভার্স অর্ডারে কম্পেনসেটিং ট্রানজেকশন চালানো  private async rollback(sagaId: string): Promise&lt;void&gt; {    console.log(&amp;#x60;[Saga Engine] Starting Rollback for Saga: ${sagaId}&amp;#x60;);    // এক্সিকিউটেড লিস্ট রিভার্স করে শেষের স্টেপ থেকে শুরুতে আসা    const reversedSteps = [...this.executedSteps].reverse();    for (const step of reversedSteps) {      try {        console.log(&amp;#x60;[Saga Engine] Compensating Step: ${step.name}&amp;#x60;);        await step.compensate();      } catch (compensateError) {        // কম্পেনসেটিং স্টেপ ফেইল করলে এটি Dead Letter Queue (DLQ)-তে পাঠাতে হবে        console.error(&amp;#x60;[CRITICAL] Compensation Failed for Step: ${step.name}. Manual intervention required!&amp;#x60;, compensateError);      }    }  }}&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;ধাপ ২: Idempotent Compensations এবং Composite Key Design&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;ডিস্ট্রিবিউটেড সিস্টেমে নেটওয়ার্ক রিট্রাইয়ের কারণে আপনার কম্পেনসেটিং কমান্ড (যেমন: &lt;code&gt;cancelInventory&lt;/code&gt;) একই সার্ভিসে একাধিকবার পৌঁছাতে পারে। যদি আপনার লজিক ইডেমপোটent না হয়, তবে ডেটাবেজ ভুল করে দুইবার স্টক বাড়িয়ে দেবে। এটি ঠেকানোর জন্য আমাদের ইউনিক সাগা আইডি (&lt;code&gt;saga_id&lt;/code&gt;) এবং কম্পোজিট কী ব্যবহার করে ডেটাবেজ গার্ড তৈরি করতে হবে।&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame has-title&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;TypeScript&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;typescript&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; { PrismaClient } &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;&apos;@prisma/client&apos;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;prisma&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D2A8FF&quot;&gt;PrismaClient&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;async&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;function&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D2A8FF&quot;&gt;compensateInventory&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#FFA657&quot;&gt;sagaId&lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;string&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#FFA657&quot;&gt;productId&lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;string&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#FFA657&quot;&gt;quantity&lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;number&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;) {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#8B949E&quot;&gt;// একটি একক ট্রানজেকশনে ইডেমপোটেন্সি চেক এবং স্টক রিস্টোর করা&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;await&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; prisma.&lt;/span&gt;&lt;span style=&quot;--0:#D2A8FF&quot;&gt;$transaction&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;async&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;--0:#FFA657&quot;&gt;tx&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;=&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#8B949E&quot;&gt;// ১. চেক করা এই সাগা আইডির জন্য রোলব্যাক ইতোমধ্যে হয়েছে কিনা&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;existingCompensation&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;await&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; tx.compensation_logs.&lt;/span&gt;&lt;span style=&quot;--0:#D2A8FF&quot;&gt;findUnique&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;({&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;where: {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;saga_id_step_name: {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;          &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;saga_id: sagaId,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;          &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;step_name: &lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;&apos;INVENTORY_DEDUCT_COMPENSATION&apos;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;},&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;},&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;});&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;if&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; (existingCompensation) {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;console.&lt;/span&gt;&lt;span style=&quot;--0:#D2A8FF&quot;&gt;log&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;`[Idempotency Guard] Compensation already processed for Saga: ${&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;sagaId&lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;}. Skipping.`&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#8B949E&quot;&gt;// ২. স্টক রিস্টোর করা&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;await&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; tx.products.&lt;/span&gt;&lt;span style=&quot;--0:#D2A8FF&quot;&gt;update&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;({&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;where: { id: productId },&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;data: { stock: { increment: quantity } },&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;});&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#8B949E&quot;&gt;// ৩. কম্পেনসেটিং লগ এন্ট্রি করা যাতে পরবর্তীতে ডুপ্লিকেট রিকোয়েস্ট ব্লক হয়&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;await&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; tx.compensation_logs.&lt;/span&gt;&lt;span style=&quot;--0:#D2A8FF&quot;&gt;create&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;({&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;data: {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;saga_id: sagaId,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;step_name: &lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;&apos;INVENTORY_DEDUCT_COMPENSATION&apos;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;processed_at: &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D2A8FF&quot;&gt;Date&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;(),&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;},&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;});&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;console.&lt;/span&gt;&lt;span style=&quot;--0:#D2A8FF&quot;&gt;log&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;`[Saga Engine] Inventory successfully restored for Product: ${&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;productId&lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;}`&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;});&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;import { PrismaClient } from &amp;#x27;@prisma/client&amp;#x27;;const prisma = new PrismaClient();async function compensateInventory(sagaId: string, productId: string, quantity: number) {  // একটি একক ট্রানজেকশনে ইডেমপোটেন্সি চেক এবং স্টক রিস্টোর করা  return await prisma.$transaction(async (tx) =&gt; {    // ১. চেক করা এই সাগা আইডির জন্য রোলব্যাক ইতোমধ্যে হয়েছে কিনা    const existingCompensation = await tx.compensation_logs.findUnique({      where: {        saga_id_step_name: {          saga_id: sagaId,          step_name: &amp;#x27;INVENTORY_DEDUCT_COMPENSATION&amp;#x27;,        },      },    });    if (existingCompensation) {      console.log(&amp;#x60;[Idempotency Guard] Compensation already processed for Saga: ${sagaId}. Skipping.&amp;#x60;);      return;    }    // ২. স্টক রিস্টোর করা    await tx.products.update({      where: { id: productId },      data: { stock: { increment: quantity } },    });    // ৩. কম্পেনসেটিং লগ এন্ট্রি করা যাতে পরবর্তীতে ডুপ্লিকেট রিকোয়েস্ট ব্লক হয়    await tx.compensation_logs.create({      data: {        saga_id: sagaId,        step_name: &amp;#x27;INVENTORY_DEDUCT_COMPENSATION&amp;#x27;,        processed_at: new Date(),      },    });    console.log(&amp;#x60;[Saga Engine] Inventory successfully restored for Product: ${productId}&amp;#x60;);  });}&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;h2 id=&quot;৭-distributed-isolation-anomalies-the-hidden-traps&quot;&gt;৭. Distributed Isolation Anomalies: The Hidden Traps&lt;/h2&gt;
&lt;p&gt;যেহেতু সাগা প্যাটার্নে কোনো গ্লোবাল ডেটাবেজ লক থাকে না, তাই ইন্টারমিডিয়েট বা আংশিক স্টেটগুলো অন্য কোনো সমসাময়িক ট্রানজেকশন দেখে ফেলতে পারে। এই আইসোলেশন না থাকার কারণে সিস্টেমে কিছু মারাত্মক Concurrency Anomaly বা ফাঁদ তৈরি হয়:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Lost Updates:&lt;/strong&gt; ধরুন, সাগা A কোনো ইউজারের ক্রেডিট লিমিট চেক করে সাময়িকভাবে ১০০ টাকা কমালো। ঠিক একই সময়ে সাগা B এসে ওই ইউজারের ক্রেডিট লিমিট আপডেট করে দিল। এখন যদি সাগা A ফেইল করে এবং রোলব্যাক চালাতে যায়, তবে সে সাগা B-এর আপডেট করা ডেটা ওভাররাইট করে আগের ডেটা বসিয়ে দেবে। ফলে সাগা B-এর আপডেটটি চিরতরে হারিয়ে যাবে।&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Dirty Reads:&lt;/strong&gt; সাগা মাঝপথে থাকা অবস্থায় (যেমন: পেমেন্ট সফল হয়েছে কিন্তু ইনভেন্টরি চেক পেন্ডিং) অন্য কোনো সাধারণ ইউজার বা ট্রানজেকশন সেই আন-কমিটেড প্রোডাক্ট স্টকে আছে দেখে অর্ডার করে ফেলল। পরবর্তীতে সাগাটি ফেইল করে রোলব্যাক হয়ে গেল। ফলে দ্বিতীয় ইউজার এমন একটি প্রোডাক্ট অর্ডার করে বসল যা বাস্তবে স্টকেই ছিল না।&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;এই আইসোলেশন সমস্যাগুলো দূর করার জন্য আমাদের প্রোডাকশন সিস্টেমে কিছু বিশেষ Architectural Countermeasure বা প্রতিরোধমূলক ব্যবস্থা নিতে হয়:&lt;/p&gt;
&lt;p&gt;১. &lt;strong&gt;Semantic Lock:&lt;/strong&gt; আমরা ডেটাবেজ ইঞ্জিনের রো-লেভেল লকের ওপর নির্ভর না করে বিজনেস লজিক লেভেলে একটি লক তৈরি করি। যেমন: অর্ডারের স্ট্যাটাস সরাসরি &lt;code&gt;ACTIVE&lt;/code&gt; না করে আমরা কলামে &lt;code&gt;PENDING_CHECKOUT&lt;/code&gt;, &lt;code&gt;RESERVED&lt;/code&gt;, বা &lt;code&gt;LOCK_ACQUIRED&lt;/code&gt; স্টেট সেট করি। অন্য কোনো ট্রানজেকশন যখন এই রেকর্ড রিড করতে আসবে, সে স্ট্যাটাস দেখেই বুঝতে পারবে যে একটি সাগা ট্রানজেকশন চলছে এবং সে ওই ডেটায় হাত দেবে না।&lt;/p&gt;
&lt;p&gt;২. &lt;strong&gt;Pessimistic View:&lt;/strong&gt; আমরা আমাদের রিড এপিআইগুলোকে এমনভাবে ডিজাইন করি যেন তারা সবসময় একটি পেসিমিস্টিক বা কনজারভেটিভ ভিউ প্রদান করে। যেমন: ইউজারের ব্যালেন্স দেখানোর সময় আমরা &lt;code&gt;Actual Balance&lt;/code&gt; থেকে &lt;code&gt;Reserved Balance&lt;/code&gt; বাদ দিয়ে শুধুমাত্র &lt;code&gt;Available Balance&lt;/code&gt; প্রদর্শন করি। এতে সাগা ফেইল বা রোলব্যাক হলেও ইউজারের কনকারেন্ট এক্সপেরিয়েন্সে কোনো সমস্যা হয় না।&lt;/p&gt;
&lt;h2 id=&quot;৮-প্রোডাকশন-সতর্কতা-ও-সুরক্ষাকবচ&quot;&gt;৮. প্রোডাকশন সতর্কতা ও সুরক্ষাকবচ&lt;/h2&gt;
&lt;div class=&quot;callout&quot; role=&quot;note&quot; data-type=&quot;danger&quot;&gt;
&lt;p class=&quot;callout-title&quot;&gt;&lt;strong&gt;The Infinite Rollback Loop&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;আপনার কম্পেনসেটিং ট্রানজেকশন (Rollback Function) যেন কোনোভাবেই নিজে কোনো আনহ্যান্ডেলড এক্সেপশন থ্রো না করে। যদি রোলব্যাক ফাংশন নিজেই ডেটাবেজ এরর বা বিজনেস লজিক এক্সেপশনের কারণে ক্র্যাশ করে, তবে সিস্টেম একটি ইনফিনিট রিট্রাই লুপে আটকে যাবে এবং ডেটা পার্মানেন্টলি আনব্যালেন্সড হয়ে পড়বে। কম্পেনসেটিং লজিক সবসময় ফল্ট-টল্যারেন্ট হতে হবে এবং প্রয়োজনে ফলব্যাক হিসেবে Dead Letter Queue (DLQ) ব্যবহার করতে হবে।&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;callout&quot; role=&quot;note&quot; data-type=&quot;warning&quot;&gt;
&lt;p class=&quot;callout-title&quot;&gt;&lt;strong&gt;Asynchronous Deadlocks in Choreography&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;কোরিওগ্রাফি সাগাতে কখনোই সাইক্লিক ডিপেন্ডেন্সি তৈরি করবেন না (যেমন: Service A ইভেন্ট পাঠায় B-কে, B পাঠায় C-কে, এবং C আবার পাঠায় A-কে)। নেটওয়ার্ক স্পাইক বা হাই-থ্রুপুট লোডের সময় এটি ডিস্ট্রিবিউটেড ডেডলক তৈরি করে ব্রোকার বাফার ক্র্যাশ করাবে। ইভেন্ট ফ্লো সবসময় একমুখী (Unidirectional) বা ট্রি-স্ট্রাকচারড হতে হবে।&lt;/p&gt;
&lt;/div&gt;
&lt;h2 id=&quot;৯-summary-production-decision-rules&quot;&gt;৯. Summary &amp;#x26; Production Decision Rules&lt;/h2&gt;
&lt;p&gt;পুরো Deep Dive থেকে আমরা দেখতে পেলাম যে ডিস্ট্রিবিউটেড সাগা কোনো সাধারণ কোডিং প্যাটার্ন নয়, এটি একটি সম্পূর্ণ আর্কিটেকচারাল প্যারাডাইম শিফট। আপনার প্রোডাকশন সিস্টেমে এই প্যাটার্নটি সঠিক উপায়ে প্রয়োগ করার জন্য নিচের সিদ্ধান্ত রুলসগুলো মেনে চলুন:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;আর্কিটেকচারাল সিলেকশন ফ্রেমওয়ার্ক:&lt;/strong&gt; আপনার সিস্টেমে যদি ২ থেকে ৪টি মাইক্রোসার্ভিস থাকে এবং তাদের ওয়ার্কফ্লো খুব সহজ হয়, তবে Choreography মডেল ব্যবহার করুন। কিন্তু সার্ভিসের সংখ্যা যদি ৫-এর বেশি হয়, অথবা ওয়ার্কফ্লোতে জটিল কন্ডিশনাল লজিক ও টাইমআউট থাকে, তবে কোনো চিন্তা ছাড়াই Orchestration (যেমন: Temporal) বেছে নিন। সেন্ট্রাল ভিজিবিলিটি ছাড়া লার্জ-স্কেল সাগা ডিবাগ করা অসম্ভব।&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;রিলিজ অ্যান্ড ট্র্যাকিং মেকানিজম:&lt;/strong&gt; ডিস্ট্রিবিউটেড সাগা আর্কিটেকচার ইমপ্লিমেন্ট করার পর প্রোডাকশন এনভায়রনমেন্টে Observability নিশ্চিত করা মাস্ট। প্রতিটি রিকোয়েস্টের শুরুতে একটি ইউনিক &lt;code&gt;trace_id&lt;/code&gt; বা &lt;code&gt;saga_id&lt;/code&gt; জেনারেট করুন এবং OpenTelemetry ব্যবহার করে প্রতিটি মাইক্রোসার্ভিসের লগ ও ইভেন্টে সেই আইডি প্রোপাগেট করুন। এতে কোনো ট্রানজেকশন ফেইল করলে ডিস্ট্রিবিউটেড ট্রেসিং ড্যাশবোর্ড থেকে এক সেকেন্ডেই বের করা সম্ভব হবে ঠিক কোন সার্ভিসে এবং কেন রোলব্যাক ট্রিগার হয়েছিল।&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;ডিস্ট্রিবিউটেড সিস্টেমের এই Low-Level মেকানিজমগুলো সঠিকভাবে বুঝতে পারলে এবং আপনার প্রোডাকশন আর্কিটেকচারে ইমপ্লিমেন্ট করতে পারলে, আপনার সিস্টেম যেকোনো নেটওয়ার্ক ফেইলর বা কনকারেন্সি লোড অত্যন্ত সাবলীলভাবে হ্যান্ডেল করতে সক্ষম হবে।&lt;/p&gt;</content:encoded><category>System Design</category><category>Deep Dive</category><category>Distributed Systems</category><category>Microservices</category><category>Saga Pattern</category><category>Compensating Transactions</category><category>System Architecture</category><category>Under the hood</category><category>Kafka</category></item><item><title>দ্য আলটিমেট সিস্টেম ডিজাইন হ্যান্ডবুক: রিয়েল-ওয়ার্ল্ড কেস স্টাডি দিয়ে গ্লোবাল স্কেল আর্কিটেকচার</title><link>https://www.rafeuddaraj.me/bn/blog/ultimate-system-design-handbook-case-study-global-scale/</link><guid isPermaLink="true">https://www.rafeuddaraj.me/bn/blog/ultimate-system-design-handbook-case-study-global-scale/</guid><description>একটি স্টার্টআপ এমভিপি থেকে ১ কোটি ইউজারের গ্লোবাল স্কেল আর্কিটেকচারে রূপান্তরের ৭টি রিয়েল-ওয়ার্ল্ড কেস স্টাডি, ডিস্ট্রিবিউটেড ডেটাবেজ, ক্যাশিং এবং মাইক্রোসার্ভিস প্যাটার্নের পূর্ণাঙ্গ গাইডলাইন।</description><pubDate>Tue, 07 Jul 2026 18:59:54 GMT</pubDate><content:encoded>&lt;p&gt;আমরা যখন নতুন কোনো সফটওয়্যার প্রজেক্ট শুরু করি, তখন আমাদের মূল মনোযোগ থাকে দ্রুত ফিচার ডেভেলপমেন্ট, ক্লিন কোড এবং ইউজার ইন্টারফেসের ওপর। কিন্তু প্রোডাকশন পরিবেশে যখন সত্যিকারের ইউজার ট্রাফিক আসতে শুরু করে, তখনই আমাদের লেখা কোড এবং আর্কিটেকচারের আসল পরীক্ষা শুরু হয়। একটি সাধারণ Monolith অ্যাপ্লিকেশন ১ হাজার ইউজারের লোড খুব সহজেই হ্যান্ডেল করতে পারে, কিন্তু ইউজার সংখ্যা যখন ১০ লাখ বা ১ কোটিতে পৌঁছায়, তখন সিস্টেমের প্রতিটি লেয়ারে Bottleneck বা বাধা তৈরি হয়। সার্ভার ক্র্যাশ করে, Database Lock হয়ে যায় এবং Page Load Time ৩ থেকে ৪ সেকেন্ড পার হয়ে যায়, যা বর্তমান আধুনিক ইন্টারনেটের যুগে সরাসরি ব্যবসায়িক ক্ষতি।&lt;/p&gt;
&lt;p&gt;সিস্টেম ডিজাইন কোনো মুখস্থ করার থিওরিটিক্যাল বিদ্যা নয়, এটি হলো বাস্তব জীবনের ইঞ্জিনিয়ারিং Trade-off অ্যানালাইসিস। এই হ্যান্ডবুকের কোর ফিলোসফি হলো রিয়েল-ওয়ার্ল্ড কেস স্টাডি বিশ্লেষণ করে সমস্যা চিহ্নিত করা এবং তার সঠিক আর্কিটেকচারাল সমাধান বের করা। আমরা কোনো গতানুগতিক সংজ্ঞায় না গিয়ে, একটি কাল্পনিক স্টার্টআপ প্ল্যাটফর্ম &quot;FoodFast&quot; এবং বিশ্বের শীর্ষস্থানীয় প্রযুক্তি প্রতিষ্ঠানগুলোর বাস্তব সিস্টেম ডিজাইনের জার্নি বিশ্লেষণ করব। আপনি যদি একজন সফটওয়্যার ইঞ্জিনিয়ার হিসেবে নিজের স্কিলকে নেক্সট লেভেলে নিয়ে যেতে চান এবং প্রোডাকশন গ্রেড সিস্টেম তৈরি করতে চান, তবে এই হ্যান্ডবুকটি আপনার জন্য একটি স্বয়ংসম্পূর্ণ গাইডলাইন হিসেবে কাজ করবে।&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;ফাউন্ডেশনাল-মেন্টাল-মডেলস-ও-ইঞ্জিনিয়ারিং-অ্যানালজি&quot;&gt;ফাউন্ডেশনাল মেন্টাল মডেলস ও ইঞ্জিনিয়ারিং অ্যানালজি&lt;/h2&gt;
&lt;p&gt;কোডে হাত দেওয়ার আগে পুরো সিস্টেমের স্ট্রাকচার বুঝতে আমাদের কিছু রিয়েল-ওয়ার্ল্ড মেন্টাল মডেল মাথায় রাখতে হবে। আমরা যখন কোনো জটিল সিস্টেম ডিজাইন করি, তখন কিছু মৌলিক প্যাটার্ন বারবার আমাদের সামনে আসে। এই প্যাটার্নগুলোকে সহজভাবে বোঝার জন্য আমরা দৈনন্দিন জীবনের কিছু অ্যানালজি ব্যবহার করতে পারি। নিচে এমন চারটি কোর ইঞ্জিনিয়ারিং কনসেপ্ট এবং তাদের বাস্তব অ্যানালজি আলোচনা করা হলো।&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Vertical vs Horizontal Scaling (লিফট বনাম নতুন সিঁড়ি অ্যানালজি):&lt;/strong&gt; আপনার বিল্ডিংয়ে মানুষ বেড়ে গেলে লিফটের মোটর বড় করা হলো Vertical Scaling বা Scale Up। কিন্তু একটি নির্দিষ্ট সীমার পর লিফটের মোটর আর বড় করা যায় না, কারণ ভৌত সীমাবদ্ধতা থাকে। তখন সেই মোটরের ওপর চাপ না বাড়িয়ে পাশে নতুন সিঁড়ি বা নতুন লিফট বসানো হলো Horizontal Scaling বা Scale Out। সফটওয়্যার ইঞ্জিনিয়ারিংয়ে আমরা একটি মাত্র সার্ভারে আনলিমিটেড CPU বা RAM না বাড়িয়ে একাধিক সাধারণ সার্ভার নেটওয়ার্কে যোগ করি।&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Load Balancer (ট্রাফিক পুলিশ অ্যানালজি):&lt;/strong&gt; রাস্তায় যখন হঠাৎ হাজার হাজার গাড়ি চলে আসে, তখন একজন ট্রাফিক পুলিশ সিগন্যাল দিয়ে বিভিন্ন লেনে গাড়িগুলোকে সমানভাবে ভাগ করে দেয়। আমাদের সফটওয়্যার সিস্টেমেও Load Balancer ঠিক একই কাজ করে। লাখ লাখ ক্লায়েন্ট রিকোয়েস্ট যখন সার্ভারে আঘাত করে, তখন লোড ব্যালেন্সার রাউন্ড-রবিন বা অন্য কোনো অ্যালগরিদম ব্যবহার করে ব্যাকএন্ড সার্ভারগুলোর মধ্যে সেই চাপ সমানভাবে বন্টন করে দেয়।&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Monolith vs Microservices (এক ঘরের রান্নাঘর বনাম ফুড কোর্ট অ্যানালজি):&lt;/strong&gt; Monolith হলো একটি বিশাল ঘরের ভেতর সব ধরনের রান্না ও পরিবেশনের কাজ করা। সেই ঘরের গ্যাস পাইপলাইনে কোনো দুর্ঘটনা ঘটলে পুরো রেস্টুরেন্ট বন্ধ হয়ে যায়। অন্যদিকে Microservices হলো একটি বিশাল ফুড কোর্টের মতো, যেখানে পিৎজা, বার্গার এবং কফির দোকান সম্পূর্ণ আলাদা। কফির দোকানের কফি মেশিন নষ্ট হলেও পিৎজা বিক্রি বন্ধ হয় না, এবং পুরো সিস্টেম সচল থাকে।&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Database Indexing (বইয়ের সূচিপত্র অ্যানালজি):&lt;/strong&gt; ১ হাজার পৃষ্ঠার একটি বই থেকে কোনো নির্দিষ্ট টপিক খুঁজতে পুরো বই প্রথম থেকে শেষ পর্যন্ত পড়া হলো Full Table Scan, যার Time Complexity হলো O(n)। আর বইয়ের পেছনের সূচিপত্র দেখে সরাসরি সেই নির্দিষ্ট পেজে চলে যাওয়া হলো Indexing। ডেটাবেজে আমরা B-Tree ডেটা স্ট্রাকচার ব্যবহার করে এই ইনডেক্সিং করি, যা O(log n) টাইমে কোটি কোটি ডেটার ভেতর থেকে সঠিক তথ্য খুঁজে বের করে।&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id=&quot;কেস-স্টাডি-১-foodfast-এমভিপি-লঞ্চ-ও-প্রথম-১০-হাজার-ইউজার-monolith-separation&quot;&gt;কেস স্টাডি ১: FoodFast এমভিপি লঞ্চ ও প্রথম ১০ হাজার ইউজার (Monolith &amp;#x26; Separation)&lt;/h2&gt;
&lt;p&gt;ধরুন, আপনি &quot;FoodFast&quot; নামের একটি নতুন ফুড ডেলিভারি স্টার্টআপের চিফ আর্কিটেক্ট। আপনাদের প্রাথমিক লক্ষ্য হলো খুব দ্রুত একটি Minimum Viable Product বা MVP তৈরি করে মার্কেটে ভ্যালিডেশন নেওয়া। এই পর্যায়ে আপনাদের বাজেট সীমিত এবং ইঞ্জিনিয়ার সংখ্যাও কম। তাই আপনারা জটিল কোনো ডিস্ট্রিবিউটেড সিস্টেমে না গিয়ে একটি সিঙ্গেল সার্ভার Monolith App এবং একটি সিঙ্গেল Relational Database দিয়ে যাত্রা শুরু করলেন। প্রথম কয়েক মাস সব কিছুই চমৎকার চলছিল, এবং আপনাদের দৈনিক অ্যাক্টিভ ইউজার ছিল মাত্র কয়েক শত। কিন্তু একটি সফল ডিজিটাল মার্কেটিং ক্যাম্পেইনের পর আপনাদের ইউজার সংখ্যা দ্রুত বাড়তে শুরু করে এবং ১০ হাজারে পৌঁছায়।&lt;/p&gt;
&lt;p&gt;ঠিক এই সময়েই আপনাদের সিস্টেমে প্রথম বড় ধরনের ইঞ্জিনিয়ারিং ক্রাইসিস দেখা দেয়। আপনারা লক্ষ্য করলেন, পিক আওয়ারে অ্যাপ্লিকেশনের Page Load Time অস্বাভাবিকভাবে বেড়ে যাচ্ছে এবং সার্ভারের CPU Utilization ১০০ শতাংশে আটকে থাকছে। এর মূল কারণ হলো, একই মেমরি এবং প্রসেসর থেকে Web Server কোড এক্সিকিউট করছে এবং Database Query প্রসেস করছে। যখন হাজার হাজার ইউজার একসাথে রেস্টুরেন্টের মেনু ব্রাউজ করছে এবং অর্ডার প্লেস করছে, তখন মেমরি এবং Disk I/O Contention শুরু হচ্ছে। অ্যাপ্লিকেশনের Thread Pool ডেটাবেজ থেকে উত্তর আসার অপেক্ষায় ব্লক হয়ে থাকছে, যার ফলে নতুন কোনো ক্লায়েন্ট রিকোয়েস্ট সার্ভার গ্রহণ করতে পারছে না।&lt;/p&gt;
&lt;p&gt;এই প্রাথমিক ক্রাইসিস সমাধানের জন্য আমাদের প্রথম ইঞ্জিনিয়ারিং পদক্ষেপ হলো App and DB Separation। আমরা Web Server এবং Database-কে দুটি আলাদা ফিজিক্যাল বা ভার্চুয়াল মেশিনে আলাদা করে ফেলি। এতে App Server-এর প্রসেসর এবং মেমরি সম্পূর্ণ স্বাধীনভাবে ক্লায়েন্ট রিকোয়েস্ট হ্যান্ডেল করতে পারে এবং ডেটাবেজ তার নিজস্ব ডেডিকেটেড রিসোর্স ব্যবহার করে কুয়েরি প্রসেস করতে পারে। একই সাথে আমরা Vertical Scaling বা সার্ভারের Hardware Upgradation প্রয়োগ করি। আমরা App Server-এর কনফিগারেশন ৪ কোর CPU থেকে ১৬ কোর CPU-তে আপগ্রেড করি এবং ডেটাবেজ সার্ভারের RAM ১৬ গিগাবাইট থেকে ৬৪ গিগাবাইটে উন্নীত করি। এই পরিবর্তনের ফলে আমাদের সিস্টেম পুনরায় দ্রুতগতিতে কাজ শুরু করে। নিচে App এবং DB Separation-এর পর একটি প্রোডাকশন-রেডি Connection Pool কনফিগারেশনের উদাহরণ দেওয়া হলো:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;style&gt;.expressive-code{font-family:var(--ec-uiFontFml);font-size:var(--ec-uiFontSize);font-weight:var(--ec-uiFontWg);line-height:var(--ec-uiLineHt);text-size-adjust:none;-webkit-text-size-adjust:none}.expressive-code *:not(:is(svg, svg *)){all:revert;box-sizing:border-box}.expressive-code pre{display:flex;margin:0;padding:0;border:var(--ec-brdWd) solid var(--ec-brdCol);border-radius:calc(var(--ec-brdRad) + var(--ec-brdWd));background:var(--ec-codeBg)}.expressive-code pre:focus-visible{outline:3px solid var(--ec-focusBrd);outline-offset:-3px}.expressive-code pre &gt; code{all:unset;display:block;flex:1 0 100%;padding:var(--ec-codePadBlk) 0;color:var(--ec-codeFg);font-family:var(--ec-codeFontFml);font-size:var(--ec-codeFontSize);font-weight:var(--ec-codeFontWg);line-height:var(--ec-codeLineHt)}.expressive-code pre{overflow-x:auto}.expressive-code pre.wrap .ec-line .code{white-space:pre-wrap;overflow-wrap:break-word;min-width:min(20ch, var(--ecMaxLine, 20ch))}.expressive-code pre.wrap .ec-line .code span.indent{white-space:pre}.expressive-code pre::-webkit-scrollbar,.expressive-code pre::-webkit-scrollbar-track{background-color:inherit;border-radius:calc(var(--ec-brdRad) + var(--ec-brdWd));border-top-left-radius:0;border-top-right-radius:0}.expressive-code pre::-webkit-scrollbar-thumb{background-color:var(--ec-sbThumbCol);border:4px solid transparent;background-clip:content-box;border-radius:10px}.expressive-code pre::-webkit-scrollbar-thumb:hover{background-color:var(--ec-sbThumbHoverCol)}.expressive-code pre::-webkit-scrollbar-corner{background:transparent}.expressive-code .ec-line{direction:ltr;unicode-bidi:isolate;display:grid;grid-template-areas:&apos;gutter code&apos;;grid-template-columns:auto 1fr;position:relative}.expressive-code .ec-line .gutter{grid-area:gutter;color:var(--ec-gtrFg)}.expressive-code .ec-line .gutter &gt; *{pointer-events:none;user-select:none;-webkit-user-select:none}.expressive-code .ec-line .gutter ~ .code{--ecLineBrdCol:var(--ec-gtrBrdCol)}.expressive-code .ec-line.highlight .gutter{color:var(--ec-gtrHlFg)}.expressive-code .ec-line .code{grid-area:code;position:relative;box-sizing:content-box;padding-inline-start:calc(var(--ecIndent, 0ch) + var(--ec-codePadInl) - var(--ecGtrBrdWd));padding-inline-end:var(--ec-codePadInl);text-indent:calc(var(--ecIndent, 0ch) * -1)}.expressive-code .ec-line .code::before,.expressive-code .ec-line .code::after,.expressive-code .ec-line .code :where(*){text-indent:0}.expressive-code .ec-line .code{--ecGtrBrdWd:var(--ec-gtrBrdWd);border-inline-start:var(--ecGtrBrdWd) solid var(--ecLineBrdCol, transparent)}.expressive-code .sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0, 0, 0, 0);white-space:nowrap;border-width:0}.expressive-code .ec-line.mark{--tmLineBgCol:var(--ec-tm-markBg)}.expressive-code .ec-line.mark .code{--ecLineBrdCol:var(--ec-tm-markBrdCol)}.expressive-code .ec-line.ins{--tmLineBgCol:var(--ec-tm-insBg);--tmLabel:var(--ec-tm-insDiffIndContent)}.expressive-code .ec-line.ins .code{--ecLineBrdCol:var(--ec-tm-insBrdCol)}.expressive-code .ec-line.ins .code::before{color:var(--ec-tm-insDiffIndCol)}.expressive-code .ec-line.del{--tmLineBgCol:var(--ec-tm-delBg);--tmLabel:var(--ec-tm-delDiffIndContent)}.expressive-code .ec-line.del .code{--ecLineBrdCol:var(--ec-tm-delBrdCol)}.expressive-code .ec-line.del .code::before{color:var(--ec-tm-delDiffIndCol)}.expressive-code .ec-line.mark,.expressive-code .ec-line.ins,.expressive-code .ec-line.del{background:var(--tmLineBgCol)}.expressive-code .ec-line.mark .code,.expressive-code .ec-line.ins .code,.expressive-code .ec-line.del .code{--ecGtrBrdWd:var(--ec-tm-lineMarkerAccentWd)}.expressive-code .ec-line.mark .code::before,.expressive-code .ec-line.ins .code::before,.expressive-code .ec-line.del .code::before{display:block;position:absolute;left:0;box-sizing:border-box;content:var(--tmLabel, &apos; &apos;);padding-inline-start:var(--ec-tm-lineDiffIndMargLeft);text-align:center;white-space:pre}.expressive-code .ec-line.mark.tm-label .code::before,.expressive-code .ec-line.ins.tm-label .code::before,.expressive-code .ec-line.del.tm-label .code::before{background:var(--ecLineBrdCol);padding:0 calc(var(--ec-tm-lineMarkerLabelPadInl) + var(--ec-tm-lineMarkerAccentWd)) 0 var(--ec-tm-lineMarkerLabelPadInl);color:var(--ec-tm-lineMarkerLabelCol)}.expressive-code .ec-line mark{--tmInlineBgCol:var(--ec-tm-markBg);--tmInlineBrdCol:var(--ec-tm-markBrdCol)}.expressive-code .ec-line ins{--tmInlineBgCol:var(--ec-tm-insBg);--tmInlineBrdCol:var(--ec-tm-insBrdCol)}.expressive-code .ec-line del{--tmInlineBgCol:var(--ec-tm-delBg);--tmInlineBrdCol:var(--ec-tm-delBrdCol)}.expressive-code .ec-line mark,.expressive-code .ec-line ins,.expressive-code .ec-line del{all:unset;display:inline-block;position:relative;--tmBrdL:var(--ec-tm-inlMarkerBrdWd);--tmBrdR:var(--ec-tm-inlMarkerBrdWd);--tmRadL:var(--ec-tm-inlMarkerBrdRad);--tmRadR:var(--ec-tm-inlMarkerBrdRad);margin-inline:0.025rem;padding-inline:var(--ec-tm-inlMarkerPad);border-radius:var(--tmRadL) var(--tmRadR) var(--tmRadR) var(--tmRadL);background:var(--tmInlineBgCol);background-clip:padding-box}.expressive-code .ec-line mark.open-start,.expressive-code .ec-line ins.open-start,.expressive-code .ec-line del.open-start{margin-inline-start:0;padding-inline-start:0;--tmBrdL:0px;--tmRadL:0}.expressive-code .ec-line mark.open-end,.expressive-code .ec-line ins.open-end,.expressive-code .ec-line del.open-end{margin-inline-end:0;padding-inline-end:0;--tmBrdR:0px;--tmRadR:0}.expressive-code .ec-line mark::before,.expressive-code .ec-line ins::before,.expressive-code .ec-line del::before{content:&apos;&apos;;position:absolute;pointer-events:none;display:inline-block;inset:0;border-radius:var(--tmRadL) var(--tmRadR) var(--tmRadR) var(--tmRadL);border:var(--ec-tm-inlMarkerBrdWd) solid var(--tmInlineBrdCol);border-inline-width:var(--tmBrdL) var(--tmBrdR)}.expressive-code .frame{all:unset;position:relative;display:block;--header-border-radius:calc(var(--ec-brdRad) + var(--ec-brdWd));--tab-border-radius:calc(var(--ec-frm-edTabBrdRad) + var(--ec-brdWd));--button-spacing:0.4rem;--code-background:var(--ec-frm-edBg);border-radius:var(--header-border-radius);box-shadow:var(--ec-frm-frameBoxShdCssVal)}.expressive-code .frame .header{display:none;z-index:1;position:relative;border-radius:var(--header-border-radius) var(--header-border-radius) 0 0}.expressive-code .frame.has-title pre,.expressive-code .frame.has-title code,.expressive-code .frame.is-terminal pre,.expressive-code .frame.is-terminal code{border-top:none;border-top-left-radius:0;border-top-right-radius:0}.expressive-code .frame .title:empty:before{content:&apos;\a0&apos;}.expressive-code .frame.has-title:not(.is-terminal){--button-spacing:calc(1.9rem + 2 * (var(--ec-uiPadBlk) + var(--ec-frm-edActTabIndHt)))}.expressive-code .frame.has-title:not(.is-terminal) .title{position:relative;color:var(--ec-frm-edActTabFg);background:var(--ec-frm-edActTabBg);background-clip:padding-box;margin-block-start:var(--ec-frm-edTabsMargBlkStart);padding:calc(var(--ec-uiPadBlk) + var(--ec-frm-edActTabIndHt)) var(--ec-uiPadInl);border:var(--ec-brdWd) solid var(--ec-frm-edActTabBrdCol);border-radius:var(--tab-border-radius) var(--tab-border-radius) 0 0;border-bottom:none;overflow:hidden}.expressive-code .frame.has-title:not(.is-terminal) .title::after{content:&apos;&apos;;position:absolute;pointer-events:none;inset:0;border-top:var(--ec-frm-edActTabIndHt) solid var(--ec-frm-edActTabIndTopCol);border-bottom:var(--ec-frm-edActTabIndHt) solid var(--ec-frm-edActTabIndBtmCol)}.expressive-code .frame.has-title:not(.is-terminal) .header{display:flex;background:linear-gradient(to top, var(--ec-frm-edTabBarBrdBtmCol) var(--ec-brdWd), transparent var(--ec-brdWd)),linear-gradient(var(--ec-frm-edTabBarBg), var(--ec-frm-edTabBarBg));background-repeat:no-repeat;padding-inline-start:var(--ec-frm-edTabsMargInlStart)}.expressive-code .frame.has-title:not(.is-terminal) .header::before{content:&apos;&apos;;position:absolute;pointer-events:none;inset:0;border:var(--ec-brdWd) solid var(--ec-frm-edTabBarBrdCol);border-radius:inherit;border-bottom:none}.expressive-code .frame.is-terminal{--button-spacing:calc(1.9rem + var(--ec-brdWd) + 2 * var(--ec-uiPadBlk));--code-background:var(--ec-frm-trmBg)}.expressive-code .frame.is-terminal .header{display:flex;align-items:center;justify-content:center;padding-block:var(--ec-uiPadBlk);padding-block-end:calc(var(--ec-uiPadBlk) + var(--ec-brdWd));position:relative;font-weight:500;letter-spacing:0.025ch;color:var(--ec-frm-trmTtbFg);background:var(--ec-frm-trmTtbBg);border:var(--ec-brdWd) solid var(--ec-brdCol);border-bottom:none}.expressive-code .frame.is-terminal .header::before{content:&apos;&apos;;position:absolute;pointer-events:none;left:var(--ec-uiPadInl);width:2.1rem;height:0.56rem;line-height:0;background-color:var(--ec-frm-trmTtbDotsFg);opacity:var(--ec-frm-trmTtbDotsOpa);-webkit-mask-image:var(--ec-frm-trmIcon);-webkit-mask-repeat:no-repeat;mask-image:var(--ec-frm-trmIcon);mask-repeat:no-repeat}.expressive-code .frame.is-terminal .header::after{content:&apos;&apos;;position:absolute;pointer-events:none;inset:0;border-bottom:var(--ec-brdWd) solid var(--ec-frm-trmTtbBrdBtmCol)}.expressive-code .frame pre{background:var(--code-background)}.expressive-code .copy{display:flex;gap:0.25rem;flex-direction:row;position:absolute;inset-block-start:calc(var(--ec-brdWd) + var(--button-spacing));inset-inline-end:calc(var(--ec-brdWd) + var(--ec-uiPadInl) / 2)}@media (scripting: none){.expressive-code .copy{display:none}}.expressive-code .copy{direction:ltr;unicode-bidi:isolate}.expressive-code .copy button{position:relative;align-self:flex-end;margin:0;padding:0;border:none;border-radius:0.2rem;z-index:1;cursor:pointer;transition-property:opacity, background, border-color;transition-duration:0.2s;transition-timing-function:cubic-bezier(0.25, 0.46, 0.45, 0.94);width:2.5rem;height:2.5rem;background:var(--code-background);opacity:0.75}.expressive-code .copy button div{position:absolute;inset:0;border-radius:inherit;background:var(--ec-frm-inlBtnBg);opacity:var(--ec-frm-inlBtnBgIdleOpa);transition-property:inherit;transition-duration:inherit;transition-timing-function:inherit}.expressive-code .copy button::before{content:&apos;&apos;;position:absolute;pointer-events:none;inset:0;border-radius:inherit;border:var(--ec-brdWd) solid var(--ec-frm-inlBtnBrd);opacity:var(--ec-frm-inlBtnBrdOpa)}.expressive-code .copy button::after{content:&apos;&apos;;position:absolute;pointer-events:none;inset:0;background-color:var(--ec-frm-inlBtnFg);-webkit-mask-image:var(--ec-frm-copyIcon);-webkit-mask-repeat:no-repeat;mask-image:var(--ec-frm-copyIcon);mask-repeat:no-repeat;margin:0.475rem;line-height:0}.expressive-code .copy button:hover,.expressive-code .copy button:focus:focus-visible{opacity:1}.expressive-code .copy button:hover div,.expressive-code .copy button:focus:focus-visible div{opacity:var(--ec-frm-inlBtnBgHoverOrFocusOpa)}.expressive-code .copy button:active{opacity:1}.expressive-code .copy button:active div{opacity:var(--ec-frm-inlBtnBgActOpa)}.expressive-code .copy .feedback{--tooltip-arrow-size:0.35rem;--tooltip-bg:var(--ec-frm-tooltipSuccessBg);color:var(--ec-frm-tooltipSuccessFg);pointer-events:none;user-select:none;-webkit-user-select:none;position:relative;align-self:center;background-color:var(--tooltip-bg);z-index:99;padding:0.125rem 0.75rem;border-radius:0.2rem;margin-inline-end:var(--tooltip-arrow-size);opacity:0;transition-property:opacity, transform;transition-duration:0.2s;transition-timing-function:ease-in-out;transform:translate3d(0, 0.25rem, 0)}.expressive-code .copy .feedback::after{content:&apos;&apos;;position:absolute;pointer-events:none;top:calc(50% - var(--tooltip-arrow-size));inset-inline-end:calc(-2 * (var(--tooltip-arrow-size) - 0.5px));border:var(--tooltip-arrow-size) solid transparent;border-inline-start-color:var(--tooltip-bg)}.expressive-code .copy .feedback.show{opacity:1;transform:translate3d(0, 0, 0)}@media (hover: hover){.expressive-code{}.expressive-code .copy button{opacity:0;width:2rem;height:2rem}.expressive-code .frame:hover .copy button:not(:hover),.expressive-code .frame:focus-within :focus-visible ~ .copy button:not(:hover),.expressive-code .frame .copy .feedback.show ~ button:not(:hover){opacity:0.75}}.expressive-code :nth-child(1 of .ec-line) .code{padding-inline-end:calc(2rem + var(--ec-codePadInl))}:root{--ec-brdRad:0.75rem;--ec-brdWd:1.5px;--ec-brdCol:var(--code-line);--ec-codeFontFml:var(--font-code);--ec-codeFontSize:0.875rem;--ec-codeFontWg:400;--ec-codeLineHt:1.75;--ec-codePadBlk:1rem;--ec-codePadInl:1.125rem;--ec-codeBg:var(--code-bg);--ec-codeFg:#e6edf3;--ec-codeSelBg:#264f78;--ec-gtrFg:#6e7681;--ec-gtrBrdCol:#6e768133;--ec-gtrBrdWd:1.5px;--ec-gtrHlFg:#e6edf3;--ec-uiFontFml:var(--font-mono);--ec-uiFontSize:0.75rem;--ec-uiFontWg:400;--ec-uiLineHt:1.65;--ec-uiPadBlk:0.25rem;--ec-uiPadInl:1rem;--ec-uiSelBg:#6e768166;--ec-uiSelFg:#e6edf3;--ec-focusBrd:#1f6feb;--ec-sbThumbCol:#8b949e33;--ec-sbThumbHoverCol:#8b949e3d;--ec-tm-lineMarkerAccentMarg:0rem;--ec-tm-lineMarkerAccentWd:0.15rem;--ec-tm-lineMarkerLabelPadInl:0.2rem;--ec-tm-lineMarkerLabelCol:white;--ec-tm-lineDiffIndMargLeft:0.3rem;--ec-tm-inlMarkerBrdWd:1.5px;--ec-tm-inlMarkerBrdRad:0.2rem;--ec-tm-inlMarkerPad:0.15rem;--ec-tm-insDiffIndContent:&apos;+&apos;;--ec-tm-delDiffIndContent:&apos;-&apos;;--ec-tm-markBg:#264a8980;--ec-tm-markBrdCol:#5570b3d0;--ec-tm-insBg:#26561c80;--ec-tm-insBrdCol:#4e7e41d0;--ec-tm-insDiffIndCol:#7eb070d0;--ec-tm-delBg:#81322b80;--ec-tm-delBrdCol:#ae594fd0;--ec-tm-delDiffIndCol:#e68a7ed0;--ec-frm-shdCol:#0000005b;--ec-frm-frameBoxShdCssVal:none;--ec-frm-edActTabBg:var(--code-bg);--ec-frm-edActTabFg:var(--code-muted);--ec-frm-edActTabBrdCol:transparent;--ec-frm-edActTabIndHt:1.5px;--ec-frm-edActTabIndTopCol:transparent;--ec-frm-edActTabIndBtmCol:#0d1117;--ec-frm-edTabsMargInlStart:0;--ec-frm-edTabsMargBlkStart:0;--ec-frm-edTabBrdRad:0.75rem;--ec-frm-edTabBarBg:var(--code-bg);--ec-frm-edTabBarBrdCol:var(--code-line);--ec-frm-edTabBarBrdBtmCol:var(--code-line);--ec-frm-edBg:var(--code-bg);--ec-frm-trmTtbFg:var(--code-muted);--ec-frm-trmTtbDotsFg:var(--code-muted);--ec-frm-trmTtbDotsOpa:0.15;--ec-frm-trmTtbBg:var(--code-bg);--ec-frm-trmTtbBrdBtmCol:var(--code-line);--ec-frm-trmBg:var(--code-bg);--ec-frm-inlBtnBg:var(--code-ink);--ec-frm-inlBtnBgIdleOpa:0;--ec-frm-inlBtnBgHoverOrFocusOpa:0.2;--ec-frm-inlBtnBgActOpa:0.3;--ec-frm-inlBtnFg:var(--code-ink);--ec-frm-inlBtnBrd:var(--code-line);--ec-frm-inlBtnBrdOpa:0.4;--ec-frm-tooltipSuccessBg:var(--color-emerald);--ec-frm-tooltipSuccessFg:var(--color-bg);--ec-frm-copyIcon:url(&quot;data:image/svg+xml,%3Csvg%20xmlns%3D&apos;http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg&apos;%20viewBox%3D&apos;0%200%2024%2024&apos;%20fill%3D&apos;none&apos;%20stroke%3D&apos;black&apos;%20stroke-width%3D&apos;1.75&apos;%3E%3Cpath%20d%3D&apos;M3%2019a2%202%200%200%201-1-2V2a2%202%200%200%201%201-1h13a2%202%200%200%201%202%201&apos;%2F%3E%3Crect%20x%3D&apos;6&apos;%20y%3D&apos;5&apos;%20width%3D&apos;16&apos;%20height%3D&apos;18&apos;%20rx%3D&apos;1.5&apos;%20ry%3D&apos;1.5&apos;%2F%3E%3C%2Fsvg%3E&quot;);--ec-frm-trmIcon:url(&quot;data:image/svg+xml,%3Csvg%20xmlns%3D&apos;http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg&apos;%20viewBox%3D&apos;0%200%2060%2016&apos;%20preserveAspectRatio%3D&apos;xMidYMid%20meet&apos;%3E%3Ccircle%20cx%3D&apos;8&apos;%20cy%3D&apos;8&apos;%20r%3D&apos;8&apos;%2F%3E%3Ccircle%20cx%3D&apos;30&apos;%20cy%3D&apos;8&apos;%20r%3D&apos;8&apos;%2F%3E%3Ccircle%20cx%3D&apos;52&apos;%20cy%3D&apos;8&apos;%20r%3D&apos;8&apos;%2F%3E%3C%2Fsvg%3E&quot;)}.expressive-code .ec-line :where(span[style^=&apos;--&apos;]:not([class])){color:var(--0, inherit);background-color:var(--0bg, transparent);font-style:var(--0fs, inherit);font-weight:var(--0fw, inherit);text-decoration:var(--0td, inherit)}&lt;/style&gt;&lt;script type=&quot;module&quot; src=&quot;/_astro/ec.0vx5m.js&quot;&gt;&lt;/script&gt;&lt;figure class=&quot;frame has-title&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;JavaScript&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;javascript&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#8B949E&quot;&gt;// db-pool-config.js&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#8B949E&quot;&gt;// Production-ready PostgreSQL connection pool setup using &apos;pg&apos; module&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; { &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;Pool&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; } &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D2A8FF&quot;&gt;require&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;&apos;pg&apos;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;pool&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D2A8FF&quot;&gt;Pool&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;({&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;host: process.env.&lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;DB_HOST&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;||&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;&apos;db-primary.foodfast.internal&apos;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;port: &lt;/span&gt;&lt;span style=&quot;--0:#D2A8FF&quot;&gt;parseInt&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;(process.env.&lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;DB_PORT&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;||&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;&apos;5432&apos;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;10&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;),&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;database: process.env.&lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;DB_NAME&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;||&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;&apos;foodfast_production&apos;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;user: process.env.&lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;DB_USER&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;||&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;&apos;admin_user&apos;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;password: process.env.&lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;DB_PASSWORD&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#8B949E&quot;&gt;// Limit the maximum number of clients in the pool to prevent memory exhaustion&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;max: &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;25&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#8B949E&quot;&gt;// Close idle clients after 30 seconds of inactivity&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;idleTimeoutMillis: &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;30000&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#8B949E&quot;&gt;// Return an error after 2 seconds if connection could not be established&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;connectionTimeoutMillis: &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;2000&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;});&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;pool.&lt;/span&gt;&lt;span style=&quot;--0:#D2A8FF&quot;&gt;on&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;&apos;error&apos;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;, (&lt;/span&gt;&lt;span style=&quot;--0:#FFA657&quot;&gt;err&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#FFA657&quot;&gt;client&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;=&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;console.&lt;/span&gt;&lt;span style=&quot;--0:#D2A8FF&quot;&gt;error&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;&apos;Unexpected error on idle database client in FoodFast cluster&apos;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;, err);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;process.&lt;/span&gt;&lt;span style=&quot;--0:#D2A8FF&quot;&gt;exit&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;});&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;module&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;exports&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#D2A8FF&quot;&gt;query&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;: (&lt;/span&gt;&lt;span style=&quot;--0:#FFA657&quot;&gt;text&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#FFA657&quot;&gt;params&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;=&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; pool.&lt;/span&gt;&lt;span style=&quot;--0:#D2A8FF&quot;&gt;query&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;(text, params),&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#D2A8FF&quot;&gt;getPool&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;: () &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;=&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; pool,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;};&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;// db-pool-config.js// Production-ready PostgreSQL connection pool setup using &amp;#x27;pg&amp;#x27; moduleconst { Pool } = require(&amp;#x27;pg&amp;#x27;);const pool = new Pool({  host: process.env.DB_HOST || &amp;#x27;db-primary.foodfast.internal&amp;#x27;,  port: parseInt(process.env.DB_PORT || &amp;#x27;5432&amp;#x27;, 10),  database: process.env.DB_NAME || &amp;#x27;foodfast_production&amp;#x27;,  user: process.env.DB_USER || &amp;#x27;admin_user&amp;#x27;,  password: process.env.DB_PASSWORD,  // Limit the maximum number of clients in the pool to prevent memory exhaustion  max: 25,  // Close idle clients after 30 seconds of inactivity  idleTimeoutMillis: 30000,  // Return an error after 2 seconds if connection could not be established  connectionTimeoutMillis: 2000,});pool.on(&amp;#x27;error&amp;#x27;, (err, client) =&gt; {  console.error(&amp;#x27;Unexpected error on idle database client in FoodFast cluster&amp;#x27;, err);  process.exit(-1);});module.exports = {  query: (text, params) =&gt; pool.query(text, params),  getPool: () =&gt; pool,};&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;div class=&quot;callout&quot; role=&quot;note&quot; data-type=&quot;note&quot;&gt;
&lt;p class=&quot;callout-title&quot;&gt;Connection Pooling Efficiency&lt;/p&gt;
&lt;p&gt;ডেটাবেজের সাথে প্রতিবার নতুন কানেকশন তৈরি করা একটি অত্যন্ত ব্যয়বহুল অপারেশন, কারণ এতে TCP Handshake এবং Authentication প্রসেস জড়িত থাকে। Connection Pool ব্যবহার করলে আগে থেকেই কিছু কানেকশন তৈরি থাকে, যা কুয়েরি ল্যাটেন্সি অনেকাংশে কমিয়ে দেয়।&lt;/p&gt;
&lt;/div&gt;
&lt;hr&gt;
&lt;h2 id=&quot;কেস-স্টাডি-২-foodfast-ফ্ল্যাশ-সেল-ক্রাইসিস-ও-১-মিলিয়ন-ইউজার-horizontal-scaling-load-balancing&quot;&gt;কেস স্টাডি ২: FoodFast ফ্ল্যাশ সেল ক্রাইসিস ও ১ মিলিয়ন ইউজার (Horizontal Scaling &amp;#x26; Load Balancing)&lt;/h2&gt;
&lt;p&gt;FoodFast-এর ইউজার সংখ্যা যখন ১ লাখে পৌঁছাল, তখন ব্যবসায়িক প্রবৃদ্ধির জন্য আপনারা একটি &quot;মিডনাইট ফ্ল্যাশ সেল&quot; ঘোষণা করলেন। রাত ১২টায় নির্দিষ্ট কিছু রেস্টুরেন্টে ৫০ শতাংশ ছাড় দেওয়া হবে। রাত ১১টা ৫৯ মিনিটে আপনাদের সিস্টেমে একসাথে ১ লাখ ইউজার লগইন করল এবং ঠিক ১২টায় একসাথে হাজার হাজার অর্ডার রিকোয়েস্ট আসতে শুরু করল। কয়েক সেকেন্ডের মধ্যে আপনাদের সেই ১৬ কোর CPU-র শক্তিশালী Web Server-টি Out of Memory বা OOM এররে ক্র্যাশ করল। পুরো প্ল্যাটফর্ম ডাউন হয়ে গেল এবং সোশ্যাল মিডিয়ায় ইউজারদের নেতিবাচক রিভিউ আসতে শুরু করল।&lt;/p&gt;
&lt;p&gt;আপনারা বুঝতে পারলেন, Vertical Scaling বা সার্ভার বড় করার একটি ভৌত এবং আর্থিক সীমাবদ্ধতা আছে। একটি সিঙ্গেল সার্ভারে আপনি চাইলেই আনলিমিটেড RAM বা প্রসেসর বসাতে পারবেন না, এবং একটি সার্ভারের ওপর নির্ভর করা মানেই সিস্টেমে Single Point of Failure বা SPOF রেখে দেওয়া। এই ক্রাইসিস থেকে মুক্তির একমাত্র পথ হলো Horizontal Scaling ইমপ্লিমেন্ট করা। আমরা একটি শক্তিশালী সার্ভারের বদলে সাধারণ কনফিগারেশনের ১০টি সার্ভার সমান্তরালভাবে নেটওয়ার্কে যুক্ত করি। কিন্তু এখন প্রশ্ন হলো, ক্লায়েন্টের মোবাইল অ্যাপ বা ব্রাউজার কীভাবে জানবে কোন সার্ভারে রিকোয়েস্ট পাঠাতে হবে?&lt;/p&gt;
&lt;p&gt;এই সমস্যার সমাধানে আমরা সার্ভার ক্লাস্টারের সামনে একটি Load Balancing Layer তৈরি করি, যেখানে Nginx বা HAProxy ব্যবহার করা হয়। লোড ব্যালেন্সার Layer 4 (Transport Layer) বা Layer 7 (Application Layer) রাউটিং ইমপ্লিমেন্ট করে। আমরা Nginx-এ Least Connections অ্যালগরিদম কনফিগার করি, যাতে যে সার্ভারে কাজের চাপ সবচেয়ে কম, নতুন রিকোয়েস্টটি সেখানেই যায়। তবে একাধিক সার্ভার ব্যবহার করার একটি প্রধান পূর্বশর্ত হলো সার্ভারকে সম্পূর্ণ Stateless করা। আগে ইউজারের লগইন সেশন সার্ভারের লোকাল মেমরিতে থাকত, যাকে Sticky Session বলা হয়। কিন্তু এখন রিকোয়েস্ট যেকোনো সার্ভারে যেতে পারে। তাই আমরা সেশন ডেটা সার্ভারের মেমরি থেকে সরিয়ে Centralized Redis Session Store-এ নিয়ে যাই এবং ক্লায়েন্ট সাইডে Stateless JWT বা JSON Web Token ব্যবহার শুরু করি।&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame has-title&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;Nginx&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;nginx&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#8B949E&quot;&gt;# nginx-load-balancer.conf&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#8B949E&quot;&gt;# Layer 7 Load Balancing configuration for FoodFast backend cluster&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;upstream&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FFA657&quot;&gt;foodfast_backend_cluster &lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#8B949E&quot;&gt;# Routelessly distribute load to the server with the least active connections&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;least_conn&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;server&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; app-node-01.foodfast.internal:3000 &lt;/span&gt;&lt;span style=&quot;--0:#FFA657&quot;&gt;max_fails&lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;3&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; fail_timeout=10s;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;server&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; app-node-02.foodfast.internal:3000 &lt;/span&gt;&lt;span style=&quot;--0:#FFA657&quot;&gt;max_fails&lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;3&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; fail_timeout=10s;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;server&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; app-node-03.foodfast.internal:3000 &lt;/span&gt;&lt;span style=&quot;--0:#FFA657&quot;&gt;max_fails&lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;3&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; fail_timeout=10s;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;server&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; app-node-04.foodfast.internal:3000 &lt;/span&gt;&lt;span style=&quot;--0:#FFA657&quot;&gt;max_fails&lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;3&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; fail_timeout=10s;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;server&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; app-node-05.foodfast.internal:3000 &lt;/span&gt;&lt;span style=&quot;--0:#FFA657&quot;&gt;max_fails&lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;3&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; fail_timeout=10s;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#8B949E&quot;&gt;# Maintain open keepalive connections between Nginx and backend servers&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;   &lt;span style=&quot;--0:#FF7B72&quot;&gt; &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;keepalive &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;64&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;server&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;   &lt;span style=&quot;--0:#FF7B72&quot;&gt; &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;listen &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;80&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;   &lt;span style=&quot;--0:#FF7B72&quot;&gt; &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;server_name &lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;api.foodfast.com;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;location&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FFA657&quot;&gt;/ &lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;       &lt;span style=&quot;--0:#FF7B72&quot;&gt; &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;proxy_pass &lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;http://foodfast_backend_cluster;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;       &lt;span style=&quot;--0:#FF7B72&quot;&gt; &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;proxy_http_version &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;1.1&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;       &lt;span style=&quot;--0:#FF7B72&quot;&gt; &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;proxy_set_header &lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;Connection &lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;       &lt;span style=&quot;--0:#FF7B72&quot;&gt; &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;proxy_set_header &lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;X-Real-IP $remote_addr;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;       &lt;span style=&quot;--0:#FF7B72&quot;&gt; &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;proxy_set_header &lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;X-Forwarded-For $proxy_add_x_forwarded_for;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;       &lt;span style=&quot;--0:#FF7B72&quot;&gt; &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;proxy_set_header &lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;Host $http_host;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#8B949E&quot;&gt;# Strict timeout configurations to prevent hanging requests during spikes&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;       &lt;span style=&quot;--0:#FF7B72&quot;&gt; &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;proxy_connect_timeout &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;3s&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;       &lt;span style=&quot;--0:#FF7B72&quot;&gt; &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;proxy_read_timeout &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;7s&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;# nginx-load-balancer.conf# Layer 7 Load Balancing configuration for FoodFast backend clusterupstream foodfast_backend_cluster {    # Routelessly distribute load to the server with the least active connections    least_conn;    server app-node-01.foodfast.internal:3000 max_fails=3 fail_timeout=10s;    server app-node-02.foodfast.internal:3000 max_fails=3 fail_timeout=10s;    server app-node-03.foodfast.internal:3000 max_fails=3 fail_timeout=10s;    server app-node-04.foodfast.internal:3000 max_fails=3 fail_timeout=10s;    server app-node-05.foodfast.internal:3000 max_fails=3 fail_timeout=10s;    # Maintain open keepalive connections between Nginx and backend servers    keepalive 64;}server {    listen 80;    server_name api.foodfast.com;    location / {        proxy_pass http://foodfast_backend_cluster;        proxy_http_version 1.1;        proxy_set_header Connection &amp;#x22;&amp;#x22;;        proxy_set_header X-Real-IP $remote_addr;        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;        proxy_set_header Host $http_host;        # Strict timeout configurations to prevent hanging requests during spikes        proxy_connect_timeout 3s;        proxy_read_timeout 7s;    }}&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;figure&gt;&lt;img src=&quot;https://raw.githubusercontent.com/rafeuddaraj/rafes-blog-assets/refs/heads/ultimate-system-design-handbook-case-study-global-scale/assets/foodfast-monolith-to-horizontal.svg&quot; alt=&quot;Monolith to Horizontal Scaling Evolution&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1000&quot; height=&quot;580&quot;&gt;&lt;figcaption&gt;Monolith to Horizontal Scaling Evolution&lt;/figcaption&gt;&lt;/figure&gt;
&lt;div class=&quot;callout&quot; role=&quot;note&quot; data-type=&quot;note&quot;&gt;
&lt;p class=&quot;callout-title&quot;&gt;Stateless Architecture Requirement&lt;/p&gt;
&lt;p&gt;লোড ব্যালেন্সার ব্যবহারের সময় সার্ভারের লোকাল মেমরিতে কখনোই কোনো ইউজার সেশন, টেম্পোরারি ফাইল বা স্টেট সেভ করবেন না। সার্ভার সম্পূর্ণ Stateless না হলে রিকোয়েস্ট অন্য নোডে রাউট হওয়ার সাথে সাথে ইউজার বারবার লগআউট হয়ে যাবে বা ডেটা হারিয়ে ফেলবে।&lt;/p&gt;
&lt;/div&gt;
&lt;hr&gt;
&lt;h2 id=&quot;কেস-স্টাডি-৩-ডেটাবেজ-যখন-বোতলঘাড়-ও-গ্লোবাল-এক্সপানশন-replication-sharding-nosql&quot;&gt;কেস স্টাডি ৩: ডেটাবেজ যখন বোতলঘাড় ও গ্লোবাল এক্সপানশন (Replication, Sharding &amp;#x26; NoSQL)&lt;/h2&gt;
&lt;p&gt;Horizontal Scaling এবং লোড ব্যালেন্সার বসানোর পর FoodFast-এর Web Server ক্লাস্টার এখন প্রতি সেকেন্ডে লাখ লাখ রিকোয়েস্ট হ্যান্ডেল করতে পারছে। কিন্তু আপনাদের ব্যবসা এখন আর একটি শহরের মধ্যে সীমাবদ্ধ নেই; পুরো দেশ জুড়ে এবং প্রতিবেশী কয়েকটি দেশে আপনাদের সেবা চালু হয়েছে। ইউজার সংখ্যা ১০ লাখ পার হয়েছে। ঠিক এই পর্যায়ে আপনাদের সিস্টেমে নতুন একটি Bottleneck তৈরি হলো। আপনাদের ১০টি App Server স্বাধীনভাবে কাজ করলেও, তারা সবাই ডেটা রিড এবং রাইট করার জন্য আঘাত করছে সেই একটি মাত্র Relational Database-এর ওপর।&lt;/p&gt;
&lt;p&gt;ডেটাবেজের ওপর এই প্রচণ্ড চাপের কারণে Database Read and Write Contention তৈরি হলো। Connection Pool নিঃশেষ হয়ে গেল এবং জটিল ট্রানজেকশনের সময় Deadlock দেখা দিল। আমরা যখন কুয়েরি লগ বিশ্লেষণ করলাম, তখন দেখলাম যে রেস্টুরেন্ট সার্চ করার কুয়েরিগুলো Full Table Scan করছে। ১ লাখ রেস্টুরেন্টের ডেটাবেজ থেকে নির্দিষ্ট এলাকার খাবার খুঁজতে গিয়ে ডেটাবেজের প্রসেসর ১০০ শতাংশ ব্যস্ত হয়ে পড়ছে। এই সমস্যার প্রথম সমাধান হিসেবে আমরা ডেটাবেজের সার্চ কলামগুলোতে B-Tree Indexing ইমপ্লিমেন্ট করি। ইনডেক্সিং করার ফলে আমাদের সার্চ কুয়েরির Time Complexity O(n) থেকে নেমে O(log n) হয়ে গেল, এবং যে কুয়েরি চলতে ৫০০ মিলিসেকেন্ড লাগছিল, তা নেমে আসলো মাত্র ৫ মিলিসেকেন্ডে।&lt;/p&gt;
&lt;p&gt;কিন্তু ইনডেক্সিং শুধুমাত্র Read স্পিড বাড়ায়। প্রতিবার নতুন অর্ডার আসার সাথে সাথে (Write Operation) ডেটাবেজকে তার ইনডেক্স ট্রি রিবিল্ড করতে হয়, যা Space Complexity এবং Time Overhead বাড়িয়ে দেয়। তাই আমরা ডেটা লেয়ারকে ডিস্ট্রিবিউটেড করার সিদ্ধান্ত নিই। আমরা Database Replication ইমপ্লিমেন্ট করে একটি Leader (Write) ডেটাবেজ এবং ৪টি Follower (Read) ডেটাবেজ তৈরি করি। আমাদের অ্যাপ্লিকেশনের ৯০ শতাংশ ট্রাফিকই হলো Read Operation (যেমন: মেনু দেখা, রেস্টুরেন্ট খোঁজা)। আমরা এই সমস্ত Read ট্রাফিক লোড ব্যালেন্স করে Follower ডেটাবেজগুলোতে পাঠিয়ে দিই, এবং শুধুমাত্র অর্ডার প্লেস বা পেমেন্টের মতো Write Operation-গুলো Leader ডেটাবেজে পাঠাই। লিডার ডেটাবেজ স্বয়ংক্রিয়ভাবে তার ডেটা ফলোয়ারদের সাথে সিঙ্ক করে নেয়।&lt;/p&gt;
&lt;p&gt;যখন আমাদের অর্ডারের টেবিল কয়েক কোটি রো (Rows) পার হয়ে গেল, তখন একটি সিঙ্গেল লিডার ডেটাবেজেও ডেটা রাখা অসম্ভব হয়ে পড়ল। তখন আমরা Sharding বা Horizontal Partitioning ইমপ্লিমেন্ট করি। আমরা ইউজারের Geographic Location বা City ID-কে Sharding Key হিসেবে ব্যবহার করে ডেটাবেজকে কয়েকটি স্বাধীন অংশে ভাগ করে ফেলি। উদাহরণস্বরূপ, ঢাকার সব ইউজারের ডেটা চলে গেল Shard-A তে, এবং চট্টগ্রামের ডেটা চলে গেল Shard-B তে। একই সাথে আমরা বুঝতে পারলাম যে সব ডেটার জন্য Relational Database বা SQL উপযুক্ত নয়। পেমেন্ট এবং অর্ডারের জন্য আমাদের ACID (Atomicity, Consistency, Isolation, Durability) প্রোপার্টিজ দরকার, তাই সেখানে আমরা PostgreSQL ব্যবহার অব্যাহত রাখলাম। কিন্তু ইউজারদের রিয়েল-টাইম জিপিএস লোকেশন ট্র্যাকিং এবং চ্যাট মেসেজের মতো আনস্ট্রাকচার্ড ও হাই-ভলিউম ডেটার জন্য আমরা NoSQL ডেটাবেজ হিসেবে MongoDB এবং Cassandra বেছে নিলাম। আমাদের এই সিদ্ধান্তে CAP Theorem (Consistency, Availability, Partition Tolerance) একটি বড় ভূমিকা পালন করেছিল। আমরা পেমেন্টের ক্ষেত্রে Consistency-কে সর্বোচ্চ গুরুত্ব দিয়েছি, আর লাইভ লোকেশন ট্র্যাকিংয়ের ক্ষেত্রে Availability-কে প্রাধান্য দিয়েছি।&lt;/p&gt;
&lt;figure&gt;&lt;img src=&quot;https://raw.githubusercontent.com/rafeuddaraj/rafes-blog-assets/refs/heads/ultimate-system-design-handbook-case-study-global-scale/assets/database-sharding-replication.svg&quot; alt=&quot;Distributed Database Replication and Sharding&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1000&quot; height=&quot;520&quot;&gt;&lt;figcaption&gt;Distributed Database Replication and Sharding&lt;/figcaption&gt;&lt;/figure&gt;
&lt;div class=&quot;callout&quot; role=&quot;note&quot; data-type=&quot;warning&quot;&gt;
&lt;p class=&quot;callout-title&quot;&gt;Database Sharding Complexity&lt;/p&gt;
&lt;p&gt;ডেটাবেজ Sharding করার আগে দশবার চিন্তা করুন। একবার Sharding করার পর একাধিক Shards থেকে Join Query চালানো বা ট্রানজেকশন মেইনটেইন করা অত্যন্ত জটিল হয়ে যায়। Sharding করার আগে অবশ্যই Indexing, Caching এবং Read Replication চেষ্টা করে দেখুন।&lt;/p&gt;
&lt;/div&gt;
&lt;hr&gt;
&lt;h2 id=&quot;কেস-স্টাডি-৪-রকেটের-গতিতে-পারফরম্যান্স-বুস্টিং-caching-strategies-edge-computing&quot;&gt;কেস স্টাডি ৪: রকেটের গতিতে পারফরম্যান্স বুস্টিং (Caching Strategies &amp;#x26; Edge Computing)&lt;/h2&gt;
&lt;p&gt;FoodFast-এর ডেটাবেজ এখন ডিস্ট্রিবিউটেড এবং স্কেল করা হয়েছে। সার্ভার ক্র্যাশ করছে না, এবং অর্ডারও ঠিকমতো প্লেস হচ্ছে। কিন্তু আপনারা ইউজারদের অ্যানালিটিক্স রিপোর্ট দেখে লক্ষ্য করলেন যে, অ্যাপ ওপেন করার পর হোমপেজ লোড হতে এখনও প্রায় ২.৫ সেকেন্ড সময় লাগছে। বর্তমান ফাস্ট-পেজড ইন্টারনেটের যুগে ২.৫ সেকেন্ড লোড টাইম মানেই প্রচুর ইউজার অ্যাপ বন্ধ করে প্রতিদ্বন্দ্বী প্ল্যাটফর্মে চলে যাওয়া। আমরা যখন নেটওয়ার্ক রিকোয়েস্ট ট্রেস করলাম, তখন দেখলাম প্রতিবার ইউজার হোমপেজে আসলে আমাদের App Server ডেটাবেজে কুয়েরি চালিয়ে রেস্টুরেন্টের লিস্ট এবং পপুলার খাবারের তালিকা নিয়ে আসছে। ফিজিক্যাল হার্ডডিস্ক বা এসএসডি থেকে ডেটা রিড করতে এবং নেটওয়ার্ক রাউন্ড ট্রিপে এই মূল্যবান সময় নষ্ট হচ্ছে।&lt;/p&gt;
&lt;p&gt;এই ল্যাটেন্সি বা বিলম্বকে মিলিসেকেন্ড থেকে মাইক্রোসেকেন্ডে নামিয়ে আনার মোক্ষম ইঞ্জিনিয়ারিং অস্ত্র হলো In-Memory Caching। আমরা আমাদের আর্কিটেকচারে Redis এবং Memcached-এর মতো ইন-মেমরি ডেটাবেজ যুক্ত করি। যে সমস্ত ডেটা খুব ঘন ঘন পরিবর্তন হয় না (যেমন: রেস্টুরেন্টের মেনু, খাবারের দাম, ও ক্যাটাগরি লিস্ট), সেগুলো আমরা সরাসরি সার্ভারের RAM-এ সেভ করে রাখি। আমরা Read-Heavy অপারেশনের জন্য Cache-Aside প্যাটার্ন ইমপ্লিমেন্ট করি। যখন কোনো রিকোয়েস্ট আসে, অ্যাপ্লিকেশন প্রথমে Redis ক্যাশে ডেটা খোঁজে (Cache Hit)। যদি ডেটা পাওয়া যায়, তবে ডেটাবেজে না গিয়েই তাৎক্ষণিক উত্তর দিয়ে দেয়। আর যদি ক্যাশে ডেটা না থাকে (Cache Miss), তখন অ্যাপ্লিকেশন মূল ডেটাবেজ থেকে ডেটা নিয়ে আসে, ক্লায়েন্টকে উত্তর দেয়, এবং পরবর্তী রিকোয়েস্টের জন্য সেই ডেটা Redis-এ সেভ করে রাখে।&lt;/p&gt;
&lt;p&gt;কিন্তু RAM বা মেমরি অত্যন্ত ব্যয়বহুল এবং এর ধারণক্ষমতা সীমিত। কোটি কোটি খাবারের আইটেম আজীবন মেমরিতে রাখা সম্ভব নয়। তাই আমরা সঠিক Cache Eviction Policies কনফিগার করি। আমরা Redis ক্লাস্টারে LRU (Least Recently Used) অ্যালগরিদম সেট করি। যখন মেমরি ফুল হয়ে যায়, তখন যে ডেটাগুলো দীর্ঘ সময় ধরে কোনো ইউজার ব্রাউজ করেনি, সিস্টেম স্বয়ংক্রিয়ভাবে সেগুলো মেমরি থেকে মুছে ফেলে এবং নতুন হট-ডেটার জন্য জায়গা করে দেয়। একই সাথে ডেটা consistency ঠিক রাখার জন্য আমরা প্রতিটি ক্যাশ কি (Key)-এর সাথে একটি যৌক্তিক TTL (Time To Live) বা মেয়াদ নির্ধারণ করে দিই, যাতে রেস্টুরেন্ট খাবারের দাম পরিবর্তন করলে ইউজার পুরনো দাম দেখতে না পায়।&lt;/p&gt;
&lt;p&gt;এছাড়া আমাদের প্ল্যাটফর্মে প্রতিদিন হাজার হাজার খাবারের হাই-রেজোলিউশন ছবি এবং প্রমোশনাল ভিডিও আপলোড হয়। একজন ইউজার যখন অ্যাপ ব্রাউজ করে, তখন এই ভারী স্ট্যাটিক ফাইলগুলো আমাদের মূল সার্ভার থেকে লোড হতে প্রচুর সময় নেয় এবং নেটওয়ার্ক ব্যান্ডউইথ খরচ করে। এই সমস্যার সমাধানে আমরা Cloudflare এবং AWS CloudFront-এর মতো CDN বা Content Delivery Network ব্যবহার শুরু করি। সিডিএন বিশ্বের বিভিন্ন স্থানে ছড়িয়ে থাকা Edge Servers-এ আমাদের ছবি ও ভিডিওগুলোর ক্যাশ কপি রেখে দেয়। এখন একজন ইউজার যখন অ্যাপ খোলে, তখন তার খাবারের ছবিগুলো আমাদের মূল সার্ভার থেকে না এসে তার ভৌগোলিক অবস্থানের সবচেয়ে কাছের Edge Location থেকে লোড হয়। এর ফলে রাউন্ড ট্রিপ টাইম (RTT) নাটকীয়ভাবে কমে যায় এবং পুরো অ্যাপ রকেটের গতিতে কাজ করে।&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame has-title&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;TypeScript&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;typescript&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#8B949E&quot;&gt;// redis-cache-aside.ts&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#8B949E&quot;&gt;// Production implementation of Cache-Aside pattern using Redis and Node.js&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; { createClient } &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;&apos;redis&apos;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; { getPool } &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;&apos;./db-pool-config&apos;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;redisClient&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D2A8FF&quot;&gt;createClient&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;({ url: process.env.&lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;REDIS_URL&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; });&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;redisClient.&lt;/span&gt;&lt;span style=&quot;--0:#D2A8FF&quot;&gt;connect&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;export&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;async&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;function&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D2A8FF&quot;&gt;getRestaurantMenu&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#FFA657&quot;&gt;restaurantId&lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;string&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FFA657&quot;&gt;Promise&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;any&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;cacheKey&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;`foodfast:menu:${&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;restaurantId&lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;}`&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;try&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#8B949E&quot;&gt;// Step 1: Check if the menu exists in Redis in-memory cache&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;cachedData&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;await&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; redisClient.&lt;/span&gt;&lt;span style=&quot;--0:#D2A8FF&quot;&gt;get&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;(cacheKey);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;if&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; (cachedData) {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;console.&lt;/span&gt;&lt;span style=&quot;--0:#D2A8FF&quot;&gt;info&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;`[Cache Hit] Serving menu from Redis for restaurant: ${&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;restaurantId&lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;}`&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;JSON&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#D2A8FF&quot;&gt;parse&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;(cachedData);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#8B949E&quot;&gt;// Step 2: Cache Miss - Query the primary PostgreSQL database&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;console.&lt;/span&gt;&lt;span style=&quot;--0:#D2A8FF&quot;&gt;warn&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;`[Cache Miss] Fetching menu from DB for restaurant: ${&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;restaurantId&lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;}`&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;dbPool&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D2A8FF&quot;&gt;getPool&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;queryText&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;`&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;SELECT id, name, description, price, category, is_available&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;FROM menu_items&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;WHERE restaurant_id = $1 AND is_deleted = false&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;`&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;result&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;await&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; dbPool.&lt;/span&gt;&lt;span style=&quot;--0:#D2A8FF&quot;&gt;query&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;(queryText, [restaurantId]);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;if&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; (result.rows.&lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;length&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;===&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;) {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;null&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;menuData&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; result.rows;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#8B949E&quot;&gt;// Step 3: Write data to Redis Cache with a TTL of 3600 seconds (1 hour)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;await&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; redisClient.&lt;/span&gt;&lt;span style=&quot;--0:#D2A8FF&quot;&gt;setEx&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;(cacheKey, &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;3600&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;JSON&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#D2A8FF&quot;&gt;stringify&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;(menuData));&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; menuData;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;} &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;catch&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; (error) {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;console.&lt;/span&gt;&lt;span style=&quot;--0:#D2A8FF&quot;&gt;error&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;&apos;Error in getRestaurantMenu execution:&apos;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;, error);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#8B949E&quot;&gt;// Fallback: If Redis fails, gracefully degrade and fetch from DB directly&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;dbPool&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D2A8FF&quot;&gt;getPool&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;fallbackResult&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;await&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; dbPool.&lt;/span&gt;&lt;span style=&quot;--0:#D2A8FF&quot;&gt;query&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;&apos;SELECT * FROM menu_items WHERE restaurant_id = $1&apos;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;, [restaurantId]);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; fallbackResult.rows;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;// redis-cache-aside.ts// Production implementation of Cache-Aside pattern using Redis and Node.jsimport { createClient } from &amp;#x27;redis&amp;#x27;;import { getPool } from &amp;#x27;./db-pool-config&amp;#x27;;const redisClient = createClient({ url: process.env.REDIS_URL });redisClient.connect();export async function getRestaurantMenu(restaurantId: string): Promise&lt;any&gt; {  const cacheKey = &amp;#x60;foodfast:menu:${restaurantId}&amp;#x60;;  try {    // Step 1: Check if the menu exists in Redis in-memory cache    const cachedData = await redisClient.get(cacheKey);    if (cachedData) {      console.info(&amp;#x60;[Cache Hit] Serving menu from Redis for restaurant: ${restaurantId}&amp;#x60;);      return JSON.parse(cachedData);    }    // Step 2: Cache Miss - Query the primary PostgreSQL database    console.warn(&amp;#x60;[Cache Miss] Fetching menu from DB for restaurant: ${restaurantId}&amp;#x60;);    const dbPool = getPool();    const queryText = &amp;#x60;      SELECT id, name, description, price, category, is_available      FROM menu_items      WHERE restaurant_id = $1 AND is_deleted = false    &amp;#x60;;    const result = await dbPool.query(queryText, [restaurantId]);    if (result.rows.length === 0) {      return null;    }    const menuData = result.rows;    // Step 3: Write data to Redis Cache with a TTL of 3600 seconds (1 hour)    await redisClient.setEx(cacheKey, 3600, JSON.stringify(menuData));    return menuData;  } catch (error) {    console.error(&amp;#x27;Error in getRestaurantMenu execution:&amp;#x27;, error);    // Fallback: If Redis fails, gracefully degrade and fetch from DB directly    const dbPool = getPool();    const fallbackResult = await dbPool.query(&amp;#x27;SELECT * FROM menu_items WHERE restaurant_id = $1&amp;#x27;, [restaurantId]);    return fallbackResult.rows;  }}&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;div class=&quot;callout&quot; role=&quot;note&quot; data-type=&quot;tip&quot;&gt;
&lt;p class=&quot;callout-title&quot;&gt;Cache Stampede Prevention&lt;/p&gt;
&lt;p&gt;যখন কোনো জনপ্রিয় খাবারের ক্যাশ মেয়াদ শেষ (TTL Expire) হয়ে যায়, তখন একসাথে হাজার হাজার রিকোয়েস্ট মূল ডেটাবেজে আঘাত করতে পারে, যাকে Cache Stampede বলা হয়। এটি রোধ করার জন্য Mutex Lock বা Distributed Lock ব্যবহার করুন, যাতে শুধুমাত্র একটি থ্রেড ডেটাবেজ থেকে ডেটা এনে ক্যাশ আপডেট করতে পারে।&lt;/p&gt;
&lt;/div&gt;
&lt;hr&gt;
&lt;h2 id=&quot;কেস-স্টাডি-৫-দ্য-মনোলিথ-ব্রেকডাউন-ও-৫০-জন-ডেভেলপার-microservices-event-driven-flow&quot;&gt;কেস স্টাডি ৫: দ্য মনোলিথ ব্রেকডাউন ও ৫০ জন ডেভেলপার (Microservices &amp;#x26; Event-Driven Flow)&lt;/h2&gt;
&lt;p&gt;FoodFast এখন একটি বিশাল প্রতিষ্ঠানে পরিণত হয়েছে। আপনাদের ইঞ্জিনিয়ারিং টিমে এখন ৫০ জনেরও বেশি সফটওয়্যার ডেভেলপার, টেস্টার এবং ডেভঅপস ইঞ্জিনিয়ার কাজ করছেন। কিন্তু এত বড় টিম হওয়ার পরেও আপনারা লক্ষ্য করলেন যে, নতুন কোনো ফিচার রিলিজ করতে এখন আগের চেয়ে অনেক বেশি সময় লাগছে। এর মূল কারণ হলো আপনাদের সেই পুরনো Monolith কোডবেস। পুরো প্ল্যাটফর্মের সমস্ত লজিক (ইউজার অথেনটিকেশন, রেস্টুরেন্ট অনবোর্ডিং, কার্ট ম্যানেজমেন্ট, পেমেন্ট প্রসেসিং, ডেলিভারি রাইডার ম্যাচিং, এবং নোটিফিকেশন সিস্টেম) একটি মাত্র বিশাল রিপোজিটরিতে বন্দি হয়ে আছে।&lt;/p&gt;
&lt;p&gt;এই মনোলিথিক সিস্টেমে Tight Coupling তৈরি হয়েছে। একজন জুনিয়র ডেভেলপার যখন নোটিফিকেশন মডিউলের ইমেইল টেম্পলেট পরিবর্তন করার চেষ্টা করল, তখন একটি ছোট সিনট্যাক্স এররের কারণে পুরো পেমেন্ট সিস্টেম ক্র্যাশ করে বসল। প্রতিদিন ৫০ জন ডেভেলপার যখন একই কোডবেসে কোড পুশ করছে, তখন গিট কনফ্লিক্ত লেগেই থাকছে। একটি ছোট বাগ ফিক্স করে প্রোডাকশনে ডিপ্লয় করতে পুরো বিশাল মনোলিথ অ্যাপ্লিকেশন বিল্ড এবং টেস্ট করতে কয়েক ঘণ্টা সময় লেগে যাচ্ছে। এছাড়া স্কেলিং করার সময় আমরা শুধু পেমেন্ট সার্ভিস স্কেল করতে পারছিলাম না; আমাদের পুরো মনোলিথ সার্ভার স্কেল করতে হচ্ছিল, যা মারাত্মক Resource Wastage।&lt;/p&gt;
&lt;p&gt;এই ইঞ্জিনিয়ারিং দুঃস্বপ্ন থেকে বাঁচতে আমরা আমাদের পুরো সিস্টেমকে Microservices Architecture-এ রূপান্তর করার সিদ্ধান্ত নিই। আমরা ডোমেইন-ড্রাইভেন ডিজাইন (Domain-Driven Design) অনুসরণ করে আমাদের মনোলিথকে ছোট ছোট স্বাধীন সার্ভিসে ভেঙে ফেলি। আমরা তৈরি করি Auth Service, Restaurant Service, Order Service, Payment Service, Rider Matching Service এবং Notification Service। প্রতিটি মাইক্রোসার্ভিসের নিজস্ব ডেডিকেটেড ডেটাবেজ এবং স্বাধীন ডিপ্লয়মেন্ট পাইপলাইন তৈরি করা হয়। এখন পেমেন্ট টিমের ইঞ্জিনিয়াররা অন্য কোনো টিমের ওপর নির্ভর না করে দিনে ১০ বার তাদের সার্ভিস প্রোডাকশনে ডিপ্লয় করতে পারেন।&lt;/p&gt;
&lt;p&gt;ক্লায়েন্ট অ্যাপ্লিকেশন এবং এই অসংখ্য মাইক্রোসার্ভিসের মাঝে আমরা একটি Single Entry Point হিসেবে API Gateway বসাই। ক্লায়েন্টকে এখন প্রতিটি সার্ভিসের আলাদা আইপি বা ইউআরএল চিনতে হয় না। API Gateway সমস্ত রিকোয়েস্ট গ্রহণ করে, Authentication এবং SSL Termination সম্পন্ন করে, এবং সঠিক মাইক্রোসার্ভিসে রিকোয়েস্ট রাউট করে দেয়। সার্ভিস থেকে সার্ভিসে কথা বলার জন্য আমরা দুই ধরনের কমিউনিকেশন প্যাটার্ন ব্যবহার করি। যখন কোনো ইনস্ট্যান্ট রেসপন্স দরকার হয় (যেমন: অর্ডার প্লেস করার সময় ইউজার অথেনটিকেটেড কিনা তা যাচাই করা), তখন আমরা Synchronous Communication হিসেবে gRPC বা REST প্রটোকল ব্যবহার করি। gRPC প্রটোকল Protocol Buffers ব্যবহার করে বাইনারি ফরম্যাটে ডেটা আদান-প্রদান করে, যা সাধারণ JSON-এর চেয়ে ১০ গুণ দ্রুত কাজ করে।&lt;/p&gt;
&lt;p&gt;আর যে সমস্ত কাজে ইনস্ট্যান্ট উত্তরের প্রয়োজন নেই, সেখানে আমরা Asynchronous Communication ইমপ্লিমেন্ট করি। উদাহরণস্বরূপ, যখন কোনো ইউজার একটি খাবারের অর্ডার সফলভাবে প্লেস করে, তখন Order Service সরাসরি Notification Service বা Billing Service-কে কল করে বসে থাকে না। এর পরিবর্তে Order Service একটি Message Broker বা Event Bus (যেমন: Apache Kafka বা RabbitMQ)-এ একটি &lt;code&gt;OrderCreatedEvent&lt;/code&gt; মেসেজ পুশ করে দেয়। Kafka ক্লাস্টারের সেই টপিক থেকে Payment Service, Notification Service এবং Analytics Service স্বাধীনভাবে মেসেজটি কনজিউম করে এবং তাদের নিজ নিজ কাজ (যেমন: ইনভয়েস তৈরি করা, এসএমএস পাঠানো, ও রাইডার খোঁজা) ব্যাকগ্রাউন্ডে সম্পন্ন করে। এই Event-Driven Architecture আমাদের সিস্টেমকে অত্যন্ত ফাস্ট, লুজলি কাপলড এবং স্কেলেবল করে তোলে।&lt;/p&gt;
&lt;figure&gt;&lt;img src=&quot;https://raw.githubusercontent.com/rafeuddaraj/rafes-blog-assets/refs/heads/ultimate-system-design-handbook-case-study-global-scale/assets/microservices-event-driven-flow.svg&quot; alt=&quot;Microservices Architecture and Event-Driven Kafka Flow&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1000&quot; height=&quot;520&quot;&gt;&lt;figcaption&gt;Microservices Architecture and Event-Driven Kafka Flow&lt;/figcaption&gt;&lt;/figure&gt;
&lt;hr&gt;
&lt;h2 id=&quot;কেস-স্টাডি-৬-সিস্টেম-যখন-অমর-ও-বিপর্যয়-মোকাবেলা-fault-tolerance-rate-limiting-observability&quot;&gt;কেস স্টাডি ৬: সিস্টেম যখন অমর ও বিপর্যয় মোকাবেলা (Fault Tolerance, Rate Limiting &amp;#x26; Observability)&lt;/h2&gt;
&lt;p&gt;ডিস্ট্রিবিউটেড মাইক্রোসার্ভিস সিস্টেমে একটি ধ্রুব সত্য হলো: &quot;যেকোনো কিছু যেকোনো সময় ফেইল করতে পারে।&quot; একদিন শুক্রবার রাতে পিক আওয়ারে আমাদের থার্ড-পার্টি পেমেন্ট গেটওয়ে পার্টনারের সার্ভারে যান্ত্রিক ত্রুটি দেখা দিল। তারা পেমেন্ট রিকোয়েস্টের উত্তর দিতে ৩০ সেকেন্ডের বেশি সময় নিচ্ছিল। আমাদের FoodFast-এর Payment Service সেই উত্তরের আশায় অপেক্ষা করতে করতে তার সমস্ত থ্রেড এবং কানেকশন পুল ব্লক করে ফেলল। যেহেতু Order Service সিঙ্ক্রোনাসভাবে Payment Service-এর ওপর নির্ভরশীল ছিল, তাই Order Service-ও ক্র্যাশ করল। দেখতে দেখতে এই Cascading Failure-এর কারণে আমাদের পুরো মাইক্রোসার্ভিস ইকোসিস্টেম ডমিনোর মতো তাসের ঘরের মতো ভেঙে পড়ল।&lt;/p&gt;
&lt;p&gt;এই ভয়াবহ অভিজ্ঞতা থেকে শিক্ষা নিয়ে আমরা আমাদের আর্কিটেকচারে Fault Tolerance বা বিপর্যয় সহনশীলতা ইমপ্লিমেন্ট করি। আমরা প্রতিটি সার্ভিসের মাঝে Circuit Breaker Pattern যুক্ত করি। বৈদ্যুতিক সার্কিট ব্রেকার যেমন অতিরিক্ত ভোল্টেজ আসলে ট্রিপ করে ঘরকে দুর্ঘটনার হাত থেকে বাঁচায়, সফটওয়্যার সার্কিট ব্রেকারও ঠিক একই কাজ করে। আমরা Resilience4j বা Hystrix কনসেপ্ট ব্যবহার করে লজিক সেট করি যে, যদি কোনো সার্ভিস ১০ সেকেন্ডের মধ্যে ৫০ শতাংশ রিকোয়েস্টে টাইমআউট বা এরর দেয়, তবে সার্কিট ব্রেকার &quot;Open&quot; হয়ে যাবে। সার্কিট ওপেন থাকা অবস্থায় আমাদের সিস্টেম সেই অকেজো সার্ভিসে আর কোনো রিকোয়েস্ট পাঠাবে না, বরং তাৎক্ষণিক একটি Fallback Response রিটার্ন করবে (যেমন: &quot;পেমেন্ট সেবা সাময়িক বিঘ্নিত হচ্ছে, আপনার অর্ডারটি ক্যাশ অন ডেলিভারিতে রূপান্তর করা হলো&quot;)। এর ফলে মেইন থ্রেড ব্লক হয় না এবং সিস্টেম সচল থাকে।&lt;/p&gt;
&lt;p&gt;একই সাথে আমরা আমাদের সিস্টেমকে হ্যাকারদের ও ক্ষতিকারক বট (Bots)-এর হাত থেকে বাঁচাতে Rate Limiting ইমপ্লিমেন্ট করি। আমরা Token Bucket বা Leaky Bucket অ্যালগরিদম ব্যবহার করে API Gateway লেয়ারে নিয়ম সেট করে দিই যে, একটি নির্দিষ্ট আইপি বা ইউজার অ্যাকাউন্ট প্রতি সেকেন্ডে সর্বোচ্চ ২০টির বেশি রিকোয়েস্ট পাঠাতে পারবে না। যদি কেউ এর চেয়ে বেশি রিকোয়েস্ট পাঠায় (যেমন: কোনো প্রতিযোগী প্রতিষ্ঠান যদি আমাদের মেনু স্ক্র্যাপ করার চেষ্টা করে বা DDoS অ্যাটাক দেয়), তবে লোড ব্যালেন্সার তাকে তাৎক্ষণিক &lt;code&gt;429 Too Many Requests&lt;/code&gt; স্ট্যাটাস কোড দিয়ে ব্লক করে দেবে।&lt;/p&gt;
&lt;p&gt;অবশেষে, ৫০টি মাইক্রোসার্ভিসের হাজার হাজার সার্ভারে কোথায় কী ঘটছে, তা অন্ধের মতো অনুমান না করে আমরা Observability বা পর্যবেক্ষণ ব্যবস্থা গড়ে তুলি। আমরা তিনটি স্তম্ভের ওপর ভিত্তি করে এই ব্যবস্থা তৈরি করি: Logging, Metrics, এবং Tracing। আমরা প্রতিটি মাইক্রোসার্ভিস থেকে লগ সংগ্রহ করে ELK Stack (Elasticsearch, Logstash, Kibana)-এ পাঠাই। সার্ভারের CPU, মেমরি, এবং রিকোয়েস্ট ল্যাটেন্সি মাপার জন্য আমরা Prometheus ব্যবহার করে রিয়েল-টাইম মেট্রিক্স সংগ্রহ করি এবং Grafana ড্যাশবোর্ডে তা ভিজ্যুয়ালাইজ করি। আর একটি রিকোয়েস্ট API Gateway থেকে শুরু করে কোন কোন মাইক্রোসার্ভিস হয়ে ডেটাবেজ পর্যন্ত গেল, তার সম্পূর্ণ পথ ট্র্যাক করার জন্য আমরা Jaeger বা Zipkin ব্যবহার করে Distributed Tracing ইমপ্লিমেন্ট করি। এখন কোনো রিকোয়েস্ট স্লো হলে আমরা ড্যাশবোর্ড দেখেই ১ সেকেন্ডে বলে দিতে পারি ঠিক কোন সার্ভিসের কোন কুয়েরিটি ল্যাটেন্সি তৈরি করছে।&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame has-title&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;TypeScript&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;typescript&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#8B949E&quot;&gt;// circuit-breaker-pattern.ts&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#8B949E&quot;&gt;// Production-ready implementation of Circuit Breaker using Opossum library pattern&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; CircuitBreaker &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;&apos;opossum&apos;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; axios &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;&apos;axios&apos;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#8B949E&quot;&gt;// The potentially unreliable external service call (e.g., Bank Payment Gateway)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;async&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;function&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D2A8FF&quot;&gt;callExternalPaymentGateway&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#FFA657&quot;&gt;payload&lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;any&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FFA657&quot;&gt;Promise&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;any&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;response&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;await&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; axios.&lt;/span&gt;&lt;span style=&quot;--0:#D2A8FF&quot;&gt;post&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;&apos;https://bank-gateway.external.com/api/v1/charge&apos;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;, payload, {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;timeout: &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;3000&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#8B949E&quot;&gt;// Strict 3 seconds timeout to prevent thread blocking&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;});&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; response.data;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#8B949E&quot;&gt;// Circuit Breaker configuration options for FoodFast payment service&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;breakerOptions&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;timeout: &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;3500&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#8B949E&quot;&gt;// If function execution takes longer than 3.5s, trigger a failure&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;errorThresholdPercentage: &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;50&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#8B949E&quot;&gt;// When 50% of requests fail, trip the circuit to OPEN&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;resetTimeout: &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;30000&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#8B949E&quot;&gt;// After 30 seconds, transition to HALF-OPEN state to test service health&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;};&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;paymentCircuitBreaker&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D2A8FF&quot;&gt;CircuitBreaker&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;(callExternalPaymentGateway, breakerOptions);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#8B949E&quot;&gt;// Fallback logic executed immediately when Circuit is OPEN or service fails&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;paymentCircuitBreaker.&lt;/span&gt;&lt;span style=&quot;--0:#D2A8FF&quot;&gt;fallback&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;((&lt;/span&gt;&lt;span style=&quot;--0:#FFA657&quot;&gt;payload&lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;any&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#FFA657&quot;&gt;error&lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;any&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;=&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;console.&lt;/span&gt;&lt;span style=&quot;--0:#D2A8FF&quot;&gt;warn&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;`[Circuit Breaker OPEN] Payment gateway failed for order ${&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;payload&lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;orderId&lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;}. Executing fallback.`&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;status: &lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;&apos;ACCEPTED_FALLBACK&apos;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;paymentMethod: &lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;&apos;CASH_ON_DELIVERY&apos;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;message: &lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;&apos;Online payment is temporarily unavailable. Order converted to Cash on Delivery.&apos;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;originalError: error.message,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;};&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;});&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;paymentCircuitBreaker.&lt;/span&gt;&lt;span style=&quot;--0:#D2A8FF&quot;&gt;on&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;&apos;open&apos;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;, () &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;=&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; console.&lt;/span&gt;&lt;span style=&quot;--0:#D2A8FF&quot;&gt;error&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;&apos;CRITICAL ALERT: Payment Circuit Breaker TRIPPED to OPEN!&apos;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;));&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;paymentCircuitBreaker.&lt;/span&gt;&lt;span style=&quot;--0:#D2A8FF&quot;&gt;on&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;&apos;halfOpen&apos;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;, () &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;=&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; console.&lt;/span&gt;&lt;span style=&quot;--0:#D2A8FF&quot;&gt;info&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;&apos;Payment Circuit Breaker is HALF-OPEN. Testing gateway health...&apos;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;));&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;paymentCircuitBreaker.&lt;/span&gt;&lt;span style=&quot;--0:#D2A8FF&quot;&gt;on&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;&apos;close&apos;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;, () &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;=&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; console.&lt;/span&gt;&lt;span style=&quot;--0:#D2A8FF&quot;&gt;info&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;&apos;Payment Circuit Breaker CLOSED. Gateway operating normally.&apos;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;));&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;export&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;async&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;function&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D2A8FF&quot;&gt;processOrderPayment&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#FFA657&quot;&gt;payload&lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;any&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FFA657&quot;&gt;Promise&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;any&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;await&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; paymentCircuitBreaker.&lt;/span&gt;&lt;span style=&quot;--0:#D2A8FF&quot;&gt;fire&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;(payload);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;// circuit-breaker-pattern.ts// Production-ready implementation of Circuit Breaker using Opossum library patternimport CircuitBreaker from &amp;#x27;opossum&amp;#x27;;import axios from &amp;#x27;axios&amp;#x27;;// The potentially unreliable external service call (e.g., Bank Payment Gateway)async function callExternalPaymentGateway(payload: any): Promise&lt;any&gt; {  const response = await axios.post(&amp;#x27;https://bank-gateway.external.com/api/v1/charge&amp;#x27;, payload, {    timeout: 3000, // Strict 3 seconds timeout to prevent thread blocking  });  return response.data;}// Circuit Breaker configuration options for FoodFast payment serviceconst breakerOptions = {  timeout: 3500, // If function execution takes longer than 3.5s, trigger a failure  errorThresholdPercentage: 50, // When 50% of requests fail, trip the circuit to OPEN  resetTimeout: 30000, // After 30 seconds, transition to HALF-OPEN state to test service health};const paymentCircuitBreaker = new CircuitBreaker(callExternalPaymentGateway, breakerOptions);// Fallback logic executed immediately when Circuit is OPEN or service failspaymentCircuitBreaker.fallback((payload: any, error: any) =&gt; {  console.warn(&amp;#x60;[Circuit Breaker OPEN] Payment gateway failed for order ${payload.orderId}. Executing fallback.&amp;#x60;);  return {    status: &amp;#x27;ACCEPTED_FALLBACK&amp;#x27;,    paymentMethod: &amp;#x27;CASH_ON_DELIVERY&amp;#x27;,    message: &amp;#x27;Online payment is temporarily unavailable. Order converted to Cash on Delivery.&amp;#x27;,    originalError: error.message,  };});paymentCircuitBreaker.on(&amp;#x27;open&amp;#x27;, () =&gt; console.error(&amp;#x27;CRITICAL ALERT: Payment Circuit Breaker TRIPPED to OPEN!&amp;#x27;));paymentCircuitBreaker.on(&amp;#x27;halfOpen&amp;#x27;, () =&gt; console.info(&amp;#x27;Payment Circuit Breaker is HALF-OPEN. Testing gateway health...&amp;#x27;));paymentCircuitBreaker.on(&amp;#x27;close&amp;#x27;, () =&gt; console.info(&amp;#x27;Payment Circuit Breaker CLOSED. Gateway operating normally.&amp;#x27;));export async function processOrderPayment(payload: any): Promise&lt;any&gt; {  return await paymentCircuitBreaker.fire(payload);}&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;div class=&quot;callout&quot; role=&quot;note&quot; data-type=&quot;warning&quot;&gt;
&lt;p class=&quot;callout-title&quot;&gt;Distributed Tracing Overhead&lt;/p&gt;
&lt;p&gt;প্রোডাকশন সিস্টেমে ১০০ শতাংশ রিকোয়েস্টের Distributed Tracing চালূ রাখবেন না। এতে প্রচুর নেটওয়ার্ক ব্যান্ডউইথ এবং স্টোরেজ নষ্ট হয়। এর পরিবর্তে ১ শতাংশ বা ৫ শতাংশ রিকোয়েস্ট স্যাম্পলিং (Sampling) করুন, যা সিস্টেমের সামগ্রিক স্বাস্থ্য বোঝার জন্য যথেষ্ট।&lt;/p&gt;
&lt;/div&gt;
&lt;hr&gt;
&lt;h2 id=&quot;কেস-স্টাডি-৭-গ্লোবাল-টেক-জায়ান্টদের-এন্ড-টু-এন্ড-ব্লুপ্রিন্ট-url-shortener-news-feed-video-streaming&quot;&gt;কেস স্টাডি ৭: গ্লোবাল টেক জায়ান্টদের এন্ড-টু-এন্ড ব্লুপ্রিন্ট (URL Shortener, News Feed &amp;#x26; Video Streaming)&lt;/h2&gt;
&lt;p&gt;এতক্ষণ আমরা FoodFast-এর জার্নি দিয়ে সিস্টেম ডিজাইনের বিভিন্ন লেয়ার এবং কম্পোনেন্ট বুঝতে পেরেছি। এখন আমরা আমাদের অর্জিত সমস্ত জ্ঞানকে একসাথে জোড়া দিয়ে দেখব বিশ্বের শীর্ষস্থানীয় প্রযুক্তি প্রতিষ্ঠানগুলো কীভাবে তাদের কোর প্রোডাক্টগুলো স্ক্র্যাচ থেকে ডিজাইন করে। নিচে তিনটি রিয়েল-ওয়ার্ল্ড এন্ড-টু-এন্ড ব্লুপ্রিন্ট আলোচনা করা হলো।&lt;/p&gt;
&lt;h3 id=&quot;কেস-স্টাডি-৭ক-url-shortener-ডিজাইন-bitly-বা-tinyurl-স্টাইল&quot;&gt;কেস স্টাডি ৭ক: URL Shortener ডিজাইন (Bitly বা TinyURL স্টাইল)&lt;/h3&gt;
&lt;p&gt;একটি URL Shortener সার্ভিসের মূল কাজ হলো একটি দীর্ঘ ওয়েব এড্রেসকে ছোট একটি ইউনিক লিঙ্কে রূপান্তর করা এবং সেই ছোট লিঙ্কে ক্লিক করলে ইউজারকে মূল দীর্ঘ লিঙ্কে রিডাইরেক্ট করা।&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;ট্রেড-অফ ও রেশিও অ্যানালাইসিস:&lt;/strong&gt; এই ধরনের সিস্টেমে নতুন লিঙ্ক তৈরির চেয়ে লিঙ্কগুলোতে ক্লিক পড়ার হার অনেক বেশি থাকে। আমরা ধরে নিই এর Read/Write Ratio হলো ১০:১। অর্থাৎ প্রতি সেকেন্ডে যদি ১০০টি নতুন লিঙ্ক তৈরি হয়, তবে প্রতি সেকেন্ডে ১ হাজারটি রিডাইরেক্ট রিকোয়েস্ট আসবে। তাই আমাদের সিস্টেমকে Read-Heavy পারফরম্যান্সের জন্য অপ্টিমাইজ করতে হবে।&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;ইউনিক আইডি জেনারেশন ও এনকোডিং:&lt;/strong&gt; একটি ছোট লিঙ্ক তৈরি করার জন্য আমাদের একটি ৭ অক্ষরের ইউনিক কি (Key) জেনারেশন করতে হবে। আমরা Base62 Encoding (a-z, A-Z, 0-9) ব্যবহার করি। ৭ অক্ষরের Base62 এনকোডিং দিয়ে আমরা &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.8141em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;6&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.8141em;&quot;&gt;&lt;span style=&quot;top:-3.063em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mtight&quot;&gt;7&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; বা প্রায় ৩ লক্ষ ৫০ হাজার কোটি ইউনিক লিঙ্ক তৈরি করতে পারি, যা আগামী ৫০ বছরের জন্য যথেষ্ট। এই ইউনিক কি জেনারেশনের জন্য আমরা ডেটাবেজ অটো-ইনক্রিমেন্টের ওপর নির্ভর না করে Distributed Sequence Generator যেমন Twitter Snowflake বা একটি ডেডিকেটেড Key Generation Service (KGS) ব্যবহার করি। KGS আগে থেকেই লাখ লাখ ইউনিক কি তৈরি করে মেমরিতে রেখে দেয়, ফলে নতুন লিঙ্ক তৈরির সময় কোনো ল্যাটেন্সি থাকে না।&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;ডেটা লেয়ার ও ক্যাশিং:&lt;/strong&gt; সমস্ত Short Key এবং Long URL ম্যাপিং আমরা একটি Horizontally Sharded NoSQL ডেটাবেজে (যেমন: DynamoDB বা Cassandra) সেভ করি, কারণ এখানে কোনো জটিল রিলেশনাল জয়েন কুয়েরির প্রয়োজন নেই। আর রিডাইরেক্ট ল্যাটেন্সি শূন্যের কোঠায় নামিয়ে আনার জন্য আমরা ডেটাবেজের সামনে বিশাল Redis Cache ক্লাস্টার বসাই। যখন কোনো ইউজার ছোট লিঙ্কে হিট করে, সিস্টেম প্রথমে Redis থেকে মূল লিঙ্কটি খুঁজে নেয় এবং ক্লায়েন্টকে &lt;code&gt;301 Permanent Redirect&lt;/code&gt; বা &lt;code&gt;302 Temporary Redirect&lt;/code&gt; স্ট্যাটাস কোড দিয়ে মূল ওয়েবসাইটে পাঠিয়ে দেয়।&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;কেস-স্টাডি-৭খ-news-feed-সিস্টেম-ডিজাইন-facebook-বা-twitter-স্টাইল&quot;&gt;কেস স্টাডি ৭খ: News Feed সিস্টেম ডিজাইন (Facebook বা Twitter স্টাইল)&lt;/h3&gt;
&lt;p&gt;একটি সোশ্যাল মিডিয়া নিউজ ফিডের মূল চ্যালেঞ্জ হলো রিয়েল-টাইমে লাখ লাখ ইউজারের জন্য তাদের ফলো করা বন্ধুদের পোস্টগুলোকে সঠিক ক্রমানুসারে সাজিয়ে প্রদর্শন করা।&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;ফ্যানআউট আর্কিটেকচার (Fan-out on Write vs Read):&lt;/strong&gt; যখন কোনো ইউজার একটি নতুন পোস্ট করে, তখন সেই পোস্টটি তার সমস্ত ফলোয়ারের নিউজ ফিডে পৌঁছে দেওয়ার প্রক্রিয়াকে Fan-out বলা হয়। এখানে দুটি আর্কিটেকচারাল মডেল রয়েছে। প্রথমটি হলো Fan-out on Write (Push Model)। একজন সাধারণ ইউজার যখন পোস্ট করে, তখন আমাদের ব্যাকএন্ড সার্ভিস তার সমস্ত ফলোয়ারের লিস্ট বের করে এবং প্রতিটি ফলোয়ারের ইন-মেমরি ফিড ক্যাশে (Redis Timeline) সরাসরি পোস্টটি পুশ করে দেয়। এর সুবিধা হলো, ফলোয়ার যখন অ্যাপ খোলে, তখন তার ফিড আগে থেকেই তৈরি থাকে এবং লোড হতে কোনো সময় লাগে না।&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;সেলেব্রেটি প্রবলেম ও হাইব্রিড সলিউশন:&lt;/strong&gt; কিন্তু এই Push Model-এ একটি বড় সমস্যা হলো &quot;Celebrity Problem&quot;। ধরুন, কোনো বিখ্যাত সেলিব্রেটির ৫ কোটি ফলোয়ার রয়েছে। তিনি যখন একটি পোস্ট করবেন, তখন ৫ কোটি ইউজারের ক্যাশে সেই পোস্ট পুশ করতে গেলে আমাদের সার্ভারে বিশাল Write Storm তৈরি হবে এবং সিস্টেম ক্র্যাশ করতে পারে। তাই সেলিব্রেটিদের ক্ষেত্রে আমরা Fan-out on Read (Pull Model) ব্যবহার করি। সেলিব্রেটি পোস্ট করলে তা শুধুমাত্র তার নিজের টাইমলাইন ডেটাবেজে সেভ হয়। যখন তার কোনো ফলোয়ার অ্যাপ ওপেন করে, তখন আমাদের Feed Generation Service সাধারণ বন্ধুদের পোস্টগুলো ইন-মেমরি ক্যাশ থেকে নেয় এবং সেলিব্রেটির পোস্টটি মূল ডেটাবেজ থেকে Pull করে এনে একত্রিত করে ফিড তৈরি করে। এই হাইব্রিড মডেলটিই ফেসবুক এবং টুইটার প্রোডাকশনে ব্যবহার করে।&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;কেস-স্টাডি-৭গ-video-streaming-প্ল্যাটফর্ম-ডিজাইন-youtube-বা-netflix-স্টাইল&quot;&gt;কেস স্টাডি ৭গ: Video Streaming প্ল্যাটফর্ম ডিজাইন (YouTube বা Netflix স্টাইল)&lt;/h3&gt;
&lt;p&gt;একটি ভিডিও স্ট্রিমিং প্ল্যাটফর্মের প্রধান চ্যালেঞ্জ হলো বিশাল আকারের ভিডিও ফাইল হ্যান্ডেল করা, নেটওয়ার্ক ব্যান্ডউইথ অপ্টিমাইজ করা এবং যেকোনো ইন্টারনেটের গতিতে বাফারিং ছাড়া ভিডিও প্রদর্শন করা।&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;ভিডিও ইনজেশন ও ডিস্ট্রিবিউটেড ট্রান্সকোডিং:&lt;/strong&gt; যখন কোনো কন্টেন্ট ক্রিয়েটর একটি ৪কে (4K) রেজোলিউশনের র-ভিডিও আপলোড করে, তখন সেটি সরাসরি ক্লায়েন্টকে দেখানো অসম্ভব। আপলোড হওয়া ভিডিওটি প্রথমে একটি Object Storage (যেমন: AWS S3 বা Google Cloud Storage)-এ সেভ হয়। এরপর আমাদের সিস্টেম একটি Message Queue (Kafka)-এ একটি ট্রান্সকোডিং ইভেন্ট পুশ করে। আমাদের ব্যাকগ্রাউন্ডে থাকা শত শত Transcoding Workers সেই ইভেন্ট গ্রহণ করে এবং FFmpeg টুল ব্যবহার করে মূল ভিডিওটিকে বিভিন্ন রেজোলিউশনে (1080p, 720p, 480p, 360p) রূপান্তর বা Transcode করে।&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;চাঙ্কিং ও অ্যাডাপ্টিভ বিটরেট স্ট্রিমিং (ABR):&lt;/strong&gt; ট্রান্সকোডিং করার সময় প্রতিটি রেজোলিউশনের ভিডিওকে ছোট ছোট ২ থেকে ৪ সেকেন্ডের টুকরো বা Chunks-এ ভাগ করা হয় (যেমন: &lt;code&gt;.ts&lt;/code&gt; বা &lt;code&gt;.m4s&lt;/code&gt; ফাইল) এবং একটি Master Playlist বা Manifest ফাইল (যেমন: &lt;code&gt;.m3u8&lt;/code&gt; বা &lt;code&gt;.mpd&lt;/code&gt;) তৈরি করা হয়। এই পুরো প্রক্রিয়াকে Adaptive Bitrate Streaming (HLS বা DASH প্রোটোকল) বলা হয়।&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;সিডিএন এজ ডেলিভারি ও ক্লায়েন্ট প্লেয়ার:&lt;/strong&gt; এই সমস্ত ছোট ছোট ভিডিও চঙ্ক এবং ম্যানিফেসট ফাইলগুলো আমরা Global CDN Edge Servers-এ পাঠিয়ে দিই। যখন কোনো ইউজার ভিডিও প্লে করে, তখন তার ব্রাউজারের ভিডিও প্লেয়ার প্রথমে ম্যানিফেসট ফাইলটি ডাউনলোড করে। ইউজারের ইন্টারনেটের গতি যদি ভালো থাকে, তবে প্লেয়ার স্বয়ংক্রিয়ভাবে 1080p রেজোলিউশনের চঙ্কগুলো সিডিএন থেকে ডাউনলোড করে প্লে করে। আর যদি ইন্টারনেটের গতি হঠাৎ কমে যায়, তবে প্লেয়ার ভিডিও থামিয়ে বাফারিং না করে পরবর্তী চঙ্কটি 360p রেজোলিউশনে ডাউনলোড করে স্মুথ প্লেব্যাক বজায় রাখে।&lt;/li&gt;
&lt;/ul&gt;
&lt;figure&gt;&lt;img src=&quot;https://raw.githubusercontent.com/rafeuddaraj/rafes-blog-assets/refs/heads/ultimate-system-design-handbook-case-study-global-scale/assets/video-streaming-transcoding-pipeline.svg&quot; alt=&quot;YouTube and Netflix Video Streaming Transcoding Pipeline&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1000&quot; height=&quot;500&quot;&gt;&lt;figcaption&gt;YouTube and Netflix Video Streaming Transcoding Pipeline&lt;/figcaption&gt;&lt;/figure&gt;
&lt;hr&gt;
&lt;h2 id=&quot;ডেভেলপার-চেকলিস্ট-ও-প্রোডাকশন-গাইডলাইন&quot;&gt;ডেভেলপার চেকলিস্ট ও প্রোডাকশন গাইডলাইন&lt;/h2&gt;
&lt;p&gt;একটি সফল সিস্টেম ডিজাইন হলো সঠিক সময়ে সঠিক ট্রেড-অফটি বেছে নেওয়া। আপনি যখনই কোনো নতুন প্রজেক্টের আর্কিটেকচার ডিজাইন করবেন বা পুরনো সিস্টেম রিফ্যাক্টর করবেন, তখন নিচের প্রোডাকশন-রেডি চেকলিস্টটি মিলিয়ে নেবেন। এটি আপনাকে সম্ভাব্য ইঞ্জিনিয়ারিং বিপর্যয় থেকে রক্ষা করবে।&lt;/p&gt;
&lt;ul class=&quot;contains-task-list&quot;&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; disabled aria-label=&quot;স্কেলেবিলিটি ও স্টেটলেসনেস: আপনার Web Server এবং API সার্ভারগুলো কি সম্পূর্ণ Stateless হিসেবে কনফিগার করা হয়েছে? কোনো স&quot;&gt; &lt;strong&gt;স্কেলেবিলিটি ও স্টেটলেসনেস:&lt;/strong&gt; আপনার Web Server এবং API সার্ভারগুলো কি সম্পূর্ণ Stateless হিসেবে কনফিগার করা হয়েছে? কোনো সার্ভার হঠাৎ বন্ধ হয়ে গেলে ক্লায়েন্টের সেশন বা ডেটা নষ্ট হবে না তো?&lt;/li&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; disabled aria-label=&quot;ক্যাশিং ও এক্সপাইরি পলিসি: আপনার ক্যাশ মেমরিতে কি সঠিক LRU বা LFU Eviction Policy সেট করা আছে? প্রতিটি ক্যাশ কি (Key)-এর&quot;&gt; &lt;strong&gt;ক্যাশিং ও এক্সপাইরি পলিসি:&lt;/strong&gt; আপনার ক্যাশ মেমরিতে কি সঠিক LRU বা LFU Eviction Policy সেট করা আছে? প্রতিটি ক্যাশ কি (Key)-এর সাথে কি যৌক্তিক TTL (Time To Live) নির্ধারণ করা হয়েছে যাতে মেমরি লিক না হয়?&lt;/li&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; disabled aria-label=&quot;ডেটাবেজ ও ইনডেক্সিং: ডেটাবেজের যে কলামগুলো দিয়ে ঘন ঘন সার্চ বা ফিল্টার করা হয়, সেগুলোতে কি B-Tree Indexing করা হয়েছে?&quot;&gt; &lt;strong&gt;ডেটাবেজ ও ইনডেক্সিং:&lt;/strong&gt; ডেটাবেজের যে কলামগুলো দিয়ে ঘন ঘন সার্চ বা ফিল্টার করা হয়, সেগুলোতে কি B-Tree Indexing করা হয়েছে? আপনার কুয়েরিগুলো কি Full Table Scan করছে নাকি Index Scan করছে তা &lt;code&gt;EXPLAIN ANALYZE&lt;/code&gt; চালিয়ে যাচাই করেছেন কি?&lt;/li&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; disabled aria-label=&quot;সিঙ্ক্রোনাস বনাম অ্যাসিঙ্ক্রোনাস: যে সমস্ত টাস্কের ইনস্ট্যান্ট উত্তরের প্রয়োজন নেই (যেমন: ইমেইল পাঠানো, পিডিএফ জেনারেশন&quot;&gt; &lt;strong&gt;সিঙ্ক্রোনাস বনাম অ্যাসিঙ্ক্রোনাস:&lt;/strong&gt; যে সমস্ত টাস্কের ইনস্ট্যান্ট উত্তরের প্রয়োজন নেই (যেমন: ইমেইল পাঠানো, পিডিএফ জেনারেশন, অ্যানালিটিক্স ডেটা সেভ করা), সেগুলো কি Message Queue (Kafka/RabbitMQ) দিয়ে ব্যাকগ্রাউন্ড ওয়ারকারে পাঠানো হচ্ছে?&lt;/li&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; disabled aria-label=&quot;ফল্ট টলারেন্স ও সার্কিট ব্রেকার: থার্ড-পার্টি সার্ভিস বা মাইক্রোসার্ভিস কলের সময় কি সঠিক Timeout এবং Circuit Breaker Pa&quot;&gt; &lt;strong&gt;ফল্ট টলারেন্স ও সার্কিট ব্রেকার:&lt;/strong&gt; থার্ড-পার্টি সার্ভিস বা মাইক্রোসার্ভিস কলের সময় কি সঠিক Timeout এবং Circuit Breaker Pattern ইমপ্লিমেন্ট করা হয়েছে, যাতে Cascading Failure রোধ করা যায়?&lt;/li&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; disabled aria-label=&quot;রেট লিমিটিং ও সিকিউরিটি: আপনার API Gateway-তে কি Token Bucket অ্যালগরিদম ব্যবহার করে Rate Limiting কনফিগার করা আছে, যাতে&quot;&gt; &lt;strong&gt;রেট লিমিটিং ও সিকিউরিটি:&lt;/strong&gt; আপনার API Gateway-তে কি Token Bucket অ্যালগরিদম ব্যবহার করে Rate Limiting কনফিগার করা আছে, যাতে হ্যাকারদের ও ক্ষতিকারক বট অ্যাটাক থেকে সার্ভার সুরক্ষিত থাকে?&lt;/li&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; disabled aria-label=&quot;সিঙ্গেল পয়েন্ট অব ফেইলার (SPOF): আপনার আর্কিটেকচারের প্রতিটি লেয়ারে (লোড ব্যালেন্সার, ডেটাবেজ, ক্যাশ ক্লাস্টার) কি Red&quot;&gt; &lt;strong&gt;সিঙ্গেল পয়েন্ট অব ফেইলার (SPOF):&lt;/strong&gt; আপনার আর্কিটেকচারের প্রতিটি লেয়ারে (লোড ব্যালেন্সার, ডেটাবেজ, ক্যাশ ক্লাস্টার) কি Redundancy বা ব্যাকআপ নোড রাখা হয়েছে? কোনো একটি মেশিন পুড়ে গেলেও কি সিস্টেম শূন্য ডাউনটাইমে চলতে পারবে?&lt;/li&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; disabled aria-label=&quot;অবজারভেবিলিটি ও অ্যালার্টিং: প্রোডাকশন সার্ভারের রিয়েল-টাইম মেট্রিক্স (CPU, Memory, Latency) দেখার জন্য কি Prometheus এ&quot;&gt; &lt;strong&gt;অবজারভেবিলিটি ও অ্যালার্টিং:&lt;/strong&gt; প্রোডাকশন সার্ভারের রিয়েল-টাইম মেট্রিক্স (CPU, Memory, Latency) দেখার জন্য কি Prometheus এবং Grafana ড্যাশবোর্ড সেটআপ করা হয়েছে? কোনো সার্ভিস ডাউন হলে আপনার অন-কল ইঞ্জিনিয়ারের কাছে স্বয়ংক্রিয় অ্যালার্ট পৌঁছানোর ব্যবস্থা আছে কি?&lt;/li&gt;
&lt;/ul&gt;</content:encoded><category>System Design</category><category>System Design</category><category>Software Architecture</category><category>Microservices</category><category>Scalability</category><category>Database Sharding</category><category>Caching Strategies</category><category>Load Balancing</category><category>Fault Tolerance</category><category>Kafka</category><category>High Availability</category></item><item><title>Deep Dive: গবেষণা গুগলের, বাজিমাৎ ওপেনআই-এর - জেনারেটিভ এআই-এর আন্ডার-দ্য-হুড আর্কিটেকচার</title><link>https://www.rafeuddaraj.me/bn/blog/generative-ai-under-the-hood-google-vs-openai-deep-dive/</link><guid isPermaLink="true">https://www.rafeuddaraj.me/bn/blog/generative-ai-under-the-hood-google-vs-openai-deep-dive/</guid><description>জেনারেটিভ এআই বিপ্লবের পেছনে গুগলের ২০১৭ সালের Transformer আর্কিটেকচার কীভাবে কাজ করে এবং কেন ওপেনআই ফার্স্ট-মুভার অ্যাডভান্টেজ নিল, তার একটি রিচেবল ও রেফারেন্স-সমৃদ্ধ ইঞ্জিনিয়ারিং ডিপ-ডাইভ।</description><pubDate>Sat, 04 Jul 2026 19:34:25 GMT</pubDate><content:encoded>&lt;p&gt;সাধারণ প্রযুক্তি ব্যবহারকারী থেকে শুরু করে অনেক জুনিয়র সফটওয়্যার ইঞ্জিনিয়ারদের মধ্যেও একটি সাধারণ ধারণা রয়েছে যে, আজকের Generative AI বা Large Language Model (LLM) বিপ্লবের সম্পূর্ণ কৃতিত্ব OpenAI-এর। আমরা যখন ChatGPT, Claude কিংবা Gemini-এর মতো শক্তিশালী মডেলগুলোর সাথে কথা বলি, তখন মনে হয় এই প্রযুক্তির জন্ম হয়েছে ওপেনআই-এর নিজস্ব ল্যাবে। কিন্তু আপনি যদি এই প্রযুক্তির Under-the-hood আর্কিটেকচারে প্রবেশ করেন, তবে দেখতে পাবেন এর পেছনের আসল কারিগর আসলে অন্য কেউ। এই পুরো রেভোলিউশনের মূল মেরুদণ্ড লুকিয়ে আছে ২০১৭ সালে প্রকাশিত গুগলের একটি ঐতিহাসিক &lt;a href=&quot;https://arxiv.org/abs/1706.03762&quot; rel=&quot;noopener noreferrer&quot;&gt;Research Paper&lt;/a&gt;-এর মধ্যে।&lt;/p&gt;
&lt;p&gt;আজকের এই ডিপ-ডাইভ সেশনে আমরা বিশ্লেষণ করব কীভাবে গুগলের আবিষ্কার করা একটি যুগান্তকারী আর্কিটেকচার প্রযুক্তি দুনিয়ার হিসাব-নিকাশ বদলে দিল, কেন গুগল নিজে ফার্স্ট-মুভার অ্যাডভান্টেজ নিতে ব্যর্থ হলো, এবং কীভাবে OpenAI সেই ওপেন-সোর্স প্রযুক্তি ব্যবহার করে টেক দুনিয়ার সবচেয়ে বড় ভ্যালু ক্যাপচার বা আইডিয়া হাইজ্যাক সম্পন্ন করল। এই আর্টিকেলের শেষে আপনার জন্য সকল অরিজিনাল রিসার্চ পেপার এবং টেকনিক্যাল ডকুমেন্টেশনের রেফারেন্স লিংক যুক্ত করে দেওয়া হয়েছে।&lt;/p&gt;
&lt;h2 id=&quot;ইন্ট্রোডাকশন-টেক-দুনিয়ার-সেই-ঐতিহাসিক-মোড়&quot;&gt;ইন্ট্রোডাকশন: টেক দুনিয়ার সেই ঐতিহাসিক মোড়&lt;/h2&gt;
&lt;p&gt;২০১৭ সালের মাঝামাঝি সময়। গুগলের ব্রেইন টিম এবং গুগল রিসার্চের আটজন বিজ্ঞানী মিলে একটি গবেষণাপত্র প্রকাশ করলেন, যার শিরোনাম ছিল &lt;a href=&quot;https://arxiv.org/abs/1706.03762&quot; rel=&quot;noopener noreferrer&quot;&gt;Attention Is All You Need&lt;/a&gt;। সেই সময়ে এই পেপারটি একাডেমিক মহলে বেশ সাড়া ফেললেও সাধারণ টেক ইন্ডাস্ট্রিতে এটি যে কত বড় ভূমিকম্প তৈরি করতে যাচ্ছে, তা অনেকে অনুমান করতে পারেননি।&lt;/p&gt;
&lt;p&gt;এই গবেষণাপত্রেই বিশ্ব প্রথমবারের মতো পরিচিত হয় &lt;code&gt;Transformer Architecture&lt;/code&gt;-এর সাথে। আপনি আজকে যে চ্যাটজিপিটি ব্যবহার করছেন, তার নামের শেষের &quot;T&quot; অক্ষরটি কিন্তু এই Transformer-কে নির্দেশ করে (Generative Pre-trained Transformer)। অর্থাৎ, চ্যাটজিপিটি যে কোর ইঞ্জিনের ওপর ভর করে আপনার জটিল কোড ডিবাগ করছে বা ন্যাচারাল ল্যাঙ্গুয়েজে উত্তর দিচ্ছে, সেই ইঞ্জিনটি সম্পূর্ণ গুগলের ল্যাবে তৈরি। গুগল তাদের এই যুগান্তকারী আবিষ্কারকে নিজেদের মধ্যে কুক্ষিগত না রেখে ডেভলপার কমিউনিটির জন্য ওপেন-সোর্স করে দেয়, আর ঠিক এই পয়েন্ট থেকেই শুরু হয় টেক ইতিহাসের অন্যতম বড় স্ট্র্যাটেজিক শিফট।&lt;/p&gt;
&lt;h2 id=&quot;ফাউন্ডেশনাল-মেন্টাল-মডেল-এবং-অ্যানালজি&quot;&gt;ফাউন্ডেশনাল মেন্টাল মডেল এবং অ্যানালজি&lt;/h2&gt;
&lt;p&gt;টেকনিক্যাল আর্কিটেকচারে প্রবেশের আগে পুরো ঘটনাটিকে একটি বাস্তব জীবনের Analogy দিয়ে বোঝার চেষ্টা করা যাক। ধরুন, একটি অত্যন্ত সুপরিচিত এবং বিশ্বসেরা রেস্তোরাঁ চেইন (Google) তাদের নিজস্ব ল্যাবে বছরের পর বছর গবেষণা করে সম্পূর্ণ নতুন এবং অসাধারণ স্বাদের একটি বিরিয়ানির রেসিপি (Transformer Architecture) আবিষ্কার করল। এই রেসিপিটি এতটাই উন্নত ছিল যে খুব কম খরচে এবং দ্রুততম সময়ে লাখ লাখ মানুষের জন্য খাবার তৈরি করা সম্ভব।&lt;/p&gt;
&lt;p&gt;কিন্তু সেই রেস্তোরাঁ চেইনটি তাদের নিজস্ব নিয়মিত খাবারের মান নষ্ট হওয়ার ভয়ে এবং ব্যবসায়িক ঝুঁকির কারণে নতুন রেসিপিটি নিজেদের মেন্যুতে যুক্ত করতে গড়িমসি করছিল। এর পরিবর্তে তারা রেসিপিটি একটি উন্মুক্ত রান্নার বইয়ে প্রকাশ করে দিল, যেন দুনিয়ার যে কেউ এটি দেখতে পায়।&lt;/p&gt;
&lt;p&gt;ঠিক তখনই একটি ছোট কিন্তু অত্যন্ত উচ্চাকাঙ্ক্ষী ক্যাটারিং স্টার্টআপ (OpenAI) সেই উন্মুক্ত রেসিপিটি সংগ্রহ করল। তারা বুঝতে পারল, রেসিপিটি সাধারণ হলেও এর আসল ম্যাজিক লুকিয়ে আছে বিশাল আকারের রান্নাঘর (Supercomputing Power) এবং বিপুল পরিমাণ কাঁচামালের (Big Data) ব্যবহারে। তারা দ্রুত বিশাল ইনফ্রাস্ট্রাকচার তৈরি করে সেই রেসিপি দিয়ে সুস্বাদু বিরিয়ানি রান্না করে সরাসরি কাস্টমারদের টেবিলে পরিবেশন (ChatGPT Launch) করা শুরু করল। কাস্টমাররা খাবারের স্বাদে মুগ্ধ হয়ে মনে করল এই অসাধারণ রেসিপি এবং রান্নার পুরো কৃতিত্বই সেই নতুন স্টার্টআপের। বাস্তবে রেসিপিটি ছিল গুগলের, কিন্তু সঠিক সময়ে স্কেল করে এক্সিকিউশন করার মাধ্যমে বাজার দখল করে নিল ওপেনআই।&lt;/p&gt;
&lt;h2 id=&quot;আন্ডার-দ্য-হুড-আর্কিটেকচার-কী-ছিল-সেই-transformer-প্রযুক্তিতে&quot;&gt;আন্ডার-দ্য-হুড আর্কিটেকচার: কী ছিল সেই &quot;Transformer&quot; প্রযুক্তিতে?&lt;/h2&gt;
&lt;p&gt;কেন গুগলের এই আবিষ্কার এত গুরুত্বপূর্ণ ছিল? এটি বোঝার জন্য আমাদের দেখতে হবে ট্রান্সফরমার আসার আগে এআই মডেলগুলো কীভাবে কাজ করত। ২০১৭ সালের আগে ন্যাচারাল ল্যাঙ্গুয়েজ প্রসেসিং বা NLP-এর জন্য মূলত ব্যবহার করা হতো RNN (Recurrent Neural Networks) এবং LSTM (Long Short-Term Memory) আর্কিটেকচার।&lt;/p&gt;
&lt;p&gt;পুরানো এই RNN মডেলগুলোর সবচেয়ে বড় সীমাবদ্ধতা ছিল Sequential Processing বা ধাপে ধাপে ডাটা প্রসেস করা। আপনি যদি একটি ২০ শব্দের বাক্য ইনপুট দেন, তবে রিকারেন্ট নেটওয়ার্ক প্রথম শব্দ থেকে শুরু করে একে একে শেষ শব্দ পর্যন্ত যেত। এই প্রক্রিয়ায় দুটি বড় ইঞ্জিনিয়ারিং বটলনেক তৈরি হতো:&lt;/p&gt;
&lt;p&gt;প্রথমত, এটি ছিল অত্যন্ত স্লো। যেহেতু প্রতিটি টোকেন তার আগের টোকেনের প্রসেসিং শেষ হওয়ার ওপর নির্ভর করত, তাই এখানে GPU-এর প্যারালাল প্রসেসিং পাওয়ার ব্যবহার করা যেত না। এর Time Complexity এবং মেমোরি বটলনেক ছিল মারাত্মক। দ্বিতীয়ত, বাক্যের দৈর্ঘ্য বড় হলেই মডেলটি আগের শব্দের রেফারেন্স বা Long-term Context ভুলে যেত, যাকে বলা হয় Vanishing Gradient সমস্যা।&lt;/p&gt;
&lt;figure&gt;&lt;img src=&quot;https://raw.githubusercontent.com/rafeuddaraj/rafes-blog-assets/refs/heads/generative-ai-under-the-hood-google-vs-openai-deep-dive/assets/transformer-architecture-workflow.svg&quot; alt=&quot;Sequential RNN Processing vs Parallel Transformer Self-Attention Workflow&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;800&quot; height=&quot;450&quot;&gt;&lt;figcaption&gt;Sequential RNN Processing vs Parallel Transformer Self-Attention Workflow&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;গুগলের বিজ্ঞানীরা এই সমস্যার সমাধানে নিয়ে এলেন Self-Attention Mechanism। রিকারেন্ট নেটওয়ার্কের মতো একটার পর একটা শব্দ প্রসেস না করে, ট্রান্সফরমার আর্কিটেকচার পুরো বাক্যের সবগুলি শব্দকে একই সাথে (Parallel Processing) মেমোরিতে লোড করে। সেলফ-অ্যাটেনশন মেকানিজম একটি বাক্যের প্রতিটি শব্দের সাথে অন্য প্রতিটি শব্দের সম্পর্ক বা Attention Weight গাণিতিকভাবে হিসাব করে নেয়।&lt;/p&gt;
&lt;p&gt;উদাহরণস্বরূপ, &quot;সার্ভারটি ক্র্যাশ করেছে কারণ এটি ওভারলোডেড ছিল&quot; এই বাক্যে &quot;এটি&quot; শব্দটি যে আসলে &quot;সার্ভারটি&quot;-কে নির্দেশ করছে, রিকারেন্ট নেটওয়ার্ক তা বুঝতে হিমশিম খেত। কিন্তু গুগলের সেলফ-অ্যাটেনশন মেকানিজম হাই-ডাইমেনশনাল ভেক্টর স্পেসের মাধ্যমে চোখের পলকে এই সম্পর্ক ম্যাপ করে ফেলতে পারে। এর ফলে প্রসেসিং স্পিড বহুগুণ বেড়ে যায় এবং আধুনিক GPU বা TPU ক্লাস্টারে একে স্কেল করা অবিশ্বাস্য রকমের সহজ হয়ে ওঠে। এই বিষয়ে আরও বিস্তারিত জানা যাবে গুগলের অরিজিনাল &lt;a href=&quot;https://research.google/blog/transformer-a-novel-neural-network-architecture-for-language-understanding&quot; rel=&quot;noopener noreferrer&quot;&gt;Google Research Blog Post&lt;/a&gt; থেকে।&lt;/p&gt;
&lt;h2 id=&quot;স্টেপ-বাই-স্টেপ-এক্সিকিউশন-ট্রেস-এবং-কোড-মেকানিজম&quot;&gt;স্টেপ-বাই-স্টেপ এক্সিকিউশন ট্রেস এবং কোড মেকানিজম&lt;/h2&gt;
&lt;p&gt;আপনি যখন চ্যাটজিপিটি বা জেমিনিতে একটি প্রম্পট দেন, তখন আন্ডার-দ্য-হুড কীভাবে এই ডাটা ফ্লো কাজ করে, তা একটি এক্সিকিউশন ট্রেস দিয়ে বোঝা যাক। আমরা যদি ইঞ্জিনের ভেতরের মেমোরি লেআউট এবং পাইপলাইন ট্রেস করি, তবে নিচের ধাপগুলো দেখতে পাব:&lt;/p&gt;
&lt;p&gt;ধাপ ১ - Tokenization: আপনার ইনপুট টেক্সটটি প্রথমে ছোট ছোট টুকরো বা টোকেনে বিভক্ত হয়। প্রতিটি টোকেন একটি নির্দিষ্ট নিউম্যারিক আইডিতে রূপান্তর হয়।&lt;/p&gt;
&lt;p&gt;ধাপ ২ - Embedding &amp;#x26; Positional Encoding: যেহেতু ট্রান্সফরমার আর্কিটেকচার সব শব্দ একসাথে প্যারালালি প্রসেস করে, তাই শব্দের ক্রম বা অর্ডারিং মনে রাখার জন্য গুগলের বিজ্ঞানীরা Positional Encoding ব্যবহার করেন। প্রতিটি টোকেনের এমবেডিং ভেক্টরের সাথে তার অবস্থানের একটি গাণিতিক সিগনেচার যুক্ত করে হাই-ডাইমেনশনাল ভেক্টর তৈরি করা হয়।&lt;/p&gt;
&lt;p&gt;ধাপ ৩ - Multi-Head Self-Attention: এটিই গুগলের মূল ম্যাজিক ব্লক। এখানে প্রতিটি টোকেনের জন্য তিনটি ভেক্টর তৈরি হয়: Query (Q), Key (K), এবং Value (V)। এই ভেক্টরগুলোর Matrix Multiplication-এর মাধ্যমে মডেল হিসাব করে কোন টোকেনের প্রতি কতটুকু গুরুত্ব বা অ্যাটেনশন দিতে হবে। একাধিক অ্যাটেনশন হেড প্যারালালি কাজ করে বাক্যের সিনট্যাক্স, গ্রামার এবং কনটেক্সট আলাদাভাবে ক্যাপচার করে।&lt;/p&gt;
&lt;p&gt;ধাপ ৪ - Feed-Forward Network &amp;#x26; Normalization: অ্যাটেনশন ব্লক থেকে পাওয়া ডাটা প্রতিটি লেয়ারে Feed-Forward Neural Network এবং Layer Normalization-এর মধ্য দিয়ে গিয়ে আরও রিফাইন হয়।&lt;/p&gt;
&lt;p&gt;ধাপ ৫ - Output Generation (Softmax): সবশেষে, মডেলটি তার ভোকাবুলারির সমস্ত টোকেনের ওপর একটি Probability Distribution তৈরি করে এবং পরবর্তী সবচেয়ে সম্ভাব্য টোকেনটি প্রেডিক্ট করে। এই পুরো সাইকেলটি প্রতি মিলি-সেকেন্ডে হাজার হাজার বার লুপ করে আপনার স্ক্রিনে উত্তর জেনারেট করে।&lt;/p&gt;
&lt;h2 id=&quot;গুগলের-ভুল-নাকি-অতিরিক্ত-সতর্কতা&quot;&gt;গুগলের ভুল নাকি অতিরিক্ত সতর্কতা?&lt;/h2&gt;
&lt;p&gt;এখন সবচেয়ে বড় প্রশ্ন হলো, যে প্রযুক্তি গুগল নিজে আবিষ্কার করল, সেটি দিয়ে কেন তারা চ্যাটজিপিটির মতো কোনো প্রোডাক্ট সবার আগে বাজারে ছাড়তে পারল না? এটি কি তাদের ইঞ্জিনিয়ারিং ব্যর্থতা ছিল? মোটেই না। এটি ছিল মূলত কর্পোরেট কালচার এবং বিজনেস মডেলের কনফ্লিক্ট।&lt;/p&gt;
&lt;p&gt;প্রথম কারণ ছিল রেপুটেশন রিস্ক এবং হ্যালুসিনেশন ভীতি। একটি মাল্টি-বিলিয়ন ডলারের পাবলিক কোম্পানি হিসেবে গুগলের বিশ্বজুড়ে বিশাল বিশ্বাসযোগ্যতা রয়েছে। এই লার্জ ল্যাঙ্গুয়েজ মডেলগুলোর একটি বড় সমস্যা হলো Hallucination বা অত্যন্ত আত্মবিশ্বাসের সাথে ভুল তথ্য প্রদান করা। গুগলের লিডারশিপ ভয় পাচ্ছিল যে, যদি তারা একটি অপূর্ণাঙ্গ চ্যাটবট পাবলিকলি রিলিজ করে এবং সেটি ভুল বা বায়াসড উত্তর দেয়, তবে গুগলের সার্চ ইঞ্জিনের বিশ্বাসযোগ্যতা মারাত্মকভাবে ক্ষুণ্ন হবে।&lt;/p&gt;
&lt;p&gt;দ্বিতীয় এবং সবচেয়ে বড় কারণ ছিল Innovator&apos;s Dilemma বা বিজনেস মডেল ক্যানিবালাইজেশন। গুগলের মূল আয় আসে তাদের সার্চ ইঞ্জিন এবং অ্যাডভার্টাইজমেন্ট ব্যবসা থেকে। আপনি যখন গুগলে কিছু সার্চ করেন, তখন আপনাকে বিভিন্ন ওয়েবসাইটের লিংক দেখানো হয় এবং সেই সাথে বিজ্ঞাপন প্রদর্শিত হয়। এখন গুগল যদি এমন একটি চ্যাটবট এনে দেয় যা সরাসরি আপনার প্রশ্নের উত্তর দিয়ে দেবে, তবে ইউজাররা আর লিঙ্কে ক্লিক করবে না বা বিজ্ঞাপন দেখবে না। নিজেদের শত কোটি ডলারের বিজ্ঞাপন ব্যবসাকে নিজেদের হাতেই ধ্বংস করার ঝুঁকিতে যেতে গুগল অত্যন্ত দ্বিধাগ্রস্ত ছিল।&lt;/p&gt;
&lt;h2 id=&quot;ওপেনআই-এর-এন্ট্রি-এবং-মাস্টারস্ট্রোক&quot;&gt;ওপেনআই-এর এন্ট্রি এবং মাস্টারস্ট্রোক&lt;/h2&gt;
&lt;p&gt;গুগল যখন তাদের ল্যাবে বসে মডেলের সেফটি এবং রেভিনিউ মডেল নিয়ে অতিরিক্ত বিশ্লেষণে ব্যস্ত ছিল, ঠিক তখনই মাঠে নামে OpenAI। তারা গুগলের এই ওপেন-সোর্স ট্রান্সফরমার আর্কিটেকচারের সত্যিকারের পটেনশিয়াল বুঝতে পেরেছিল। ওপেনআই একটি সহজ সূত্রে বিশ্বাস করেছিল যাকে বলা হয় Scaling Laws। তারা বুঝতে পেরেছিল, এই ট্রান্সফরমার মডেলের প্যারামিটার এবং ট্রেনিং ডাটা যদি এক্সপোনেনশিয়ালি বাড়ানো যায়, তবে মডেলের মধ্যে স্বয়ংক্রিয়ভাবে অসাধারণ সব লজিক্যাল এবং রিজনিং ক্ষমতা তৈরি হবে।&lt;/p&gt;
&lt;p&gt;তারা একে একে প্রকাশ করল &lt;a href=&quot;https://cdn.openai.com/research-covers/language-unsupervised/language_understanding_paper.pdf&quot; rel=&quot;noopener noreferrer&quot;&gt;GPT-1 Technical Paper (2018)&lt;/a&gt; (১১৭ মিলিয়ন প্যারামিটার), GPT-2 (১.৫ বিলিয়ন প্যারামিটার), এবং ঐতিহাসিক &lt;a href=&quot;https://arxiv.org/abs/2005.14165&quot; rel=&quot;noopener noreferrer&quot;&gt;GPT-3 Technical Paper (2020)&lt;/a&gt; (১৭৫ বিলিয়ন প্যারামিটার)। কিন্তু ওপেনআই-এর আসল মাস্টারস্ট্রোক শুধু মডেল তৈরিতে ছিল না, তাদের মাস্টারস্ট্রোক ছিল প্রোডাক্ট ডেলিভারি এবং ইউজার ইন্টারফেস ডিজাইনে।&lt;/p&gt;
&lt;p&gt;২০২২ সালের নভেম্বরে তারা যখন ChatGPT রিলিজ করে, তখন তারা কোনো জটিল API বা টেকনিক্যাল কনসোল দেয়নি। তারা সাধারণ মানুষের জন্য অত্যন্ত পরিচিত এবং সহজ একটি চ্যাট ইন্টারফেস উন্মুক্ত করে দেয়। যে কেউ কোনো টেকনিক্যাল জ্ঞান ছাড়াই এর সাথে কথা বলতে পারত। এই একটি পদক্ষেপেই তারা পুরো সিলিকন ভ্যালিকে চমকে দিয়ে ফার্স্ট-মুভার অ্যাডভান্টেজ দখল করে নেয়।&lt;/p&gt;
&lt;div class=&quot;callout&quot; role=&quot;note&quot; data-type=&quot;note&quot;&gt;
&lt;p class=&quot;callout-title&quot;&gt;Important&lt;/p&gt;
&lt;p&gt;UI/UX এবং অ্যাক্সেসিবিলিটি অ্যাডভান্টেজ: প্রযুক্তি বা কোর ইনফ্রাস্ট্রাকচার আন্ডার-দ্য-হুড যতই শক্তিশালী হোক না কেন, এন্ড-ইউজারের জন্য যদি একটি সিম্পল এবং স্বজ্ঞাত ইন্টারফেস তৈরি করা না যায়, তবে সেই প্রযুক্তি ম্যাস-অ্যাদপশন পায় না। চ্যাটজিপিটি-এর ইন্টারফেসের সরলতাই ছিল এর এক্সপোনেনশিয়াল গ্রোথের অন্যতম বড় চাবিকাঠি।&lt;/p&gt;
&lt;/div&gt;
&lt;h2 id=&quot;এটি-কি-চুরি-নাকি-ওপেন-সোর্সের-নিয়ম&quot;&gt;এটি কি চুরি, নাকি ওপেন-সোর্সের নিয়ম?&lt;/h2&gt;
&lt;p&gt;সাধারণ মানুষের মনে প্রশ্ন জাগতে পারে, গুগলের আবিষ্কার করা প্রযুক্তি দিয়ে ওপেনআই ব্যবসা করছে, এটিকে কি আইনি ভাষায় &quot;চুরি&quot; বলা যায়? এর উত্তর হলো, আইনি দৃষ্টিকোণ থেকে এটিকে কোনোভাবেই চুরি বলা যাবে না।&lt;/p&gt;
&lt;p&gt;গুগল তাদের &quot;Attention Is All You Need&quot; পেপারের সাথে যে কোড এবং আর্কিটেকচার প্রকাশ করেছিল, তা ওপেন-সোর্স লাইসেন্সের আওতায় ছিল। ওপেন-সোর্স সংস্কৃতির মূল নিয়মই হলো, যে কেউ এই প্রযুক্তি ব্যবহার করতে পারবে, মডিফাই করতে পারবে, এবং চাইলে তা দিয়ে বাণিজ্যিক প্রোডাক্টও তৈরি করতে পারবে। ওপেনআই ঠিক সেই আইনি এবং ওপেন-সোর্স নিয়মের মধ্য থেকেই কাজ করেছে।&lt;/p&gt;
&lt;p&gt;তবে ব্যবসায়িক এবং কৌশলগত দৃষ্টিকোণ থেকে এটিকে টেক ইতিহাসের অন্যতম বড় &quot;আইডিয়া হাইজ্যাক&quot; বা &quot;Value Capture Failure&quot; বলা হয়। গবেষণা ও উদ্ভাবনের পেছনে কোটি কোটি ডলার এবং বছরের পর বছর সময় ব্যয় করল গুগলের বিজ্ঞানী দল, আর সেই প্রযুক্তির চূড়ান্ত বাণিজ্যিক সুবিধা এবং মার্কেট লিডারশিপ নিয়ে গেল তুলনামূলকভাবে একটি ছোট স্টার্টআপ।&lt;/p&gt;
&lt;p&gt;এই ঘটনার আরও একটি বড় ট্র্যাজেডি হলো Talent Drain। গুগলের যে আটজন বিজ্ঞানী এই ঐতিহাসিক ট্রান্সফরমার পেপারটি লিখেছিলেন, চ্যাটজিপিটি রিলিজ হওয়ার পরবর্তী কয়েক বছরের মধ্যে তাদের সবাই গুগল ছেড়ে চলে যান। তারা গুগলের ধীরগতির কর্পোরেট সিদ্ধান্তে হতাশ হয়ে নিজেরা আলাদা এআই স্টার্টআপ প্রতিষ্ঠা করেন। যেমন, &lt;a href=&quot;https://en.wikipedia.org/wiki/Ashish_Vaswani&quot; rel=&quot;noopener noreferrer&quot;&gt;Ashish Vaswani&lt;/a&gt; এবং &lt;a href=&quot;https://share.google/XklSybxSwldbKWK0q&quot; rel=&quot;noopener noreferrer&quot;&gt;Niki Parmar&lt;/a&gt; মিলে প্রতিষ্ঠা করেন &lt;a href=&quot;https://www.essential.ai/&quot; rel=&quot;noopener noreferrer&quot;&gt;Essential AI&lt;/a&gt;, &lt;a href=&quot;https://en.wikipedia.org/wiki/Aidan_Gomez&quot; rel=&quot;noopener noreferrer&quot;&gt;Aidan Gomez&lt;/a&gt; প্রতিষ্ঠা করেন বর্তমানের অন্যতম সফল এআই কোম্পানি &lt;a href=&quot;https://cohere.com/&quot; rel=&quot;noopener noreferrer&quot;&gt;Cohere&lt;/a&gt;, এবং &lt;a href=&quot;https://en.wikipedia.org/wiki/Noam_Shazeer&quot; rel=&quot;noopener noreferrer&quot;&gt;Noam Shazeer&lt;/a&gt; প্রতিষ্ঠা করেন &lt;a href=&quot;https://character.ai/&quot; rel=&quot;noopener noreferrer&quot;&gt;Character.ai&lt;/a&gt; যা পরবর্তীতে আবার গুগল তাদের ইকোসিস্টেমে ফিরিয়ে আনে।&lt;/p&gt;
&lt;h2 id=&quot;গুগলের-প্যানিক-মোড-এবং-বর্তমান-এআই-যুদ্ধ&quot;&gt;গুগলের প্যানিক মোড এবং বর্তমান এআই যুদ্ধ&lt;/h2&gt;
&lt;p&gt;চ্যাটজিপিটি লঞ্চ হওয়ার মাত্র কয়েক সপ্তাহের মধ্যে এটি ইতিহাসের দ্রুততম ১ মিলিয়ন এবং পরবর্তীতে ১০০ মিলিয়ন অ্যাক্টিভ ইউজারে পৌঁছানোর রেকর্ড গড়ে। এই অভূতপূর্ব সাফল্যে গুগলের হেডকোয়ার্টারে নড়েচড়ে বসে লিডারশিপ। গুগলের সিইও সুন্দর পিচাই কোম্পানির ভেতরে &quot;Code Red&quot; বা সর্বোচ্চ জরুরি অবস্থা জারি করেন। গুগলের প্রতিষ্ঠাতা ল্যারি পেজ এবং সের্গেই ব্রিন অবসর ভেঙে আবার ল্যাবে ফিরে আসেন।&lt;/p&gt;
&lt;p&gt;গুগল বুঝতে পারে তারা রেসে অনেক পিছিয়ে পড়েছে। তড়িঘড়ি করে ২০২৩ সালের শুরুতে তারা বাজারে রিলিজ করে তাদের প্রথম চ্যাটবট &quot;Bard&quot;। কিন্তু তাড়াহুড়ো করে রিলিজ করার কারণে লঞ্চ ইভেন্টেই Bard জেমস ওয়েব স্পেস টেলিস্কোপ নিয়ে একটি ভুল উত্তর দিয়ে বসে, যার ফলে একদিনেই গুগলের শেয়ার বাজার থেকে ১০০ বিলিয়ন ডলারের বেশি মার্কেট ভ্যালু মুছে যায়।&lt;/p&gt;
&lt;figure&gt;&lt;img src=&quot;https://raw.githubusercontent.com/rafeuddaraj/rafes-blog-assets/refs/heads/generative-ai-under-the-hood-google-vs-openai-deep-dive/assets/ai-market-timeline-clash.svg&quot; alt=&quot;Generative AI Market Evolution and Timeline Clash&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;900&quot; height=&quot;390&quot;&gt;&lt;figcaption&gt;Generative AI Market Evolution and Timeline Clash&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;পরবর্তীতে গুগল তাদের ভুল বুঝতে পেরে নিজেদের পুরো এআই স্ট্র্যাটেজি ঢেলে সাজায়। তারা তাদের বিভিন্ন বিক্ষিপ্ত এআই টিমকে (Google Brain এবং DeepMind) একত্রিত করে তৈরি করে Google DeepMind। Bard-কে সম্পূর্ণ রিব্র্যান্ডিং করে প্রকাশ করা হয় &lt;a href=&quot;https://arxiv.org/abs/2312.11805&quot; rel=&quot;noopener noreferrer&quot;&gt;Gemini Technical Architecture&lt;/a&gt;।&lt;/p&gt;
&lt;p&gt;বর্তমানে গুগলের Gemini মডেলগুলো ওপেনআই-এর GPT-4 এবং Omni মডেলগুলোর সাথে সমানে সমানে পাল্লা দিচ্ছে। গুগলের সবচেয়ে বড় সুবিধা হলো তাদের বিশাল ডেটা ইকোসিস্টেম (YouTube, Search, Android) এবং নিজস্ব চিপ ইনফ্রাস্ট্রাকচার (TPU), যা দিয়ে তারা এখন হারানো মার্কেট শেয়ার পুনরুদ্ধার করার চেষ্টা চালিয়ে যাচ্ছে।&lt;/p&gt;
&lt;div class=&quot;callout&quot; role=&quot;note&quot; data-type=&quot;warning&quot;&gt;
&lt;p class=&quot;callout-title&quot;&gt;Warning&lt;/p&gt;
&lt;p&gt;অ্যানালিসিস প্যারালাইসিস এবং মার্কেট টাইমিং: প্রোডাকশন সিস্টেমে ১০০% পারফেকশন এবং জিরো-রিস্ক নিশ্চিত করার অপেক্ষায় বসে থাকলে ফার্স্ট-মুভার অ্যাডভান্টেজ সম্পূর্ণ হাতছাড়া হয়ে যেতে পারে। সফটওয়্যার ইঞ্জিনিয়ারিংয়ে দ্রুত প্রোডাক্ট বাজারে ছেড়ে রিয়েল-ওয়ার্ল্ড ইউজার ফিডব্যাক লুপ তৈরি করা স্ট্যাটিক পারফেকশনের চেয়ে অনেক বেশি কার্যকর।&lt;/p&gt;
&lt;/div&gt;
&lt;h2 id=&quot;উপসংহার-ও-প্রোডাকশন-ডিসিশন-রুলস&quot;&gt;উপসংহার ও প্রোডাকশন ডিসিশন রুলস&lt;/h2&gt;
&lt;p&gt;গবেষণা গুগলের আর বাজিমাৎ ওপেনআই-এর - এই পুরো ঐতিহাসিক ঘটনাটি সফটওয়্যার ইঞ্জিনিয়ার, সিস্টেম আর্কিটেক্ট এবং টেকনোলজি লিডারদের জন্য অত্যন্ত গুরুত্বপূর্ণ কিছু শিক্ষা রেখে গেছে। প্রযুক্তি দুনিয়ায় শুধুমাত্র যুগান্তকারী আইডিয়া বা থিওরিটিক্যাল ইনোভেশন থাকা কখনোই সফলতার গ্যারান্টি দেয় না। সঠিক সময়ে সেই আইডিয়াকে স্কেল করা এবং ইউজার-ফ্রেন্ডলি প্রোডাক্টে রূপান্তর করাই আসল গেম চেঞ্জার।&lt;/p&gt;
&lt;p&gt;একজন সফটওয়্যার আর্কিটেক্ট বা ডেভলপার হিসেবে আপনার দৈনন্দিন প্রজেক্ট এবং সিস্টেম ডিজাইনে এই ডিপ-ডাইভ থেকে নেওয়া নিচের তিনটি Production Decision Rules প্রয়োগ করতে পারেন:&lt;/p&gt;
&lt;p&gt;১. &lt;strong&gt;ইকোসিস্টেম রেডিনেস নিশ্চিত করুন:&lt;/strong&gt; আপনি যদি কোনো ইনোভেশন বা কোর লাইব্রেরি ওপেন-সোর্স করতে চান, তবে সেটি রিলিজ করার আগেই তার ওপর ভিত্তি করে বাণিজ্যিক প্রোডাক্ট বা ইকোসিস্টেম তৈরির প্রস্তুতি আপনার নিজের হাতে থাকতে হবে। অন্যথায় আপনার উদ্ভাবিত ভ্যালু অন্য কেউ ক্যাপচার করে নেবে।&lt;/p&gt;
&lt;p&gt;২. &lt;strong&gt;আইডিয়েশন বনাম এক্সিকিউশন ব্যালেন্স:&lt;/strong&gt; ইঞ্জিনিয়ারিংয়ে Over-engineering বা পারফেকশনের জন্য অনন্তকাল অপেক্ষা করবেন না। একটি Minimum Viable Product (MVP) বা বেসিক কিন্তু ফাংশনাল ভার্সন দ্রুত প্রোডাকশনে ডিপ্লয় করুন। ইউজার কীভাবে আপনার সিস্টেম ব্যবহার করছে, সেই রিয়েল-ওয়ার্ল্ড ডাটাই আপনাকে সঠিক আর্কিটেকচারাল রিফাইনেমেন্ট করতে সাহায্য করবে।&lt;/p&gt;
&lt;p&gt;৩. &lt;strong&gt;অ্যাক্সেসিবিলিটি এবং ইউজার এক্সপেরিয়েন্সকে প্রাধান্য দিন:&lt;/strong&gt; আপনার ব্যাকএন্ডের কোড যত পরিষ্কারই হোক বা ডাটাবেজ যত দ্রুতই কাজ করুক না কেন, এন্ড-ইউজার যদি একটি সহজ ইন্টারফেসের মাধ্যমে সেই ভ্যালু কনজিউম করতে না পারে, তবে পুরো সিস্টেমটি ব্যর্থ। ওপেনআই-এর মতো জটিল আন্ডার-দ্য-হুড আর্কিটেকচারকে সবসময় একটি সিম্পল এবং স্বজ্ঞাত ইন্টারফেসের পেছনে আবৃত রাখার চেষ্টা করুন।&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;রেফারেন্স-এবং-ফার্দার-রিডিং-references-further-reading&quot;&gt;রেফারেন্স এবং ফার্দার রিডিং (References &amp;#x26; Further Reading)&lt;/h2&gt;
&lt;p&gt;আপনি যদি এই আর্কিটেকচার এবং এআই রেভোলিউশনের টেকনিক্যাল বিষয়গুলো নিয়ে আরও গভীরভাবে গবেষণা করতে চান, তবে নিচের অফিসিয়াল হোয়াইটপেপার এবং ডকুমেন্টেশনগুলো পড়তে পারেন:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://arxiv.org/abs/1706.03762&quot; rel=&quot;noopener noreferrer&quot;&gt;Attention Is All You Need (arXiv:1706.03762)&lt;/a&gt;: ২০১৭ সালে প্রকাশিত গুগলের সেই মূল ঐতিহাসিক Research Paper, যেখানে প্রথম Transformer আর্কিটেকচার এবং Self-Attention মেকানিজম ব্যাখ্যা করা হয়েছে।&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://research.google/blog/transformer-a-novel-neural-network-architecture-for-language-understanding&quot; rel=&quot;noopener noreferrer&quot;&gt;Google Research Blog: Transformer A Novel Neural Network Architecture&lt;/a&gt;: গুগল ব্রেইন টিমের নিজস্ব অফিসিয়াল ব্লগ পোস্ট, যেখানে অত্যন্ত সহজ ভাষায় ট্রান্সফরমার আর্কিটেকচারের কাজের ধরন ও প্যারালাল প্রসেসিং সুবিধা তুলে ধরা হয়েছে।&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://cdn.openai.com/research-covers/language-unsupervised/language_understanding_paper.pdf&quot; rel=&quot;noopener noreferrer&quot;&gt;Improving Language Understanding by Generative Pre-Training (GPT-1 Paper)&lt;/a&gt;: ওপেনআই-এর প্রথম গবেষণাপত্র যেখানে তারা গুগলের ট্রান্সফরমার ব্যবহার করে Pre-training এবং Fine-tuning কনসেপ্ট প্রমাণ করে।&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://arxiv.org/abs/2005.14165&quot; rel=&quot;noopener noreferrer&quot;&gt;Language Models are Few-Shot Learners (GPT-3 Paper - arXiv:2005.14165)&lt;/a&gt;: ওপেনআই-এর ১৭৫ বিলিয়ন প্যারামিটার মডেলের পেপার, যা প্রমাণ করেছিল Scaling Laws কীভাবে জেনারেটিভ এআই-এর ম্যাজিক তৈরি করে।&lt;/li&gt;
&lt;li&gt;just &lt;a href=&quot;https://arxiv.org/abs/2312.11805&quot; rel=&quot;noopener noreferrer&quot;&gt;Gemini: A Family of Highly Capable Multimodal Models (arXiv:2312.11805)&lt;/a&gt;: ওপেনআই-এর সাথে প্রতিযোগিতায় ফিরে আসার পর গুগলের রিলিজ করা সর্বাধুনিক Gemini আর্কিটেকচারের অফিসিয়াল টেকনিক্যাল রিপোর্ট।&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://jalammar.github.io/illustrated-transformer/&quot; rel=&quot;noopener noreferrer&quot;&gt;The Illustrated Transformer by Jay Alammar&lt;/a&gt;: আন্ডার-দ্য-হুড ডাটা ফ্লো, ম্যাট্রিক্স মাল্টিপ্লিকেশন এবং অ্যাটেনশন হেড কীভাবে কাজ করে তা ভিজ্যুয়ালি বোঝার জন্য সফটওয়্যার ইঞ্জিনিয়ারদের মাঝে সবচেয়ে জনপ্রিয় ব্লগ।&lt;/li&gt;
&lt;/ul&gt;</content:encoded><category>Artificial Intelligence</category><category>Deep Dive</category><category>Under the hood</category><category>Architecture</category><category>Generative AI</category><category>Transformer</category><category>System Design</category><category>OpenAI</category><category>Google</category><category>References</category></item><item><title>দ্য কমপ্লিট ইঞ্জিনিয়ারিং হ্যান্ডবুক: প্রোডাকশন স্কেলেবিলিটির জন্য Data Structure এবং Algorithm</title><link>https://www.rafeuddaraj.me/bn/blog/the-complete-engineering-handbook-data-structures-and-algorithms-for-production-scalability/</link><guid isPermaLink="true">https://www.rafeuddaraj.me/bn/blog/the-complete-engineering-handbook-data-structures-and-algorithms-for-production-scalability/</guid><description>একটি ডিপ-ডাইভ ইঞ্জিনিয়ারিং গাইড যা রিয়েল-ওয়ার্ল্ড প্রোডাকশন বটেলনেক, মেমোরি লেআউট, Big-O Notation এবং সিস্টেম আর্কিটেকচারের মাধ্যমে Data Structure এবং Algorithm-এর আসল শক্তি প্রকাশ করে।</description><pubDate>Sun, 28 Jun 2026 10:01:14 GMT</pubDate><content:encoded>&lt;h2 id=&quot;কোর-ফিলোসফি-কেন-আমরা-এখানে&quot;&gt;কোর ফিলোসফি (কেন আমরা এখানে?)&lt;/h2&gt;
&lt;p&gt;আপনি খুব যত্ন নিয়ে একটি দুর্দান্ত Web Application তৈরি করলেন। আপনার Localhost Environment-এ দশজন ইউজারের জন্য সবকিছু একদম রকেট স্পিডে কাজ করছে। প্রতিটি Request মিলি-সেকেন্ডে প্রসেস হচ্ছে, এবং Database কুয়েরিগুলো কোনো বিলম্ব ছাড়াই উত্তর দিচ্ছে। কিন্তু যেদিন আপনি আপনার অ্যাপ্লিকেশনটি Production সার্ভারে ডিপ্লয় করলেন এবং ট্রাফিক হঠাৎ বেড়ে এক লাখ ইউজার একযোগে Request পাঠালো, ঠিক তখনই এক ভয়াবহ বিপর্যয় ঘটল। আপনার Server-এর CPU এবং Memory ব্যবহার ১০০ শতাংশে পৌঁছে গেল, API রেসপন্স টাইম কয়েক সেকেন্ড পার হয়ে গেল, এবং শেষ পর্যন্ত পুরো সিস্টেম ক্র্যাশ করল। আপনি কি কখনো গভীরভাবে ভেবে দেখেছেন, কেন Localhost-এ নিখুঁতভাবে কাজ করা কোড Production-এর বাস্তব লোড সামলাতে গিয়ে এভাবে ভেঙে পড়ে?&lt;/p&gt;
&lt;p&gt;আমাদের সফটওয়্যার ইঞ্জিনিয়ারিং ইন্ডাস্ট্রিতে একটি বিশাল ভুল ধারণা রয়েছে। অনেকেই মনে করেন, শুধুমাত্র কোনো একটি প্রোগ্রামিং ভাষার Syntax জানা, যেমন Loop চালানো বা If-Else কন্ডিশন লিখতে পারাই সফটওয়্যার ইঞ্জিনিয়ারিংয়ের মূল ভিত্তি। কিন্তু বাস্তব প্রোডাকশন সিস্টেমে শুধুমাত্র কোড লিখতে পারলেই Scalable সিস্টেম তৈরি করা যায় না। আপনার লেখা কোড যখন চলে, তখন কম্পিউটার কীভাবে Memory বা RAM-এর ভেতরে ডেটা সংরক্ষণ করছে এবং CPU কীভাবে সেই ডেটা প্রসেস করছে, সেই গভীর মেকানিজম না জানলে প্রোডাকশনে Request Bottleneck তৈরি হওয়া অবশ্যম্ভাবী। আপনি যত শক্তিশালী Hardware বা Cloud Server ব্যবহার করুন না কেন, অদক্ষ কোড আর্কিটেকচার পুরো সিস্টেমের কর্মক্ষমতাকে ধ্বংস করে দিতে পারে।&lt;/p&gt;
&lt;p&gt;তাহলে Data Structure আসলে কী? সহজ কথায়, Data Structure হলো কম্পিউটারের Memory বা RAM-এর ভেতরে ডেটাকে অত্যন্ত দক্ষ ও গুছিয়ে রাখার একটি শিল্প। বিষয়টি বোঝার জন্য আমরা একটি বাস্তব জীবনের Analogy বিবেচনা করতে পারি। একটি অত্যন্ত অগোছালো ওয়ার্কশপ বা কারখানার কথা চিন্তা করুন, যেখানে হাজার হাজার যন্ত্রপাতি মেঝেতে এলোমেলোভাবে ছড়িয়ে-ছিটিয়ে আছে। সেই স্তূপ থেকে একটি নির্দিষ্ট স্ক্রু-ড্রাইভার খুঁজে বের করতে আপনার ত্রিশ মিনিট সময় নষ্ট হয়ে যাবে। এবার চিন্তা করুন একটি গুছিয়ে রাখা স্মার্ট টুলবক্সের কথা, যেখানে প্রতিটি যন্ত্রের জন্য আলাদা ও নির্দিষ্ট স্লট রয়েছে। সেই টুলবক্স থেকে আপনি চোখ বন্ধ করেও মাত্র কয়েক সেকেন্ডে সঠিক যন্ত্রটি তুলে নিতে পারবেন। Data Structure হলো আপনার কম্পিউটারের Memory-র জন্য সেই স্মার্ট টুলবক্স, যা ডেটাকে এমনভাবে সাজিয়ে রাখে যাতে প্রয়োজন মাত্রই দ্রুত খুঁজে পাওয়া এবং প্রসেস করা যায়।&lt;/p&gt;
&lt;p&gt;অন্যদিকে, Algorithm হলো সেই গুছিয়ে রাখা ডেটার ওপর কাজ করার জন্য ধাপে ধাপে সাজানো লজিক্যাল ইনস্ট্রাকশন বা রেসিপি। আপনার কাছে পৃথিবীর সেরা টুলবক্স থাকতে পারে, কিন্তু সেই টুলস ব্যবহার করে কীভাবে একটি ইঞ্জিন মেরামত করতে হবে তার সঠিক পদক্ষেপ জানা না থাকলে কোনো কাজই হবে না। ঠিক একইভাবে, শুধুমাত্র ডেটা গুছিয়ে রাখলেই চলবে না, সেই ডেটা থেকে সঠিক তথ্য খুঁজে বের করা বা পরিবর্তন করার সবচেয়ে দ্রুততম লজিক্যাল পথটি বেছে নেওয়াই হলো Algorithm-এর কাজ। একটি উচ্চমানের Scalable সিস্টেম বা API তৈরি করার মূল চাবিকাঠি হলো সঠিক Data Structure-এর সাথে সবচেয়ে অপটিমাইজড Algorithm-এর নিখুঁত কম্বিনেশন। এই দুইয়ের মেলবন্ধন ছাড়া কোনো আধুনিক সফটওয়্যার আর্কিটেকচারই প্রোডাকশন গ্রেড হতে পারে না।&lt;/p&gt;
&lt;h2 id=&quot;পারফরম্যান্স-পরিমাপের-মানদণ্ড-big-o-notation-এবং-trade-offs&quot;&gt;পারফরম্যান্স পরিমাপের মানদণ্ড (Big-O Notation এবং Trade-offs)&lt;/h2&gt;
&lt;p&gt;সফটওয়্যার ইঞ্জিনিয়ার হিসেবে যখন আমরা কোনো কোড বা লজিক লিখি, তখন সেই কোডটি কত দ্রুত কাজ করছে তা পরিমাপ করা অত্যন্ত জরুরি। কিন্তু আপনি যদি সেকেন্ড বা মিলি-সেকেন্ড দিয়ে আপনার কোডের গতি মাপতে যান, তবে সেটি হবে একটি বড় ইঞ্জিনিয়ারিং বোকামি। কারণ সময়ের এই পরিমাপ সম্পূর্ণভাবে নির্ভর করে হার্ডওয়্যারের ক্ষমতার ওপর। আপনার লেখা একটি কোড হয়তো আপনার সর্বাধুনিক শক্তিশালী ল্যাপটপে মাত্র দশ মিলি-সেকেন্ডে রান করছে, কিন্তু একই কোড যখন অন্য কোনো ইউজারের পুরোনো বা কম ক্ষমতার ডিভাইসে চলবে, তখন সেটি রান হতে এক সেকেন্ড সময় লেগে যেতে পারে। তাই আমাদের এমন একটি ইউনিভার্সাল বা সার্বজনীন পরিমাপক স্কেল প্রয়োজন, যা কোনো নির্দিষ্ট Hardware বা প্রসেসরের গতির ওপর নির্ভর করে না, বরং ইনপুট ডেটার আকার বৃদ্ধির সাথে সাথে কোডের কর্মক্ষমতা কীভাবে পরিবর্তিত হয় তা নির্দেশ করে।&lt;/p&gt;
&lt;p&gt;এই ইউনিভার্সাল মানদণ্ডটি হলো Big-O Notation। এটি মূলত আমাদের জানায়, ইনপুট ডেটা বা n&lt;em&gt;n&lt;/em&gt;-এর আকার যদি বাড়তে থাকে, তবে অ্যালগরিদমটি সম্পন্ন হতে প্রয়োজনীয় সময় বা মেমোরি কত দ্রুত হারে বৃদ্ধি পাবে। এখানে আমাদের দুটি প্রধান বিষয় নিয়ে চিন্তা করতে হয়: Time Complexity এবং Space Complexity। Time Complexity নির্দেশ করে কোডটি রান হতে কতটি লজিক্যাল অপারেশন বা ধাপ প্রয়োজন, আর Space Complexity নির্দেশ করে কোডটি রান হওয়ার সময় কম্পিউটারের Memory বা RAM-এ অতিরিক্ত কতটুকু জায়গা দখল করছে। প্রোডাকশন আর্কিটেকচারে এই দুইয়ের মধ্যে একটি ভারসাম্য বা Trade-off বজায় রাখা অত্যন্ত গুরুত্বপূর্ণ। অনেক সময় কোডের গতি বাড়ানোর জন্য আমাদের অতিরিক্ত Memory ব্যবহার করতে হয়, আবার কখনো মেমোরি বাঁচানোর জন্য কিছুটা বেশি প্রসেসিং টাইম মেনে নিতে হয়।&lt;/p&gt;
&lt;p&gt;Big-O Notation-এর প্রধান কয়েকটি রূপ আমাদের প্রতিদিনের ইঞ্জিনিয়ারিং সিদ্ধান্তে প্রভাব ফেলে। এগুলো সহজ ভাষায় নিচে ব্যাখ্যা করা হলো:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;O(1) - Constant Time:&lt;/strong&gt; এটি হলো সর্বশ্রেষ্ঠ পারফরম্যান্স। আপনার সিস্টেমে ডেটা দশটি থাকুক বা এক কোটি থাকুক, এই লজিকটি রান করতে সবসময় একদম একই সময় লাগবে। উদাহরণস্বরূপ, একটি Array থেকে তার Index নম্বর ব্যবহার করে সরাসরি কোনো ডেটা তুলে নেওয়ার সময় ডেটাসেটের আকারের ওপর নির্ভর করে না।&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;O(n) - Linear Time:&lt;/strong&gt; এক্ষেত্রে ইনপুট ডেটা যতগুণ বাড়বে, কোডটি রান করার সময়ও ঠিক ততগুণ বাড়বে। আপনি যদি একটি Array-এর শুরু থেকে শেষ পর্যন্ত Loop চালিয়ে কোনো একটি নির্দিষ্ট ডেটা খোঁজার চেষ্টা করেন, তবে এক কোটি ডেটার জন্য লুপটিকে সর্বোচ্চ এক কোটি বার ঘুরতে হতে পারে।&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;O(log n) - Logarithmic Time:&lt;/strong&gt; এটি অত্যন্ত স্মার্ট এবং দ্রুতগতির একটি পারফরম্যান্স প্যাটার্ন। এই পদ্ধতিতে প্রতি ধাপে খোঁজার জায়গা বা ডেটাসেটকে অর্ধেক করে কেটে বাদ দিয়ে দেওয়া হয়। ফলে ডেটার আকার দ্বিগুণ হলেও কাজের ধাপ বাড়ে মাত্র একটি। বড় ডেটাবেস বা সর্টেড লিস্টে কাজ করার জন্য এটি আদর্শ।&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;O(n^2) - Quadratic Time:&lt;/strong&gt; এটি হলো প্রোডাকশন সিস্টেমের নীরব ঘাতক। যখন আপনি কোনো কোডে Nested Loop ব্যবহার করেন, অর্থাৎ একটি লুপের ভেতরে আরেকটি লুপ চালান, তখন ডেটা কিছুটা বাড়লেই প্রসেসিং টাইম জ্যামিতিক হারে বেড়ে যায়। ডেটা এক হাজার হলে লুপ ঘুরবে দশ লাখ বার, যা মুহূর্তেই আপনার Server-কে ফ্রিজ করে দিতে পারে।&lt;/li&gt;
&lt;/ul&gt;
&lt;figure&gt;&lt;img src=&quot;https://raw.githubusercontent.com/rafeuddaraj/rafes-blog-assets/refs/heads/the-complete-engineering-handbook-data-structures-and-algorithms-for-production-scalability/assets/big-o-performance-curves.svg&quot; alt=&quot;Big-O Complexity Chart - O(1), O(log n), O(n), O(n²) পারফরম্যান্স কার্ভ তুলনা&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;800&quot; height=&quot;500&quot;&gt;&lt;figcaption&gt;Big-O Complexity Chart - O(1), O(log n), O(n), O(n²) পারফরম্যান্স কার্ভ তুলনা&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;উপরের ডায়াগ্রামটি লক্ষ্য করুন। এখানে স্পষ্টভাবে ভিজ্যুয়ালাইজ করা হয়েছে কীভাবে ইনপুট ডেটা বা n&lt;em&gt;n&lt;/em&gt;-এর মান বৃদ্ধির সাথে সাথে বিভিন্ন Big-O Complexity-এর কর্মক্ষমতা পরিবর্তিত হয়। প্রোডাকশন পরিবেশে আমাদের সর্বদা চেষ্টা থাকে কোডকে O(1) বা O(log n)-এর ভেতরে রাখার, এবং যেকোনো মূল্যে O(n^2) বা তার চেয়ে খারাপ লজিক পরিহার করার।&lt;/p&gt;
&lt;h2 id=&quot;মেমোরি-লেআউট-এবং-linear-data-structures-ফাউন্ডেশন&quot;&gt;মেমোরি লেআউট এবং Linear Data Structures (ফাউন্ডেশন)&lt;/h2&gt;
&lt;p&gt;Data Structure গভীরভাবে বোঝার জন্য আমাদের প্রথমে জানতে হবে কম্পিউটারের Memory বা RAM আসলে কীভাবে কাজ করে। আপনি যখন কম্পিউটারে কোনো Variable বা ডেটা তৈরি করেন, তখন সেটি RAM-এর ভেতরে একটি নির্দিষ্ট জায়গায় গিয়ে জমা হয়। RAM-কে আপনি কোটি কোটি ছোট ছোট বাক্সের একটি দীর্ঘ সারি হিসেবে কল্পনা করতে পারেন। প্রতিটি বাক্সে এক Byte করে ডেটা রাখা যায় এবং প্রতিটি বাক্সের একটি নিজস্ব ও অদ্বিতীয় নম্বর বা Memory Address থাকে, ঠিক যেমন শহরের প্রতিটি বাড়ির একটি নির্দিষ্ট হোল্ডিং নম্বর থাকে। যখন CPU কোনো ডেটা পড়তে বা লিখতে চায়, তখন সে সরাসরি সেই Memory Address ধরে যোগাযোগ করে।&lt;/p&gt;
&lt;p&gt;এই মেমোরি লেআউটের ওপর ভিত্তি করে আমরা যে মৌলিক Data Structure-টি সবচেয়ে বেশি ব্যবহার করি, তা হলো Array। Array হলো মেমোরির ভেতরে একদম টানা এবং সিরিয়াল ব্লক বা পরপর সাজানো বাক্সের সমষ্টি। আপনি যখন মেমোরিতে একটি Array ঘোষণা করেন, তখন সিস্টেম আপনার জন্য মেমোরির একটি নির্দিষ্ট স্থান থেকে পরপর কয়েকটি ব্লক বরাদ্দ করে। বিষয়টি বোঝার জন্য আমরা একটি সিনেমার হলের Analogy চিন্তা করতে পারি। সিনেমার হলে যখন আপনি বন্ধুদের সাথে পাশাপাশি বসার জন্য একসাথে পাঁচটি আসন বুকিং করেন, তখন টিকিট কাউন্টার আপনাকে একই সারির পরপর পাঁচটি আসন বরাদ্দ দেয়। Array ঠিক এভাবেই মেমোরিতে টানা জায়গা দখল করে অবস্থান করে।&lt;/p&gt;
&lt;p&gt;Array-তে কোনো একটি ইনডেক্স ধরে ডেটা পড়া বা Read করার কাজ O(1) বা Constant Time-এ ঘটে। কারণ মেমোরিতে ডেটাগুলো পরপর থাকে এবং কম্পিউটার একটি সাধারণ গাণিতিক সূত্র ব্যবহার করে যেকোনো ইনডেক্সের মেমোরি অ্যাড্রেস সরাসরি বের করে ফেলতে পারে। সূত্রটি হলো: Target Address=Base Address+(Index×Size of Element)Target Address=Base Address+(Index×Size of Element)। কিন্তু Array-এর একটি বড় দুর্বলতা হলো মাঝখান থেকে ডেটা ডিলিট বা ইনসার্ট করা। আপনি যদি একটি Array-এর মাঝখানে নতুন কোনো ডেটা ঢোকাতে চান, তবে সেই স্থানের পেছনের সমস্ত ডেটাকে এক ঘর করে ডানদিকে সরিয়ে জায়গা খালি করতে হবে। এক কোটি ডেটার Array হলে এই সরাসরির কাজটি অত্যন্ত ধীরগতির এবং এটি O(n) Time Complexity তৈরি করে।&lt;/p&gt;
&lt;p&gt;এই সীমাবদ্ধতা দূর করার জন্যই আমরা ব্যবহার করি Linked List। Linked List-এর ক্ষেত্রে ডেটাগুলো মেমোরির ভেতরে Array-এর মতো পরপর বা টানা ব্লকে থাকার কোনো প্রয়োজন নেই। মেমোরির যেখানেই ফাঁকা জায়গা পাওয়া যায়, সেখানেই একটি ডেটা ব্লক বা Node বসে যেতে পারে। প্রতিটি Node-এর ভেতরে দুটি জিনিস থাকে: একটি হলো আসল ডেটা, এবং অপরটি হলো পরবর্তী Node-এর Memory Address বা Pointer। এই আর্কিটেকচারটি বোঝার জন্য আমরা একটি ট্রেজার হান্ট বা গুপ্তধন খোঁজার খেলার Analogy ব্যবহার করতে পারি। খেলায় আপনি যখন প্রথম ক্লু বা চিরকুটটি পান, সেখানে লেখা থাকে পরবর্তী চিরকুটটি কোথায় লুকানো আছে। সেই লোকেশনে গিয়ে আপনি দ্বিতীয় চিরকুটটি পান, যা আপনাকে তৃতীয় লোকেশনের পথ দেখায়। Linked List ঠিক এই চেইন পদ্ধতিতে কাজ করে।&lt;/p&gt;
&lt;p&gt;Array এবং Linked List-এর মধ্যে কোনটি আপনি প্রোডাকশনে ব্যবহার করবেন, তা নির্ভর করে আপনার Use Case-এর ওপর। যদি আপনার সিস্টেমে বারবার ইনডেক্স ধরে ডেটা পড়ার প্রয়োজন বেশি থাকে, তবে Array হলো সেরা পছন্দ। কিন্তু যদি আপনার সিস্টেমে প্রতিনিয়ত মাঝখান থেকে ডেটা ইনসার্ট বা ডিলিট করার প্রয়োজন হয় এবং ডেটার আকার আগে থেকে জানা না থাকে, তবে Linked List আপনাকে অনেক বেশি পারফরম্যান্স সুবিধা দেবে, কারণ এখানে ডেটা সরানোর কোনো প্রয়োজন হয় না, শুধু Pointer-এর ঠিকানা বদলে দিলেই কাজ শেষ হয়।&lt;/p&gt;
&lt;figure&gt;&lt;img src=&quot;https://raw.githubusercontent.com/rafeuddaraj/rafes-blog-assets/refs/heads/the-complete-engineering-handbook-data-structures-and-algorithms-for-production-scalability/assets/memory-layout-comparison.svg&quot; alt=&quot;Array vs Linked List মেমোরি লেআউট - Contiguous বনাম Scattered Node আর্কিটেকচার&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;800&quot; height=&quot;450&quot;&gt;&lt;figcaption&gt;Array vs Linked List মেমোরি লেআউট - Contiguous বনাম Scattered Node আর্কিটেকচার&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;Linear Data Structure-এর জগতে আরও দুটি অত্যন্ত গুরুত্বপূর্ণ কনসেপ্ট হলো Stack এবং Queue। Stack কাজ করে LIFO (Last In, First Out) মডেলে। এর একটি চমৎকার Analogy হলো ডাইনিং টেবিলে সাজিয়ে রাখা প্লেটের স্তূপ। আপনি যখন প্লেটগুলো ধুয়ে একটির ওপর আরেকটি সাজিয়ে রাখেন, তখন সবার শেষে যে প্লেটটি আপনি সবার ওপরে রেখেছেন, খাওয়ার সময় সেই উপরের প্লেটটিই সবার আগে তুলে নিতে হয়। সফটওয়্যার ইঞ্জিনিয়ারিংয়ে এর ব্যবহার প্রচুর। যেমন, ওয়েব ব্রাউজারের Back বাটন, কোড এক্সিকিউশনের Call Stack, এবং যেকোনো টেক্সট এডিটরের Undo-Redo ফিচার সম্পূর্ণভাবে Stack-এর LIFO আর্কিটেকচারে কাজ করে।&lt;/p&gt;
&lt;p&gt;অন্যদিকে, Queue কাজ করে FIFO (First In, First Out) মডেলে। এর বাস্তব Analogy হলো ব্যাংকের ক্যাশ কাউন্টারে বা সিনেমার টিকিট কাউন্টারে দাঁড়িয়ে থাকা মানুষের লাইন। যে ব্যক্তি সবার আগে লাইনে এসে দাঁড়াবেন, তিনি সবার আগে সেবা নিয়ে কাউন্টার ত্যাগ করবেন। ব্যাকএন্ড এবং সিস্টেম আর্কিটেকচারে Queue একটি অপরিহার্য উপাদান। Node.js-এর Event Loop, মাইক্রোসার্ভিস আর্কিটেকচারের Background Job Processing, এবং বিপুল পরিমাণ রিকোয়েস্ট সামলানোর জন্য ব্যবহৃত Task Queue বা Message Broker (যেমন RabbitMQ বা Kafka) এই FIFO নীতির ওপর ভিত্তি করেই স্কেল করে।&lt;/p&gt;
&lt;figure&gt;&lt;img src=&quot;https://raw.githubusercontent.com/rafeuddaraj/rafes-blog-assets/refs/heads/the-complete-engineering-handbook-data-structures-and-algorithms-for-production-scalability/assets/stack-vs-queue-execution-flow.svg&quot; alt=&quot;Stack LIFO বনাম Queue FIFO এক্সিকিউশন ফ্লো - Call Stack এবং Event Loop আর্কিটেকচার&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;800&quot; height=&quot;450&quot;&gt;&lt;figcaption&gt;Stack LIFO বনাম Queue FIFO এক্সিকিউশন ফ্লো - Call Stack এবং Event Loop আর্কিটেকচার&lt;/figcaption&gt;&lt;/figure&gt;
&lt;h2 id=&quot;দ্রুততম-ডেটা-লুকআপ-hash-table-এবং-map&quot;&gt;দ্রুততম ডেটা লুকআপ (Hash Table এবং Map)&lt;/h2&gt;
&lt;p&gt;প্রোডাকশন সফটওয়্যার ইঞ্জিনিয়ারিংয়ে আমরা যখন বিশাল আকারের ডেটাসেট নিয়ে কাজ করি, তখন আমাদের প্রধান লক্ষ্য থাকে কত দ্রুত কোনো একটি নির্দিষ্ট ডেটা খুঁজে বের করা যায়। আপনি যদি এক কোটি ইউজারের একটি ডেটাবেস থেকে কোনো একজন ইউজারের ইমেইল অ্যাড্রেস বা প্রোফাইল মাত্র এক মিলি-সেকেন্ডের মধ্যে খুঁজে বের করতে চান, তবে Array বা Linked List দিয়ে সেটি সম্ভব নয়। এই ধরনের অতি দ্রুত লুকআপ বা খোঁজার কাজের জন্য ইঞ্জিনিয়ারদের সবচেয়ে শক্তিশালী অস্ত্র হলো Hash Table বা Map। Hash Table যেকোনো সাইজের ডেটাবেস বা লিস্ট থেকে মাত্র O(1) বা Constant Time-এ ডেটা খুঁজে বের করার ম্যাজিক দেখাতে পারে।&lt;/p&gt;
&lt;p&gt;এই ম্যাজিকের পেছনের মূল শক্তিটি হলো Hashing এবং Hash Function। Hash Function হলো একটি বিশেষ ধরনের ম্যাথমেটিক্যাল অ্যালগরিদম, যা যেকোনো String, নাম্বার বা চাবিকে (Key) ইনপুট হিসেবে গ্রহণ করে এবং একটি নির্দিষ্ট গাণিতিক ক্যালকুলেশন করে সেটিকে একটি পূর্ণসংখ্যা বা Memory Index-এ রূপান্তর করে। উদাহরণস্বরূপ, আপনি যখন &quot;user_1029&quot; চাবিটি Hash Table-এ পাঠাবেন, তখন Hash Function একটি গাণিতিক সূত্র ব্যবহার করে বলে দেবে যে মেমোরির ঠিক ৪২ নম্বর স্লটে এই ইউজারের ডেটা রাখা আছে। পরবর্তীতে যখন আপনি আবার &quot;user_1029&quot; এর ডেটা দেখতে চাইবেন, সিস্টেম কোনো Loop না চালিয়ে সরাসরি Hash Function ব্যবহার করে ৪২ নম্বর স্লট থেকে ডেটাটি আপনার সামনে হাজির করবে।&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;style&gt;.expressive-code{font-family:var(--ec-uiFontFml);font-size:var(--ec-uiFontSize);font-weight:var(--ec-uiFontWg);line-height:var(--ec-uiLineHt);text-size-adjust:none;-webkit-text-size-adjust:none}.expressive-code *:not(:is(svg, svg *)){all:revert;box-sizing:border-box}.expressive-code pre{display:flex;margin:0;padding:0;border:var(--ec-brdWd) solid var(--ec-brdCol);border-radius:calc(var(--ec-brdRad) + var(--ec-brdWd));background:var(--ec-codeBg)}.expressive-code pre:focus-visible{outline:3px solid var(--ec-focusBrd);outline-offset:-3px}.expressive-code pre &gt; code{all:unset;display:block;flex:1 0 100%;padding:var(--ec-codePadBlk) 0;color:var(--ec-codeFg);font-family:var(--ec-codeFontFml);font-size:var(--ec-codeFontSize);font-weight:var(--ec-codeFontWg);line-height:var(--ec-codeLineHt)}.expressive-code pre{overflow-x:auto}.expressive-code pre.wrap .ec-line .code{white-space:pre-wrap;overflow-wrap:break-word;min-width:min(20ch, var(--ecMaxLine, 20ch))}.expressive-code pre.wrap .ec-line .code span.indent{white-space:pre}.expressive-code pre::-webkit-scrollbar,.expressive-code pre::-webkit-scrollbar-track{background-color:inherit;border-radius:calc(var(--ec-brdRad) + var(--ec-brdWd));border-top-left-radius:0;border-top-right-radius:0}.expressive-code pre::-webkit-scrollbar-thumb{background-color:var(--ec-sbThumbCol);border:4px solid transparent;background-clip:content-box;border-radius:10px}.expressive-code pre::-webkit-scrollbar-thumb:hover{background-color:var(--ec-sbThumbHoverCol)}.expressive-code pre::-webkit-scrollbar-corner{background:transparent}.expressive-code .ec-line{direction:ltr;unicode-bidi:isolate;display:grid;grid-template-areas:&apos;gutter code&apos;;grid-template-columns:auto 1fr;position:relative}.expressive-code .ec-line .gutter{grid-area:gutter;color:var(--ec-gtrFg)}.expressive-code .ec-line .gutter &gt; *{pointer-events:none;user-select:none;-webkit-user-select:none}.expressive-code .ec-line .gutter ~ .code{--ecLineBrdCol:var(--ec-gtrBrdCol)}.expressive-code .ec-line.highlight .gutter{color:var(--ec-gtrHlFg)}.expressive-code .ec-line .code{grid-area:code;position:relative;box-sizing:content-box;padding-inline-start:calc(var(--ecIndent, 0ch) + var(--ec-codePadInl) - var(--ecGtrBrdWd));padding-inline-end:var(--ec-codePadInl);text-indent:calc(var(--ecIndent, 0ch) * -1)}.expressive-code .ec-line .code::before,.expressive-code .ec-line .code::after,.expressive-code .ec-line .code :where(*){text-indent:0}.expressive-code .ec-line .code{--ecGtrBrdWd:var(--ec-gtrBrdWd);border-inline-start:var(--ecGtrBrdWd) solid var(--ecLineBrdCol, transparent)}.expressive-code .sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0, 0, 0, 0);white-space:nowrap;border-width:0}.expressive-code .ec-line.mark{--tmLineBgCol:var(--ec-tm-markBg)}.expressive-code .ec-line.mark .code{--ecLineBrdCol:var(--ec-tm-markBrdCol)}.expressive-code .ec-line.ins{--tmLineBgCol:var(--ec-tm-insBg);--tmLabel:var(--ec-tm-insDiffIndContent)}.expressive-code .ec-line.ins .code{--ecLineBrdCol:var(--ec-tm-insBrdCol)}.expressive-code .ec-line.ins .code::before{color:var(--ec-tm-insDiffIndCol)}.expressive-code .ec-line.del{--tmLineBgCol:var(--ec-tm-delBg);--tmLabel:var(--ec-tm-delDiffIndContent)}.expressive-code .ec-line.del .code{--ecLineBrdCol:var(--ec-tm-delBrdCol)}.expressive-code .ec-line.del .code::before{color:var(--ec-tm-delDiffIndCol)}.expressive-code .ec-line.mark,.expressive-code .ec-line.ins,.expressive-code .ec-line.del{background:var(--tmLineBgCol)}.expressive-code .ec-line.mark .code,.expressive-code .ec-line.ins .code,.expressive-code .ec-line.del .code{--ecGtrBrdWd:var(--ec-tm-lineMarkerAccentWd)}.expressive-code .ec-line.mark .code::before,.expressive-code .ec-line.ins .code::before,.expressive-code .ec-line.del .code::before{display:block;position:absolute;left:0;box-sizing:border-box;content:var(--tmLabel, &apos; &apos;);padding-inline-start:var(--ec-tm-lineDiffIndMargLeft);text-align:center;white-space:pre}.expressive-code .ec-line.mark.tm-label .code::before,.expressive-code .ec-line.ins.tm-label .code::before,.expressive-code .ec-line.del.tm-label .code::before{background:var(--ecLineBrdCol);padding:0 calc(var(--ec-tm-lineMarkerLabelPadInl) + var(--ec-tm-lineMarkerAccentWd)) 0 var(--ec-tm-lineMarkerLabelPadInl);color:var(--ec-tm-lineMarkerLabelCol)}.expressive-code .ec-line mark{--tmInlineBgCol:var(--ec-tm-markBg);--tmInlineBrdCol:var(--ec-tm-markBrdCol)}.expressive-code .ec-line ins{--tmInlineBgCol:var(--ec-tm-insBg);--tmInlineBrdCol:var(--ec-tm-insBrdCol)}.expressive-code .ec-line del{--tmInlineBgCol:var(--ec-tm-delBg);--tmInlineBrdCol:var(--ec-tm-delBrdCol)}.expressive-code .ec-line mark,.expressive-code .ec-line ins,.expressive-code .ec-line del{all:unset;display:inline-block;position:relative;--tmBrdL:var(--ec-tm-inlMarkerBrdWd);--tmBrdR:var(--ec-tm-inlMarkerBrdWd);--tmRadL:var(--ec-tm-inlMarkerBrdRad);--tmRadR:var(--ec-tm-inlMarkerBrdRad);margin-inline:0.025rem;padding-inline:var(--ec-tm-inlMarkerPad);border-radius:var(--tmRadL) var(--tmRadR) var(--tmRadR) var(--tmRadL);background:var(--tmInlineBgCol);background-clip:padding-box}.expressive-code .ec-line mark.open-start,.expressive-code .ec-line ins.open-start,.expressive-code .ec-line del.open-start{margin-inline-start:0;padding-inline-start:0;--tmBrdL:0px;--tmRadL:0}.expressive-code .ec-line mark.open-end,.expressive-code .ec-line ins.open-end,.expressive-code .ec-line del.open-end{margin-inline-end:0;padding-inline-end:0;--tmBrdR:0px;--tmRadR:0}.expressive-code .ec-line mark::before,.expressive-code .ec-line ins::before,.expressive-code .ec-line del::before{content:&apos;&apos;;position:absolute;pointer-events:none;display:inline-block;inset:0;border-radius:var(--tmRadL) var(--tmRadR) var(--tmRadR) var(--tmRadL);border:var(--ec-tm-inlMarkerBrdWd) solid var(--tmInlineBrdCol);border-inline-width:var(--tmBrdL) var(--tmBrdR)}.expressive-code .frame{all:unset;position:relative;display:block;--header-border-radius:calc(var(--ec-brdRad) + var(--ec-brdWd));--tab-border-radius:calc(var(--ec-frm-edTabBrdRad) + var(--ec-brdWd));--button-spacing:0.4rem;--code-background:var(--ec-frm-edBg);border-radius:var(--header-border-radius);box-shadow:var(--ec-frm-frameBoxShdCssVal)}.expressive-code .frame .header{display:none;z-index:1;position:relative;border-radius:var(--header-border-radius) var(--header-border-radius) 0 0}.expressive-code .frame.has-title pre,.expressive-code .frame.has-title code,.expressive-code .frame.is-terminal pre,.expressive-code .frame.is-terminal code{border-top:none;border-top-left-radius:0;border-top-right-radius:0}.expressive-code .frame .title:empty:before{content:&apos;\a0&apos;}.expressive-code .frame.has-title:not(.is-terminal){--button-spacing:calc(1.9rem + 2 * (var(--ec-uiPadBlk) + var(--ec-frm-edActTabIndHt)))}.expressive-code .frame.has-title:not(.is-terminal) .title{position:relative;color:var(--ec-frm-edActTabFg);background:var(--ec-frm-edActTabBg);background-clip:padding-box;margin-block-start:var(--ec-frm-edTabsMargBlkStart);padding:calc(var(--ec-uiPadBlk) + var(--ec-frm-edActTabIndHt)) var(--ec-uiPadInl);border:var(--ec-brdWd) solid var(--ec-frm-edActTabBrdCol);border-radius:var(--tab-border-radius) var(--tab-border-radius) 0 0;border-bottom:none;overflow:hidden}.expressive-code .frame.has-title:not(.is-terminal) .title::after{content:&apos;&apos;;position:absolute;pointer-events:none;inset:0;border-top:var(--ec-frm-edActTabIndHt) solid var(--ec-frm-edActTabIndTopCol);border-bottom:var(--ec-frm-edActTabIndHt) solid var(--ec-frm-edActTabIndBtmCol)}.expressive-code .frame.has-title:not(.is-terminal) .header{display:flex;background:linear-gradient(to top, var(--ec-frm-edTabBarBrdBtmCol) var(--ec-brdWd), transparent var(--ec-brdWd)),linear-gradient(var(--ec-frm-edTabBarBg), var(--ec-frm-edTabBarBg));background-repeat:no-repeat;padding-inline-start:var(--ec-frm-edTabsMargInlStart)}.expressive-code .frame.has-title:not(.is-terminal) .header::before{content:&apos;&apos;;position:absolute;pointer-events:none;inset:0;border:var(--ec-brdWd) solid var(--ec-frm-edTabBarBrdCol);border-radius:inherit;border-bottom:none}.expressive-code .frame.is-terminal{--button-spacing:calc(1.9rem + var(--ec-brdWd) + 2 * var(--ec-uiPadBlk));--code-background:var(--ec-frm-trmBg)}.expressive-code .frame.is-terminal .header{display:flex;align-items:center;justify-content:center;padding-block:var(--ec-uiPadBlk);padding-block-end:calc(var(--ec-uiPadBlk) + var(--ec-brdWd));position:relative;font-weight:500;letter-spacing:0.025ch;color:var(--ec-frm-trmTtbFg);background:var(--ec-frm-trmTtbBg);border:var(--ec-brdWd) solid var(--ec-brdCol);border-bottom:none}.expressive-code .frame.is-terminal .header::before{content:&apos;&apos;;position:absolute;pointer-events:none;left:var(--ec-uiPadInl);width:2.1rem;height:0.56rem;line-height:0;background-color:var(--ec-frm-trmTtbDotsFg);opacity:var(--ec-frm-trmTtbDotsOpa);-webkit-mask-image:var(--ec-frm-trmIcon);-webkit-mask-repeat:no-repeat;mask-image:var(--ec-frm-trmIcon);mask-repeat:no-repeat}.expressive-code .frame.is-terminal .header::after{content:&apos;&apos;;position:absolute;pointer-events:none;inset:0;border-bottom:var(--ec-brdWd) solid var(--ec-frm-trmTtbBrdBtmCol)}.expressive-code .frame pre{background:var(--code-background)}.expressive-code .copy{display:flex;gap:0.25rem;flex-direction:row;position:absolute;inset-block-start:calc(var(--ec-brdWd) + var(--button-spacing));inset-inline-end:calc(var(--ec-brdWd) + var(--ec-uiPadInl) / 2)}@media (scripting: none){.expressive-code .copy{display:none}}.expressive-code .copy{direction:ltr;unicode-bidi:isolate}.expressive-code .copy button{position:relative;align-self:flex-end;margin:0;padding:0;border:none;border-radius:0.2rem;z-index:1;cursor:pointer;transition-property:opacity, background, border-color;transition-duration:0.2s;transition-timing-function:cubic-bezier(0.25, 0.46, 0.45, 0.94);width:2.5rem;height:2.5rem;background:var(--code-background);opacity:0.75}.expressive-code .copy button div{position:absolute;inset:0;border-radius:inherit;background:var(--ec-frm-inlBtnBg);opacity:var(--ec-frm-inlBtnBgIdleOpa);transition-property:inherit;transition-duration:inherit;transition-timing-function:inherit}.expressive-code .copy button::before{content:&apos;&apos;;position:absolute;pointer-events:none;inset:0;border-radius:inherit;border:var(--ec-brdWd) solid var(--ec-frm-inlBtnBrd);opacity:var(--ec-frm-inlBtnBrdOpa)}.expressive-code .copy button::after{content:&apos;&apos;;position:absolute;pointer-events:none;inset:0;background-color:var(--ec-frm-inlBtnFg);-webkit-mask-image:var(--ec-frm-copyIcon);-webkit-mask-repeat:no-repeat;mask-image:var(--ec-frm-copyIcon);mask-repeat:no-repeat;margin:0.475rem;line-height:0}.expressive-code .copy button:hover,.expressive-code .copy button:focus:focus-visible{opacity:1}.expressive-code .copy button:hover div,.expressive-code .copy button:focus:focus-visible div{opacity:var(--ec-frm-inlBtnBgHoverOrFocusOpa)}.expressive-code .copy button:active{opacity:1}.expressive-code .copy button:active div{opacity:var(--ec-frm-inlBtnBgActOpa)}.expressive-code .copy .feedback{--tooltip-arrow-size:0.35rem;--tooltip-bg:var(--ec-frm-tooltipSuccessBg);color:var(--ec-frm-tooltipSuccessFg);pointer-events:none;user-select:none;-webkit-user-select:none;position:relative;align-self:center;background-color:var(--tooltip-bg);z-index:99;padding:0.125rem 0.75rem;border-radius:0.2rem;margin-inline-end:var(--tooltip-arrow-size);opacity:0;transition-property:opacity, transform;transition-duration:0.2s;transition-timing-function:ease-in-out;transform:translate3d(0, 0.25rem, 0)}.expressive-code .copy .feedback::after{content:&apos;&apos;;position:absolute;pointer-events:none;top:calc(50% - var(--tooltip-arrow-size));inset-inline-end:calc(-2 * (var(--tooltip-arrow-size) - 0.5px));border:var(--tooltip-arrow-size) solid transparent;border-inline-start-color:var(--tooltip-bg)}.expressive-code .copy .feedback.show{opacity:1;transform:translate3d(0, 0, 0)}@media (hover: hover){.expressive-code{}.expressive-code .copy button{opacity:0;width:2rem;height:2rem}.expressive-code .frame:hover .copy button:not(:hover),.expressive-code .frame:focus-within :focus-visible ~ .copy button:not(:hover),.expressive-code .frame .copy .feedback.show ~ button:not(:hover){opacity:0.75}}.expressive-code :nth-child(1 of .ec-line) .code{padding-inline-end:calc(2rem + var(--ec-codePadInl))}:root{--ec-brdRad:0.75rem;--ec-brdWd:1.5px;--ec-brdCol:var(--code-line);--ec-codeFontFml:var(--font-code);--ec-codeFontSize:0.875rem;--ec-codeFontWg:400;--ec-codeLineHt:1.75;--ec-codePadBlk:1rem;--ec-codePadInl:1.125rem;--ec-codeBg:var(--code-bg);--ec-codeFg:#e6edf3;--ec-codeSelBg:#264f78;--ec-gtrFg:#6e7681;--ec-gtrBrdCol:#6e768133;--ec-gtrBrdWd:1.5px;--ec-gtrHlFg:#e6edf3;--ec-uiFontFml:var(--font-mono);--ec-uiFontSize:0.75rem;--ec-uiFontWg:400;--ec-uiLineHt:1.65;--ec-uiPadBlk:0.25rem;--ec-uiPadInl:1rem;--ec-uiSelBg:#6e768166;--ec-uiSelFg:#e6edf3;--ec-focusBrd:#1f6feb;--ec-sbThumbCol:#8b949e33;--ec-sbThumbHoverCol:#8b949e3d;--ec-tm-lineMarkerAccentMarg:0rem;--ec-tm-lineMarkerAccentWd:0.15rem;--ec-tm-lineMarkerLabelPadInl:0.2rem;--ec-tm-lineMarkerLabelCol:white;--ec-tm-lineDiffIndMargLeft:0.3rem;--ec-tm-inlMarkerBrdWd:1.5px;--ec-tm-inlMarkerBrdRad:0.2rem;--ec-tm-inlMarkerPad:0.15rem;--ec-tm-insDiffIndContent:&apos;+&apos;;--ec-tm-delDiffIndContent:&apos;-&apos;;--ec-tm-markBg:#264a8980;--ec-tm-markBrdCol:#5570b3d0;--ec-tm-insBg:#26561c80;--ec-tm-insBrdCol:#4e7e41d0;--ec-tm-insDiffIndCol:#7eb070d0;--ec-tm-delBg:#81322b80;--ec-tm-delBrdCol:#ae594fd0;--ec-tm-delDiffIndCol:#e68a7ed0;--ec-frm-shdCol:#0000005b;--ec-frm-frameBoxShdCssVal:none;--ec-frm-edActTabBg:var(--code-bg);--ec-frm-edActTabFg:var(--code-muted);--ec-frm-edActTabBrdCol:transparent;--ec-frm-edActTabIndHt:1.5px;--ec-frm-edActTabIndTopCol:transparent;--ec-frm-edActTabIndBtmCol:#0d1117;--ec-frm-edTabsMargInlStart:0;--ec-frm-edTabsMargBlkStart:0;--ec-frm-edTabBrdRad:0.75rem;--ec-frm-edTabBarBg:var(--code-bg);--ec-frm-edTabBarBrdCol:var(--code-line);--ec-frm-edTabBarBrdBtmCol:var(--code-line);--ec-frm-edBg:var(--code-bg);--ec-frm-trmTtbFg:var(--code-muted);--ec-frm-trmTtbDotsFg:var(--code-muted);--ec-frm-trmTtbDotsOpa:0.15;--ec-frm-trmTtbBg:var(--code-bg);--ec-frm-trmTtbBrdBtmCol:var(--code-line);--ec-frm-trmBg:var(--code-bg);--ec-frm-inlBtnBg:var(--code-ink);--ec-frm-inlBtnBgIdleOpa:0;--ec-frm-inlBtnBgHoverOrFocusOpa:0.2;--ec-frm-inlBtnBgActOpa:0.3;--ec-frm-inlBtnFg:var(--code-ink);--ec-frm-inlBtnBrd:var(--code-line);--ec-frm-inlBtnBrdOpa:0.4;--ec-frm-tooltipSuccessBg:var(--color-emerald);--ec-frm-tooltipSuccessFg:var(--color-bg);--ec-frm-copyIcon:url(&quot;data:image/svg+xml,%3Csvg%20xmlns%3D&apos;http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg&apos;%20viewBox%3D&apos;0%200%2024%2024&apos;%20fill%3D&apos;none&apos;%20stroke%3D&apos;black&apos;%20stroke-width%3D&apos;1.75&apos;%3E%3Cpath%20d%3D&apos;M3%2019a2%202%200%200%201-1-2V2a2%202%200%200%201%201-1h13a2%202%200%200%201%202%201&apos;%2F%3E%3Crect%20x%3D&apos;6&apos;%20y%3D&apos;5&apos;%20width%3D&apos;16&apos;%20height%3D&apos;18&apos;%20rx%3D&apos;1.5&apos;%20ry%3D&apos;1.5&apos;%2F%3E%3C%2Fsvg%3E&quot;);--ec-frm-trmIcon:url(&quot;data:image/svg+xml,%3Csvg%20xmlns%3D&apos;http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg&apos;%20viewBox%3D&apos;0%200%2060%2016&apos;%20preserveAspectRatio%3D&apos;xMidYMid%20meet&apos;%3E%3Ccircle%20cx%3D&apos;8&apos;%20cy%3D&apos;8&apos;%20r%3D&apos;8&apos;%2F%3E%3Ccircle%20cx%3D&apos;30&apos;%20cy%3D&apos;8&apos;%20r%3D&apos;8&apos;%2F%3E%3Ccircle%20cx%3D&apos;52&apos;%20cy%3D&apos;8&apos;%20r%3D&apos;8&apos;%2F%3E%3C%2Fsvg%3E&quot;)}.expressive-code .ec-line :where(span[style^=&apos;--&apos;]:not([class])){color:var(--0, inherit);background-color:var(--0bg, transparent);font-style:var(--0fs, inherit);font-weight:var(--0fw, inherit);text-decoration:var(--0td, inherit)}&lt;/style&gt;&lt;script type=&quot;module&quot; src=&quot;/_astro/ec.0vx5m.js&quot;&gt;&lt;/script&gt;&lt;figure class=&quot;frame has-title&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;TypeScript&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;typescript&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#8B949E&quot;&gt;// একটি সিম্পল Hash Function-এর উদাহরণ যা String Key-কে Array Index-এ রূপান্তর করে&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;function&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D2A8FF&quot;&gt;simpleHash&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#FFA657&quot;&gt;key&lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;string&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#FFA657&quot;&gt;arraySize&lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;number&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;number&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;let&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; hash &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;for&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;let&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; i &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;; i &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; key.&lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;length&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;; i&lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;++&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;) {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#8B949E&quot;&gt;// প্রতিটি অক্ষরের ASCII কোডের সাথে গাণিতিক হিসাব করা হচ্ছে&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;hash &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; (hash &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;+&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; key.&lt;/span&gt;&lt;span style=&quot;--0:#D2A8FF&quot;&gt;charCodeAt&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;(i) &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;*&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;31&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;%&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; arraySize;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; hash;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;tableSize&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;100&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;index&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D2A8FF&quot;&gt;simpleHash&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;&quot;user_profile_dhaka&quot;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;, tableSize);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;console.&lt;/span&gt;&lt;span style=&quot;--0:#D2A8FF&quot;&gt;log&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;`Data will be stored at index: ${&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;index&lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;}`&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;// একটি সিম্পল Hash Function-এর উদাহরণ যা String Key-কে Array Index-এ রূপান্তর করেfunction simpleHash(key: string, arraySize: number): number {    let hash = 0;    for (let i = 0; i &lt; key.length; i++) {        // প্রতিটি অক্ষরের ASCII কোডের সাথে গাণিতিক হিসাব করা হচ্ছে        hash = (hash + key.charCodeAt(i) * 31) % arraySize;    }    return hash;}const tableSize = 100;const index = simpleHash(&amp;#x22;user_profile_dhaka&amp;#x22;, tableSize);console.log(&amp;#x60;Data will be stored at index: ${index}&amp;#x60;);&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;তবে Hash Table-এর এই অপূর্ব সিস্টেমে একটি বড় ইঞ্জিনিয়ারিং চ্যালেঞ্জ রয়েছে, যাকে বলা হয় Hash Collision। যেহেতু আমাদের মেমোরি বা Array স্লটের সংখ্যা সীমাবদ্ধ, কিন্তু ইনপুট হিসেবে আসা Key-এর সংখ্যা অসীম হতে পারে, তাই মাঝেমধ্যেই এমন ঘটনা ঘটে যখন দুটি সম্পূর্ণ আলাদা Key-কে Hash Function একই মেমোরি স্লট বা ইনডেক্স বরাদ্দ করে দেয়। উদাহরণস্বরূপ, &quot;dhaka&quot; এবং &quot;sylhet&quot; এই দুটি আলাদা শব্দের হ্যাশ ক্যালকুলেশন করে যদি উভয়ের রেজাল্টই ১৫ নম্বর স্লট আসে, তখন তাকে Hash Collision বলা হয়। এই পরিস্থিতি সঠিক লজিক দিয়ে হ্যান্ডেল না করলে সিস্টেম ক্র্যাশ করতে পারে বা ডেটা হারিয়ে যেতে পারে।&lt;/p&gt;
&lt;p&gt;সফটওয়্যার আর্কিটেকচারে Hash Collision সমাধানের জন্য মূলত দুটি অত্যন্ত জনপ্রিয় এবং কার্যকরী পদ্ধতি ব্যবহার করা হয়:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Chaining (চেইনিং):&lt;/strong&gt; এই পদ্ধতিতে Hash Table-এর প্রতিটি মেমোরি স্লটে সরাসরি একটি ডেটা না রেখে, সেখানে একটি Linked List-এর Head বা শুরু ঝুলিয়ে দেওয়া হয়। যখনই কোনো মেমোরি স্লটে Collision ঘটে এবং একাধিক ডেটা একই ইনডেক্সে এসে পড়ে, তখন নতুন ডেটাটিকে সেই স্লটের Linked List-এর সাথে একটি নতুন Node হিসেবে চেইন করে যুক্ত করে দেওয়া হয়। ডেটা খোঁজার সময় প্রথমে Hash Function দিয়ে ইনডেক্স বের করা হয়, তারপর সেই স্লটের ছোট Linked List-টিতে কয়েকটি ধাপ লুপ চালিয়ে সঠিক ডেটাটি খুঁজে নেওয়া হয়।&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Open Addressing (ওপেন অ্যাড্রেসিং):&lt;/strong&gt; এই পদ্ধতিতে মেমোরি স্লটে কোনো Linked List ব্যবহার করা হয় না। যখন কোনো একটি স্লটে নতুন ডেটা রাখার সময় দেখা যায় স্লটটি আগে থেকেই অন্য কোনো ডেটা দ্বারা দখল হয়ে আছে, তখন সিস্টেম স্বয়ংক্রিয়ভাবে পরবর্তী ফাঁকা স্লটটির খোঁজ করতে শুরু করে। এটি করার জন্য Linear Probing (পরপর এক ঘর করে এগিয়ে ফাঁকা স্লট খোঁজা) বা Quadratic Probing (গাণিতিক লাফ দিয়ে ফাঁকা স্লট খোঁজা) ব্যবহার করা হয়। যে স্লটটি প্রথমে ফাঁকা পাওয়া যায়, সেখানেই নতুন ডেটাটিকে বসিয়ে দেওয়া হয়।&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&quot;non-linear-structures-স্কেল-করার-আসল-শক্তি&quot;&gt;Non-Linear Structures (স্কেল করার আসল শক্তি)&lt;/h2&gt;
&lt;p&gt;আমরা এতক্ষণ যে Data Structure-গুলো নিয়ে আলোচনা করেছি, যেমন Array, Linked List, Stack, বা Queue, সেগুলো সবই ছিল Linear Data Structure। অর্থাৎ এখানে ডেটাগুলো একটি সরলরেখা বা সোজা লাইনে পরপর সাজানো থাকে। কিন্তু বাস্তব পৃথিবীর অনেক জটিল সমস্যা এবং বিশাল ডেটাসেটকে একটি সোজা লাইনে সমাধান করা সম্ভব নয়। যখন আমাদের সিস্টেমে ডেটার মধ্যে হায়েরার্কি বা একটির অধীনে আরেকটি ডেটার সম্পর্ক তৈরি করার প্রয়োজন হয়, তখন আমাদের Non-Linear Data Structure-এর জগতে প্রবেশ করতে হয়। এই জগতের সবচেয়ে গুরুত্বপূর্ণ এবং শক্তিশালী দুটি স্তম্ভ হলো Tree এবং Graph।&lt;/p&gt;
&lt;p&gt;Tree এবং বিশেষ করে Binary Search Tree (BST) হলো এমন একটি আর্কিটেকচার যা ডেটাকে হায়েরার্কি অনুযায়ী সাজিয়ে রাখে। এর একটি চমৎকার Analogy হলো কোনো একটি বড় কর্পোরেট কোম্পানির অর্গানোগ্রাম বা আমাদের পরিবারের ফ্যামিলি ট্রি। কোম্পানির অর্গানোগ্রামে সবার ওপরে থাকেন একজন CEO, তার অধীনে থাকেন কয়েকজন ডিরেক্টর, তাদের অধীনে ম্যানেজার এবং তাদের অধীনে সাধারণ ইঞ্জিনিয়ারগণ। Tree Data Structure ঠিক এভাবেই কাজ করে, যেখানে সবার উপরের ডেটাটিকে বলা হয় Root Node, এবং তার নিচের শাখা-প্রশাখাগুলোকে বলা হয় Child Node।&lt;/p&gt;
&lt;p&gt;কেন আধুনিক Relational Database এবং অপারেটিং সিস্টেমের File System সাধারণ Array ব্যবহার না করে Tree ব্যবহার করে? এর প্রধান কারণ হলো খোঁজার বা Search করার অসম্ভব দ্রুত গতি। একটি Binary Search Tree (BST)-তে একটি বিশেষ নিয়ম মানা হয়: যেকোনো Node-এর বাম দিকের শাখায় সবসময় ছোট ডেটা থাকবে, এবং ডান দিকের শাখায় সবসময় বড় ডেটা থাকবে। এর ফলে আপনি যখন কোনো ডেটা খুঁজবেন, তখন প্রতি ধাপে আপনি নিশ্চিতভাবে বলতে পারবেন ডেটাটি বামে আছে নাকি ডানে। এই লজিকের কারণে প্রতি ধাপে খোঁজার ডেটাসেট ঠিক অর্ধেক হয়ে যায়, যা আমাদের O(log n) Time Complexity প্রদান করে।&lt;/p&gt;
&lt;figure&gt;&lt;img src=&quot;https://raw.githubusercontent.com/rafeuddaraj/rafes-blog-assets/refs/heads/the-complete-engineering-handbook-data-structures-and-algorithms-for-production-scalability/assets/bst-vs-linear-search.svg&quot; alt=&quot;Binary Search Tree O(log n) বনাম Linear Search O(n) - সার্চ পারফরম্যান্স পার্থক্য&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;800&quot; height=&quot;450&quot;&gt;&lt;figcaption&gt;Binary Search Tree O(log n) বনাম Linear Search O(n) - সার্চ পারফরম্যান্স পার্থক্য&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;উপরের ডায়াগ্রামটি থেকে আপনি বুঝতে পারবেন, এক কোটি ডেটার একটি সাধারণ Array-তে Linear Search চালিয়ে শেষ ডেটাটি খুঁজে পেতে এক কোটি বার লুপ ঘুরাতে হতো। অথচ একটি ব্যালেন্সড Binary Search Tree বা BST ব্যবহার করে একই এক কোটি ডেটার ভেতর থেকে যেকোনো ডেটা খুঁজে বের করতে সর্বোচ্চ মাত্র ২৪ থেকে ৩০টি ধাপের প্রয়োজন হয়। প্রোডাকশন সিস্টেমে এই পারফরম্যান্স পার্থক্যটিই নির্ধারণ করে আপনার API কি মিলি-সেকেন্ডে উত্তর দেবে নাকি টাইমআউট হয়ে ক্র্যাশ করবে।&lt;/p&gt;
&lt;p&gt;Tree-এর গণ্ডি পেরিয়ে আমরা যখন আরও জটিল ও বাস্তবমুখী নেটওয়ার্ক লজিক নিয়ে কাজ করি, তখন আমাদের প্রয়োজন হয় Graph Data Structure। Tree হলো Graph-এরই একটি বিশেষ রূপ, যেখানে কোনো সাইকেল বা লুপ থাকতে পারে না এবং সবার একটি নির্দিষ্ট Root থাকে। কিন্তু Graph-এ এমন কোনো সীমাবদ্ধতা নেই। Graph মূলত দুটি জিনিস নিয়ে গঠিত: Node (বা Vertex), যা কোনো একটি বস্তু বা স্থানকে নির্দেশ করে, এবং Edge, যা দুটি Node-এর মধ্যকার সম্পর্ক বা সংযোগের পথ নির্দেশ করে।&lt;/p&gt;
&lt;p&gt;বাস্তব সফটওয়্যার ইঞ্জিনিয়ারিংয়ে Graph-এর ব্যবহার সর্বত্র বিদ্যমান। উদাহরণস্বরূপ, Facebook বা LinkedIn-এর সোশ্যাল মিডিয়া ফ্রেন্ড লিস্ট একটি বিশাল Graph। এখানে প্রতিটি ইউজার হলো একটি করে Node, এবং দুজনের মধ্যকার বন্ধুত্ব হলো একটি Edge। যখন আপনি &quot;Friends of Friends&quot; বা মিউচুয়াল ফ্রেন্ড বের করতে চান, তখন ব্যাকএন্ডে Graph Traversal অ্যালগরিদম কাজ করে। একইভাবে, Google Maps বা Uber-এর মতো রাইড-শেয়ারিং অ্যাপ্লিকেশনে পুরো শহরের রাস্তাঘাটকে একটি Graph হিসেবে মেমোরিতে রাখা হয়, যেখানে মোড়গুলো হলো Node এবং রাস্তাগুলো হলো Edge। এক স্থান থেকে অন্য স্থানে যাওয়ার সবচেয়ে ছোট এবং দ্রুততম রাস্তাটি (Shortest Path Calculation) বের করার জন্য Dijkstra বা A* এর মতো Graph অ্যালগরিদম ব্যবহার করা হয়। এছাড়া ইন্টারনেট এবং নেটওয়ার্ক রাউটিং প্রোটোকলগুলো সম্পূর্ণভাবে Graph আর্কিটেকচারের ওপর ভিত্তি করে ডেটা প্যাকেট আদান-প্রদান করে।&lt;/p&gt;
&lt;h2 id=&quot;কোর-অ্যালগরিদমিক-টেকনিক-এবং-প্যারাডাইম&quot;&gt;কোর অ্যালগরিদমিক টেকনিক এবং প্যারাডাইম&lt;/h2&gt;
&lt;p&gt;ডেটাকে সঠিকভাবে মেমোরিতে সাজানোর পর আমাদের পরবর্তী কাজ হলো সেই ডেটার ওপর বিভিন্ন লজিক বা অপারেশন চালানো। এই কাজের জন্য আমাদের কিছু কোর অ্যালগরিদমিক টেকনিক এবং সমস্যা সমাধানের প্যারাডাইম বা চিন্তাধারা আয়ত্ত করতে হয়। সফটওয়্যার ইঞ্জিনিয়ারিংয়ে আমরা সবচেয়ে বেশি যে দুটি কাজের মুখোমুখি হই, তা হলো Searching (ডেটা খোঁজা) এবং Sorting (ডেটা সাজানো)।&lt;/p&gt;
&lt;p&gt;Searching-এর ক্ষেত্রে আমরা ইতোমধ্যে দেখেছি যে Linear Search হলো সবচেয়ে ধীরগতির পদ্ধতি, যেখানে লুপ চালিয়ে এক এক করে ডেটা মেলাতে হয়, যার Complexity O(n)। কিন্তু আপনার ডেটাসেট যদি আগে থেকেই ছোট থেকে বড় ক্রমানুসারে সাজানো বা Sorted থাকে, তবে আপনি ব্যবহার করতে পারেন Binary Search। এটি একটি অত্যন্ত শক্তিশালী অ্যালগরিদম, যা প্রতি ধাপে মাঝখানের ডেটার সাথে টার্গেট ডেটা মেলায় এবং এক লাফে ডেটাসেটের অর্ধেক অংশ বাদ দিয়ে দেয়। இதன் ফলে O(log n) সময়েই যেকোনো ডেটা খুঁজে পাওয়া সম্ভব হয়।&lt;/p&gt;
&lt;p&gt;এবার আসুন Sorting বা ডেটা সাজানোর বিষয়ে কথা বলি। প্রোডাকশন সিস্টেমে ডেটা সাজিয়ে রাখা অত্যন্ত জরুরি, কারণ সর্টেড ডেটা ছাড়া Binary Search বা দ্রুতগতির কুয়েরি চালানো অসম্ভব। ছোটখাটো ডেটার জন্য সাধারণ সর্টিং অ্যালগরিদম কাজ করলেও, লাখ লাখ বা কোটি কোটি ডেটাবেস রেকর্ড সর্ট করার জন্য আমাদের উন্নত অ্যালগরিদম প্রয়োজন, যার মধ্যে সবচেয়ে জনপ্রিয় হলো QuickSort এবং MergeSort।&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;QuickSort:&lt;/strong&gt; এটি একটি Divide and Conquer অ্যালগরিদম। এটি ডেটাসেট থেকে যেকোনো একটি ডেটাকে Pivot হিসেবে বেছে নেয় এবং সেই Pivot-এর চেয়ে ছোট সব ডেটাকে বামে আর বড় সব ডেটাকে ডানে পাঠিয়ে দেয়। এরপর বাম ও ডান অংশকে আলাদাভাবে একই পদ্ধতিতে সর্ট করে। এর গড় Time Complexity হলো O(n log n) এবং এটি মেমোরিতে অতিরিক্ত জায়গা বা Space খুব কম ব্যবহার করে। তবে ডেটা যদি আগে থেকেই উল্টোভাবে সাজানো থাকে এবং সঠিক Pivot নির্বাচন করা না হয়, তবে এর Worst Case পারফরম্যান্স O(n^2) হয়ে যেতে পারে।&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;MergeSort:&lt;/strong&gt; এটিও Divide and Conquer নীতির ওপর কাজ করে। এটি পুরো ডেটাসেটকে মাঝখান থেকে কেটে ছোট ছোট ভাগে ভাগ করতে থাকে যতক্ষণ না প্রতিটি ভাগে মাত্র একটি করে ডেটা অবশিষ্ট থাকে। এরপর সেই ছোট ভাগগুলোকে ক্রমানুসারে জোড়া লাগিয়ে বা Merge করে একটি সম্পূর্ণ সর্টেড লিস্ট তৈরি করে। এর সবচেয়ে বড় সুবিধা হলো, ডেটা যেমনই থাকুক না কেন, এটি সবসময় নিশ্চিতভাবে O(n log n) সময়েই কাজ শেষ করবে। তবে এর Trade-off হলো, ডেটাগুলোকে জোড়া লাগানোর সময় এর অতিরিক্ত মেমোরি বা O(n) Space Complexity প্রয়োজন হয়।&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;কোনো একটি নতুন বা জটিল ইঞ্জিনিয়ারিং সমস্যার মুখোমুখি হলে আমরা কীভাবে চিন্তা করব? সফটওয়্যার ইঞ্জিনিয়ারিংয়ে সমস্যা সমাধানের জন্য মূলত ৩টি বড় চিন্তাধারা বা Algorithmic Paradigms রয়েছে:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Brute Force (ব্রুট ফোর্স):&lt;/strong&gt; এটি হলো কোনো স্মার্টনেস বা অপটিমাইজেশন ছাড়া সমস্যার সমাধান করার সবচেয়ে সাধারণ পদ্ধতি। এই পদ্ধতিতে একটি সমস্যার যতগুলো সম্ভাব্য সমাধান বা রাস্তা থাকতে পারে, তার সবগুলো একে একে চেষ্টা করে দেখা হয়। এটি কোড করা সহজ এবং এটি সবসময় সঠিক উত্তর দেয়, কিন্তু প্রোডাকশন সিস্টেমে এটি অত্যন্ত ধীরগতির এবং এর Time Complexity প্রায়ই O(n^2) বা O(2^n) হয়ে যায়।&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Greedy Algorithm (গ্রিডি অ্যালগরিদম):&lt;/strong&gt; এই চিন্তাধারায় ভবিষ্যতের কথা বা সামগ্রিক ফলের কথা চিন্তা না করে, বর্তমান মুহূর্তে দাঁড়িয়ে যে সিদ্ধান্তটিকে সবচেয়ে সেরা বা লাভজনক মনে হয়, সেটিই গ্রহণ করা হয়। প্রতি ধাপে Locally Optimal সিদ্ধান্ত নিয়ে একটি Globally Optimal সমাধানে পৌঁছানোর চেষ্টা করা হয়। যেমন, কোনো নেটওয়ার্কে সবচেয়ে কম খরচে ডেটা পাঠানোর পথ খোঁজার সময় প্রতি মোড়ে দাঁড়িয়ে সবচেয়ে ছোট রাস্তাটি বেছে নেওয়াই হলো Greedy লজিক। এটি অত্যন্ত দ্রুত কাজ করে, তবে সব ধরনের সমস্যায় এটি ১০০% সঠিক উত্তর নাও দিতে পারে।&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Dynamic Programming বা DP (ডাইনামিক প্রোগ্রামিং):&lt;/strong&gt; এটি হলো একটি অত্যন্ত শক্তিশালী ও স্মার্ট ইঞ্জিনিয়ারিং প্যারাডাইম। যখন কোনো একটি বড় ও জটিল সমস্যাকে অনেকগুলো ছোট ছোট একই ধরনের সমস্যায় (Overlapping Subproblems) ভেঙে সমাধান করা যায়, তখন DP ব্যবহার করা হয়। এর মূল মন্ত্র হলো: &quot;যে ক্যালকুলেশন আপনি একবার করেছেন, তা পুনরায় করবেন না।&quot; ছোট সমস্যাগুলোর সমাধান মেমোরিতে একটি Array বা Map-এর ভেতর ধরে রাখা বা Caching (Memoization) করা হয়। পরবর্তীতে একই ক্যালকুলেশনের প্রয়োজন হলে প্রসেসরকে আবার হিসাব করতে না দিয়ে সরাসরি মেমোরি থেকে আগের রেজাল্টটি নিয়ে নেওয়া হয়। এর ফলে যে সমস্যার সমাধান করতে Brute Force-এ কয়েক হাজার বছর লেগে যেতে পারে, Dynamic Programming ব্যবহার করে তা মাত্র কয়েক সেকেন্ডে সমাধান করা সম্ভব হয়।&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&quot;প্রোডাকশন-ইঞ্জিনিয়ারিং-এবং-রিয়েল-ওয়ার্ল্ড-ইউজ-কেস&quot;&gt;প্রোডাকশন ইঞ্জিনিয়ারিং এবং রিয়েল-ওয়ার্ল্ড ইউজ কেস&lt;/h2&gt;
&lt;p&gt;তাত্ত্বিক আলোচনার পর এবার আমরা দেখব কীভাবে এই Data Structure এবং Algorithm-এর জ্ঞান আমাদের প্রতিদিনের প্রোডাকশন ইঞ্জিনিয়ারিং এবং রিয়েল-ওয়ার্ল্ড সিস্টেমে সরাসরি প্রয়োগ করা হয়। আমরা দুটি অত্যন্ত গুরুত্বপূর্ণ প্রোডাকশন ইউজ কেস নিয়ে বিস্তারিত আলোচনা করব: Database Indexing এবং Caching Architecture।&lt;/p&gt;
&lt;p&gt;প্রথমেই কথা বলা যাক ডেটাবেস ইনডেক্সিং বা Database Indexing নিয়ে। আপনি যখন একটি Relational Database যেমন MySQL বা PostgreSQL ব্যবহার করেন এবং সেখানে কোটি কোটি ইউজারের রেকর্ড থাকে, তখন &lt;code&gt;SELECT * FROM users WHERE email = &apos;example@test.com&apos;&lt;/code&gt; কুয়েরিটি কীভাবে মাত্র কয়েক মিলি-সেকেন্ডে উত্তর দেয়? আপনি যদি ইমেইল কলামের ওপর Index তৈরি না করে রাখেন, তবে ডেটাবেস ইঞ্জিনকে Hard Disk বা SSD থেকে প্রতিটি রো বা রেকর্ড একে একে মেমোরিতে এনে পরীক্ষা করতে হবে। একে বলা হয় Full Table Scan। ট্রাফিক বেশি থাকা অবস্থায় এক কোটি রেকর্ডের ওপর Full Table Scan চললে সার্ভারের প্রসেসর এবং মেমোরি মুহূর্তেই ওভারলোড হয়ে পুরো ডেটাবেস ক্র্যাশ করবে।&lt;/p&gt;
&lt;p&gt;এই সমস্যা সমাধানের জন্য ডেটাবেস ইঞ্জিনগুলো B-Tree এবং B+ Tree নামক বিশেষ Balanced Tree Data Structure ব্যবহার করে। যখন আপনি কোনো কলামের ওপর Index তৈরি করেন, তখন ডেটাবেস সেই কলামের ডেটাগুলোকে একটি B+ Tree আকারে সাজিয়ে মেমোরি বা ডিস্কের একটি আলাদা স্থানে সংরক্ষণ করে। B+ Tree-এর বৈশিষ্ট্য হলো এর প্রতিটি Node-এ অনেকগুলো করে ডেটা এবং Child Pointer থাকতে পারে, যা Tree-এর উচ্চতাকে অত্যন্ত কম রাখে। ফলে কোটি কোটি রেকর্ডের ভেতর থেকেও যেকোনো ডেটা খুঁজে বের করতে ডেটাবেসকে মাত্র ৩ থেকে ৪টি ডিস্ক রিড (Disk Read) অপারেশন করতে হয়, যা লজিক্যালি O(log n) পারফরম্যান্স নিশ্চিত করে।&lt;/p&gt;
&lt;p&gt;আমাদের দ্বিতীয় প্রোডাকশন ইউজ কেসটি হলো Caching Architecture। যেকোনো হাই-ট্রাফিক স্কেলেবল সিস্টেমে ডেটাবেসের ওপর লোড কমানোর জন্য এবং ইউজারকে অতি দ্রুত রেসপন্স দেওয়ার জন্য আমরা Cache Memory (যেমন Redis বা Memcached) ব্যবহার করি। কিন্তু মেমোরি বা RAM-এর জায়গা অত্যন্ত সীমিত ও ব্যয়বহুল। তাই আমাদের এমন একটি স্মার্ট Cache সিস্টেম তৈরি করতে হয়, যা সবচেয়ে প্রয়োজনীয় ডেটাগুলো মেমোরিতে রাখবে এবং মেমোরি ভরে গেলে অপ্রয়োজনীয় বা পুরোনো ডেটাগুলো স্বয়ংক্রিয়ভাবে মুছে ফেলবে। এই কাজের জন্য ইন্ডাস্ট্রির সবচেয়ে জনপ্রিয় অ্যালগরিদম হলো LRU Cache (Least Recently Used)।&lt;/p&gt;
&lt;p&gt;একটি প্রোডাকশন-গ্রেড LRU Cache তৈরি করতে হলে আমাদের এমন একটি আর্কিটেকচার প্রয়োজন যেখানে দুটি কাজই O(1) বা Constant Time-এ হতে হবে:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;যেকোনো Key দিয়ে ডেটা খুঁজে বের করা (Lookup)।&lt;/li&gt;
&lt;li&gt;কোনো নতুন ডেটা আসলে বা পুরোনো ডেটা মুছে ফেলার সময় মেমোরি আপডেট করা (Eviction &amp;#x26; Insertion)।&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;শুধুমাত্র Array বা Linked List দিয়ে এটি করা সম্ভব নয়। তাই ইঞ্জিনিয়াররা এখানে একটি অসাধারণ কম্বিনেশন ব্যবহার করেন: Hash Map এবং Doubly Linked List। Hash Map আমাদের O(1) সময়ে ডেটা খুঁজে বের করার নিশ্চয়তা দেয়, আর Doubly Linked List আমাদের O(1) সময়ে যেকোনো অবস্থান থেকে Node মুছে ফেলার এবং নতুন Node যুক্ত করার সুবিধা দেয়।&lt;/p&gt;
&lt;figure&gt;&lt;img src=&quot;https://raw.githubusercontent.com/rafeuddaraj/rafes-blog-assets/refs/heads/the-complete-engineering-handbook-data-structures-and-algorithms-for-production-scalability/assets/lru-cache-architecture.svg&quot; alt=&quot;LRU Cache আর্কিটেকচার - Hash Map এবং Doubly Linked List কম্বিনেশন O(1) Eviction&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;800&quot; height=&quot;450&quot;&gt;&lt;figcaption&gt;LRU Cache আর্কিটেকচার - Hash Map এবং Doubly Linked List কম্বিনেশন O(1) Eviction&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;উপরের ডায়াগ্রামটি লক্ষ্য করুন। এখানে Hash Map-এর প্রতিটি Key সরাসরি Doubly Linked List-এর একটি নির্দিষ্ট Node-এর মেমোরি অ্যাড্রেস বা Pointer ধারণ করে আছে। যখনই কোনো ডেটা Read বা Write করা হয়, তখন সেই Node-টিকে Doubly Linked List-এর একদম শুরুতে বা Head-এ নিয়ে আসা হয় (Most Recently Used)। আর যখন মেমোরি পূর্ণ হয়ে যায়, তখন একদম শেষে বা Tail-এ থাকা Node-টিকে (Least Recently Used) মাত্র O(1) সময়ে কেটে বাদ দিয়ে দেওয়া হয়।&lt;/p&gt;
&lt;p&gt;নিচে একটি প্রোডাকশন-রেডি, সম্পূর্ণ টাইপ-সেফ TypeScript কোড ব্লক দেওয়া হলো, যেখানে Hash Map এবং Doubly Linked List ব্যবহার করে একটি কার্যকরী LRU Cache ইমপ্লিমেন্ট করে দেখানো হয়েছে:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame has-title&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;TypeScript&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;typescript&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#8B949E&quot;&gt;// Doubly Linked List-এর প্রতিটি Node-এর আর্কিটেকচার&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FFA657&quot;&gt;CacheNode&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;--0:#FFA657&quot;&gt;K&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#FFA657&quot;&gt;V&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FFA657&quot;&gt;key&lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FFA657&quot;&gt;K&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FFA657&quot;&gt;value&lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FFA657&quot;&gt;V&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FFA657&quot;&gt;prev&lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FFA657&quot;&gt;CacheNode&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;--0:#FFA657&quot;&gt;K&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#FFA657&quot;&gt;V&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;|&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;null&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;null&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FFA657&quot;&gt;next&lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FFA657&quot;&gt;CacheNode&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;--0:#FFA657&quot;&gt;K&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#FFA657&quot;&gt;V&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;|&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;null&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;null&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;constructor&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#FFA657&quot;&gt;key&lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FFA657&quot;&gt;K&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#FFA657&quot;&gt;value&lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FFA657&quot;&gt;V&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;) {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;this&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;.key &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; key;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;this&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;.value &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; value;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#8B949E&quot;&gt;// কমপ্লিট LRU Cache ইমপ্লিমেন্টেশন&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;export&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FFA657&quot;&gt;LRUCache&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;--0:#FFA657&quot;&gt;K&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#FFA657&quot;&gt;V&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;private&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FFA657&quot;&gt;capacity&lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;number&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;private&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FFA657&quot;&gt;cacheMap&lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FFA657&quot;&gt;Map&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;--0:#FFA657&quot;&gt;K&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#FFA657&quot;&gt;CacheNode&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;--0:#FFA657&quot;&gt;K&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#FFA657&quot;&gt;V&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;&gt;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;private&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FFA657&quot;&gt;head&lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FFA657&quot;&gt;CacheNode&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;--0:#FFA657&quot;&gt;K&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#FFA657&quot;&gt;V&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;private&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FFA657&quot;&gt;tail&lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FFA657&quot;&gt;CacheNode&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;--0:#FFA657&quot;&gt;K&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#FFA657&quot;&gt;V&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;constructor&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#FFA657&quot;&gt;capacity&lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;number&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;) {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;this&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;.capacity &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; capacity;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;this&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;.cacheMap &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D2A8FF&quot;&gt;Map&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#8B949E&quot;&gt;// ডামি Head এবং Tail নোড তৈরি করা হচ্ছে যাতে Edge Case হ্যান্ডেল করা সহজ হয়&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;this&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;.head &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D2A8FF&quot;&gt;CacheNode&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;--0:#FFA657&quot;&gt;K&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#FFA657&quot;&gt;V&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;&gt;({} &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;as&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FFA657&quot;&gt;K&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;, {} &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;as&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FFA657&quot;&gt;V&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;this&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;.tail &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D2A8FF&quot;&gt;CacheNode&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;--0:#FFA657&quot;&gt;K&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#FFA657&quot;&gt;V&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;&gt;({} &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;as&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FFA657&quot;&gt;K&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;, {} &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;as&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FFA657&quot;&gt;V&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;this&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;.head.next &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;this&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;.tail;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;this&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;.tail.prev &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;this&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;.head;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#8B949E&quot;&gt;// যেকোনো Node-কে Linked List থেকে বিচ্ছিন্ন করার O(1) লজিক&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;private&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D2A8FF&quot;&gt;removeNode&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#FFA657&quot;&gt;node&lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FFA657&quot;&gt;CacheNode&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;--0:#FFA657&quot;&gt;K&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#FFA657&quot;&gt;V&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;&gt;)&lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;void&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;prevNode&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; node.prev;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;nextNode&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; node.next;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;if&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; (prevNode &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;&amp;#x26;&amp;#x26;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; nextNode) {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;prevNode.next &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; nextNode;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;nextNode.prev &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; prevNode;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#8B949E&quot;&gt;// যেকোনো Node-কে Linked List-এর একদম শুরুতে (Head-এর পরে) যুক্ত করার O(1) লজিক&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;private&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D2A8FF&quot;&gt;addToHead&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#FFA657&quot;&gt;node&lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FFA657&quot;&gt;CacheNode&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;--0:#FFA657&quot;&gt;K&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#FFA657&quot;&gt;V&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;&gt;)&lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;void&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;node.prev &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;this&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;.head;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;node.next &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;this&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;.head.next;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;if&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;this&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;.head.next) {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;            &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;this&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;.head.next.prev &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; node;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;this&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;.head.next &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; node;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#8B949E&quot;&gt;// ডেটা পড়ার ও(1) মেথড&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D2A8FF&quot;&gt;get&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#FFA657&quot;&gt;key&lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FFA657&quot;&gt;K&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FFA657&quot;&gt;V&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;|&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;null&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;if&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;!&lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;this&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;.cacheMap.&lt;/span&gt;&lt;span style=&quot;--0:#D2A8FF&quot;&gt;has&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;(key)) {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;            &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;null&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;node&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;this&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;.cacheMap.&lt;/span&gt;&lt;span style=&quot;--0:#D2A8FF&quot;&gt;get&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;(key)&lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;!&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#8B949E&quot;&gt;// যেহেতু ডেটাটি এইমাত্র ব্যবহার হলো, তাই এটিকে সরিয়ে Head-এ নিয়ে আসা হচ্ছে&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;this&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#D2A8FF&quot;&gt;removeNode&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;(node);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;this&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#D2A8FF&quot;&gt;addToHead&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;(node);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; node.value;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#8B949E&quot;&gt;// ডেটা লেখার ও(1) মেথড&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D2A8FF&quot;&gt;put&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#FFA657&quot;&gt;key&lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FFA657&quot;&gt;K&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#FFA657&quot;&gt;value&lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FFA657&quot;&gt;V&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;void&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;if&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;this&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;.cacheMap.&lt;/span&gt;&lt;span style=&quot;--0:#D2A8FF&quot;&gt;has&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;(key)) {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;            &lt;/span&gt;&lt;span style=&quot;--0:#8B949E&quot;&gt;// ডেটা আগে থেকেই থাকলে ভ্যালু আপডেট করে Head-এ নিয়ে আসা হচ্ছে&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;            &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;existingNode&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;this&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;.cacheMap.&lt;/span&gt;&lt;span style=&quot;--0:#D2A8FF&quot;&gt;get&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;(key)&lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;!&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;existingNode.value &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; value;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;            &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;this&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#D2A8FF&quot;&gt;removeNode&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;(existingNode);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;            &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;this&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#D2A8FF&quot;&gt;addToHead&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;(existingNode);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;} &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;else&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;            &lt;/span&gt;&lt;span style=&quot;--0:#8B949E&quot;&gt;// নতুন ডেটার জন্য নতুন Node তৈরি করা হচ্ছে&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;            &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;newNode&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D2A8FF&quot;&gt;CacheNode&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;(key, value);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;            &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;this&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;.cacheMap.&lt;/span&gt;&lt;span style=&quot;--0:#D2A8FF&quot;&gt;set&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;(key, newNode);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;            &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;this&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#D2A8FF&quot;&gt;addToHead&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;(newNode);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;            &lt;/span&gt;&lt;span style=&quot;--0:#8B949E&quot;&gt;// ক্যাপাসিটি অতিক্রম করলে সবচেয়ে পুরোনো ডেটা (Tail-এর আগের Node) মুছে ফেলা হচ্ছে&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;            &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;if&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;this&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;.cacheMap.size &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;this&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;.capacity) {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;                &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;lruNode&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;this&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;.tail.prev;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;                &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;if&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; (lruNode &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;&amp;#x26;&amp;#x26;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; lruNode &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;!==&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;this&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;.head) {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;                    &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;this&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#D2A8FF&quot;&gt;removeNode&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;(lruNode);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;                    &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;this&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;.cacheMap.&lt;/span&gt;&lt;span style=&quot;--0:#D2A8FF&quot;&gt;delete&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;(lruNode.key);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;                &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#8B949E&quot;&gt;// প্রোডাকশন টেস্ট এক্সিকিউশন&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;userCache&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D2A8FF&quot;&gt;LRUCache&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;string&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;string&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#79C0FF&quot;&gt;2&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;userCache.&lt;/span&gt;&lt;span style=&quot;--0:#D2A8FF&quot;&gt;put&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;&quot;user_1&quot;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;&quot;Alice Profile&quot;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;userCache.&lt;/span&gt;&lt;span style=&quot;--0:#D2A8FF&quot;&gt;put&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;&quot;user_2&quot;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;&quot;Bob Profile&quot;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;console.&lt;/span&gt;&lt;span style=&quot;--0:#D2A8FF&quot;&gt;log&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;(userCache.&lt;/span&gt;&lt;span style=&quot;--0:#D2A8FF&quot;&gt;get&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;&quot;user_1&quot;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;)); &lt;/span&gt;&lt;span style=&quot;--0:#8B949E&quot;&gt;// Alice Profile (user_1 এখন Most Recently Used)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#8B949E&quot;&gt;// নতুন ডেটা ঢোকানোর ফলে ক্যাপাসিটি পূর্ণ হয়ে যাবে এবং user_2 (Least Recently Used) মেমোরি থেকে মুছে যাবে&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;userCache.&lt;/span&gt;&lt;span style=&quot;--0:#D2A8FF&quot;&gt;put&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;&quot;user_3&quot;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;&quot;Charlie Profile&quot;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;console.&lt;/span&gt;&lt;span style=&quot;--0:#D2A8FF&quot;&gt;log&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;(userCache.&lt;/span&gt;&lt;span style=&quot;--0:#D2A8FF&quot;&gt;get&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;&quot;user_2&quot;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;)); &lt;/span&gt;&lt;span style=&quot;--0:#8B949E&quot;&gt;// null (ডেটাটি Cache থেকে Evicted হয়ে গেছে)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;// Doubly Linked List-এর প্রতিটি Node-এর আর্কিটেকচারclass CacheNode&lt;K, V&gt; {    public key: K;    public value: V;    public prev: CacheNode&lt;K, V&gt; | null = null;    public next: CacheNode&lt;K, V&gt; | null = null;    constructor(key: K, value: V) {        this.key = key;        this.value = value;    }}// কমপ্লিট LRU Cache ইমপ্লিমেন্টেশনexport class LRUCache&lt;K, V&gt; {    private capacity: number;    private cacheMap: Map&lt;K, CacheNode&lt;K, V&gt;&gt;;    private head: CacheNode&lt;K, V&gt;;    private tail: CacheNode&lt;K, V&gt;;    constructor(capacity: number) {        this.capacity = capacity;        this.cacheMap = new Map();        // ডামি Head এবং Tail নোড তৈরি করা হচ্ছে যাতে Edge Case হ্যান্ডেল করা সহজ হয়        this.head = new CacheNode&lt;K, V&gt;({} as K, {} as V);        this.tail = new CacheNode&lt;K, V&gt;({} as K, {} as V);        this.head.next = this.tail;        this.tail.prev = this.head;    }    // যেকোনো Node-কে Linked List থেকে বিচ্ছিন্ন করার O(1) লজিক    private removeNode(node: CacheNode&lt;K, V&gt;): void {        const prevNode = node.prev;        const nextNode = node.next;        if (prevNode &amp;#x26;&amp;#x26; nextNode) {            prevNode.next = nextNode;            nextNode.prev = prevNode;        }    }    // যেকোনো Node-কে Linked List-এর একদম শুরুতে (Head-এর পরে) যুক্ত করার O(1) লজিক    private addToHead(node: CacheNode&lt;K, V&gt;): void {        node.prev = this.head;        node.next = this.head.next;        if (this.head.next) {            this.head.next.prev = node;        }        this.head.next = node;    }    // ডেটা পড়ার ও(1) মেথড    public get(key: K): V | null {        if (!this.cacheMap.has(key)) {            return null;        }        const node = this.cacheMap.get(key)!;        // যেহেতু ডেটাটি এইমাত্র ব্যবহার হলো, তাই এটিকে সরিয়ে Head-এ নিয়ে আসা হচ্ছে        this.removeNode(node);        this.addToHead(node);        return node.value;    }    // ডেটা লেখার ও(1) মেথড    public put(key: K, value: V): void {        if (this.cacheMap.has(key)) {            // ডেটা আগে থেকেই থাকলে ভ্যালু আপডেট করে Head-এ নিয়ে আসা হচ্ছে            const existingNode = this.cacheMap.get(key)!;            existingNode.value = value;            this.removeNode(existingNode);            this.addToHead(existingNode);        } else {            // নতুন ডেটার জন্য নতুন Node তৈরি করা হচ্ছে            const newNode = new CacheNode(key, value);            this.cacheMap.set(key, newNode);            this.addToHead(newNode);            // ক্যাপাসিটি অতিক্রম করলে সবচেয়ে পুরোনো ডেটা (Tail-এর আগের Node) মুছে ফেলা হচ্ছে            if (this.cacheMap.size &gt; this.capacity) {                const lruNode = this.tail.prev;                if (lruNode &amp;#x26;&amp;#x26; lruNode !== this.head) {                    this.removeNode(lruNode);                    this.cacheMap.delete(lruNode.key);                }            }        }    }}// প্রোডাকশন টেস্ট এক্সিকিউশনconst userCache = new LRUCache&lt;string, string&gt;(2);userCache.put(&amp;#x22;user_1&amp;#x22;, &amp;#x22;Alice Profile&amp;#x22;);userCache.put(&amp;#x22;user_2&amp;#x22;, &amp;#x22;Bob Profile&amp;#x22;);console.log(userCache.get(&amp;#x22;user_1&amp;#x22;)); // Alice Profile (user_1 এখন Most Recently Used)// নতুন ডেটা ঢোকানোর ফলে ক্যাপাসিটি পূর্ণ হয়ে যাবে এবং user_2 (Least Recently Used) মেমোরি থেকে মুছে যাবেuserCache.put(&amp;#x22;user_3&amp;#x22;, &amp;#x22;Charlie Profile&amp;#x22;);console.log(userCache.get(&amp;#x22;user_2&amp;#x22;)); // null (ডেটাটি Cache থেকে Evicted হয়ে গেছে)&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;h2 id=&quot;রিক্যাপ-এবং-প্রোডাকশন-চেকলিস্ট&quot;&gt;রিক্যাপ এবং প্রোডাকশন চেকলিস্ট&lt;/h2&gt;
&lt;p&gt;আমাদের এই দীর্ঘ এবং গভীর আলোচনার মাধ্যমে আমরা একটি বিষয় অত্যন্ত স্পষ্টভাবে বুঝতে পেরেছি: একজন জুনিয়র ডেভেলপার থেকে একজন দক্ষ সিস্টেম আর্কিটেক্ট হওয়ার মূল পার্থক্যটি লুকিয়ে আছে চিন্তার গভীরতায়। জুনিয়র ডেভেলপাররা চিন্তা করেন কোডটি কীভাবে কাজ করবে এবং আউটপুট দেবে। আর একজন আর্কিটেক্ট চিন্তা করেন কোডটি যখন এক লাখ বা এক কোটি বার এক্সিকিউট হবে, তখন মেমোরি লেআউট কেমন হবে, নেটওয়ার্ক লেটেন্সি কত হবে, এবং প্রসেসরের ওপর কতটুকু চাপ পড়বে। Data Structure এবং Algorithm শুধুমাত্র চাকরির ইন্টারভিউ পাশ করার কোনো তাত্ত্বিক বিষয় নয়; এটি হলো আপনার সফটওয়্যার ইঞ্জিনিয়ারিং ক্যারিয়ারের সবচেয়ে শক্তিশালী ভিত্তি, যা আপনাকে স্কেলেবল, দ্রুতগতির এবং নির্ভরযোগ্য প্রোডাকশন সিস্টেম তৈরি করার ক্ষমতা প্রদান করে।&lt;/p&gt;
&lt;p&gt;ভবিষ্যতে যখনই আপনি কোনো নতুন সিস্টেমের আর্কিটেকচার ডিজাইন করবেন বা কোনো জটিল প্রবলেম সলভ করবেন, তখন সিদ্ধান্ত নেওয়ার জন্য নিচের ডেভেলপার ডিসিশন চেকলিস্টটি সবসময় মনে রাখবেন:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Array ব্যবহার করবেন যখন:&lt;/strong&gt; আপনার ডেটার আকার আগে থেকেই নির্দিষ্ট থাকে, মেমোরি ব্যবহারের ক্ষেত্রে সর্বোচ্চ অপটিমাইজেশন প্রয়োজন হয়, এবং ইনডেক্স নম্বর ধরে বারবার ডেটা পড়ার (O(1) Lookup) প্রয়োজন সবচেয়ে বেশি থাকে।&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Linked List ব্যবহার করবেন যখন:&lt;/strong&gt; আপনার সিস্টেমে প্রতিনিয়ত ডেটার আকার পরিবর্তিত হয়, এবং তালিকার মাঝখান থেকে বা শুরু থেকে দ্রুত ডেটা ইনসার্ট বা ডিলিট করার প্রয়োজন হয়।&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Hash Table / Map ব্যবহার করবেন যখন:&lt;/strong&gt; যেকোনো বিশাল ডেটাসেট থেকে কোনো একটি নির্দিষ্ট Key বা চাবি ধরে একদম মিলি-সেকেন্ডে বা O(1) সময়ে ডেটা খুঁজে বের করার প্রয়োজন হয়।&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Tree / Binary Search Tree (BST) ব্যবহার করবেন যখন:&lt;/strong&gt; ডেটার মধ্যে হায়েরার্কি বা ক্রমানুসারে সম্পর্ক বজায় রাখতে হয়, এবং সর্টেড ডেটার ওপর দ্রুত Range Query বা সার্চ চালানোর প্রয়োজন হয়।&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Graph ব্যবহার করবেন যখন:&lt;/strong&gt; বাস্তব পৃথিবীর কোনো নেটওয়ার্ক, সোশ্যাল মিডিয়া কানেকশন, রাস্তাঘাটের ম্যাপ বা জটিল রুট ক্যালকুলেশনের লজিক ইমপ্লিমেন্ট করতে হয়।&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Queue ব্যবহার করবেন when:&lt;/strong&gt; আপনার সিস্টেমে আসা হাজার হাজার Request বা Background Job-কে সিরিয়াল অনুযায়ী বা FIFO (First In, First Out) পদ্ধতিতে একে একে প্রসেস করার প্রয়োজন হয়।&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Stack ব্যবহার করবেন যখন:&lt;/strong&gt; আপনার লজিকে LIFO (Last In, First Out) আর্কিটেকচার প্রয়োজন হয়, যেমন হিস্ট্রি ট্র্যাকিং, সিনট্যাক্স পার্সিং, বা Undo-Redo মেকানিজম তৈরি করা।&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;আপনার ইঞ্জিনিয়ারিং যাত্রা শুভ হোক। সঠিক আর্কিটেকচারাল সিদ্ধান্তের মাধ্যমে আপনার তৈরি প্রতিটি সিস্টেম হয়ে উঠুক প্রোডাকশন-রেডি এবং হাইলি স্কেলেবল।&lt;/p&gt;</content:encoded><category>Software Engineering</category><category>Software Engineering</category><category>Data Structures</category><category>Algorithms</category><category>System Architecture</category><category>Performance Optimization</category><category>Big-O Notation</category><category>Backend Engineering</category><category>Scalability</category><category>Caching</category><category>Database Indexing</category></item><item><title>Messenger-এর &quot;Delete Conversation&quot; ফিচার আসলে Under-the-Hood কীভাবে কাজ করে?</title><link>https://www.rafeuddaraj.me/bn/blog/messenger-delete-conversation-architecture-deep-dive/</link><guid isPermaLink="true">https://www.rafeuddaraj.me/bn/blog/messenger-delete-conversation-architecture-deep-dive/</guid><description>Distributed systems এবং high-throughput chat applications-এ database-level hard delete না চালিয়ে কীভাবে timestamp-based view filtering এবং metadata pointer ব্যবহার করে Big-O(1) storage complexity-তে conversation clear করা হয়, তার একটি deep architectural breakdown।</description><pubDate>Wed, 10 Jun 2026 12:05:10 GMT</pubDate><content:encoded>&lt;p&gt;সাধারণ ডেভেলপারদের মধ্যে একটি প্রচলিত ধারণা রয়েছে যে, কোনো চ্যাট অ্যাপ্লিকেশনে &quot;Delete Conversation&quot; বাটনে ক্লিক করা মানেই backend থেকে সরাসরি database-এর ওপর একটি &lt;code&gt;DELETE&lt;/code&gt; কোয়েরি চালিয়ে দেওয়া। আপনি যদি ছোটখাটো কোনো প্রজেক্ট তৈরি করেন, তবে এই ব্রুট-ফোর্স পদ্ধতি কাজ করতে পারে। কিন্তু যখন আপনি মেসেঞ্জারের মতো high-throughput distributed systems নিয়ে কাজ করবেন, যেখানে প্রতি সেকেন্ডে লাখ লাখ রিকোয়েস্ট প্রসেস হয়, সেখানে hard delete চালানো বা প্রতিটি ইউজারের জন্য আলাদা করে data duplication করা একটি মারাত্মক engineering disaster ডেকে আনতে পারে।&lt;/p&gt;
&lt;p&gt;চলুন শুরুতে বোঝার চেষ্টা করি, কেন সাধারণ বা naive approach-গুলো production environment-এ পুরোপুরি ব্যর্থ হয়।&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Hard Delete Fallacy: আপনি যখন কোনো চ্যাট ডিলিট করেন এবং সিস্টেম যদি সরাসরি ডিলিট কোয়েরি চালায়, তবে আপনার ডিলিট রিকোয়েস্টের কারণে আপনার এবং আপনার সাথে চ্যাট করা অপর ইউজারের ইনবক্স থেকে পুরো ডাটা মুছে যাবে। এটি কোনোভাবেই গ্রহণযোগ্য নয়, কারণ এতে business recall এবং user experience দুটোই সম্পূর্ণ নষ্ট হয়।&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Data Duplication Anti-Pattern: এই সমস্যা সমাধানের জন্য অনেক ডেভেলপার প্রতিটি ইউজারের জন্য আলাদা database row তৈরি করার কথা ভাবেন। কিন্তু যখনই আপনি প্রতিটি মেসেজের জন্য দুটি করে row তৈরি করবেন, তখনই সিস্টেমে write amplification ঘটবে।&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Impact on Production: ডাটা ডুপ্লিকেশনের ফলে storage costs অস্বাভাবিক হারে বৃদ্ধি পায়। এছাড়া database index অত্যন্ত ভারী হয়ে যায় এবং query latency এক্সপোনেনশিয়ালি বেড়ে গিয়ে পুরো সিস্টেমকে ধীরগতির করে তোলে।&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;The Core Solution: এই জটিল সমস্যার সমাধান করতে মেসেঞ্জারের মতো স্কেলাবল সিস্টেমগুলো smart metadata management এবং timestamp-based view filtering ব্যবহার করে। এর ফলে কোনো মেসেজ ডিলিট না করেই Big-O(1) storage complexity-তে পুরো সমস্যার একটি অপটিমাইজড সমাধান নিশ্চিত করা সম্ভব হয়।&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id=&quot;foundational-mental-model-এবং-একটি-রিয়েল-ওয়ার্ল্ড-অ্যানালজি&quot;&gt;Foundational Mental Model এবং একটি রিয়েল-ওয়ার্ল্ড অ্যানালজি&lt;/h2&gt;
&lt;p&gt;লো-লেভেল আর্কিটেকচারে ঢোকার আগে আমাদের একটি কোর কনসেপ্ট পরিষ্কার করতে হবে, আর তা হলো Shared Immutable Data vs. User-Specific View State। এর মূল দর্শন হলো, মূল ডাটা বা মেসেজ লগ সবসময় অপরিবর্তিত থাকবে, আমরা কেবল ইউজারের read query-র বাউন্ডারি বা সীমানা পরিবর্তন করে দেব।&lt;/p&gt;
&lt;p&gt;বিষয়টি সহজে বোঝার জন্য আমরা একটি বাস্তব জীবনের অ্যানালজি ব্যবহার করতে পারি।&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;The Setup: মনে করুন, আপনার অফিসের দেওয়ালে একটি বিশাল shared noticeboard রয়েছে, যেখানে প্রতিদিনের বিভিন্ন প্রাতিষ্ঠানিক নোটিশ টাঙানো হয়।&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;The Problem: কয়েক মাসের পুরনো নোটিশগুলো দেখে আপনার কাজের মনোযোগ নষ্ট হচ্ছে, কিন্তু আপনার সহকর্মীর রানিং প্রজেক্টের জন্য সেই পুরনো নোটিশগুলো অত্যন্ত প্রয়োজন।&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;The Naive Fixes: এই পরিস্থিতিতে আপনি যদি বোর্ড থেকে নোটিশগুলো ছিঁড়ে ফেলেন (Hard Delete), তবে আপনার সহকর্মী বিপদে পড়বেন। আবার আপনাদের দুজনের জন্য আলাদা দুটি বিশাল নোটিশবোর্ড তৈরি করাও (Data Duplication) একটি অপচয় এবং অবাস্তব সমাধান।&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;The Smart Solution: এর চেয়ে অনেক স্মার্ট সমাধান হলো, আপনি চোখে একটি বিশেষ visor বা চশমা পরে নেবেন, যার মধ্যে একটি ফিল্টার লজিক সেট করা থাকবে: &quot;আজ সকাল ১০টার আগের কোনো নোটিশ আমাকে দেখাবে না&quot;। এতে করে নোটিশবোর্ডে পুরনো নোটিশ ঠিকই থাকবে, কিন্তু আপনার চোখ কেবল সকাল ১০টার পরের নোটিশগুলোই দেখতে পাবে।&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Application to Software: আমাদের সফটওয়্যার আর্কিটেকচারে database হলো সেই shared noticeboard, আর ইউজারের profile metadata-তে থাকা timestamp হলো আপনার চশমার ফিল্টার।&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;figure&gt;&lt;img src=&quot;https://raw.githubusercontent.com/rafeuddaraj/rafes-blog-assets/refs/heads/messenger-delete-conversation-architecture-deep-dive/assets/shared-vs-duplicated-storage-model.svg&quot; alt=&quot;Shared Data Model vs Duplicated Storage Model&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;800&quot; height=&quot;400&quot;&gt;&lt;figcaption&gt;Shared Data Model vs Duplicated Storage Model&lt;/figcaption&gt;&lt;/figure&gt;
&lt;hr&gt;
&lt;h2 id=&quot;under-the-hood-architecture-the-core-deep-dive&quot;&gt;Under-The-Hood Architecture (The Core Deep Dive)&lt;/h2&gt;
&lt;p&gt;এখন চলুন আমরা সরাসরি database engine-এর ভেতরে প্রবেশ করি। এই আর্কিটেকচারটি ঠিকমতো কাজ করানোর জন্য আমাদের relational বা NoSQL document store-কে প্রধানত দুটি আলাদা লেয়ারে বিভক্ত করতে হবে।&lt;/p&gt;
&lt;h3 id=&quot;a-messages-table-the-immutable-log&quot;&gt;A. &lt;code&gt;messages&lt;/code&gt; Table (The Immutable Log)&lt;/h3&gt;
&lt;p&gt;এটি হলো আমাদের মূল মেসেজ স্টোরেজ, যা একটি append-only টেবিল হিসেবে কাজ করে। সাধারণ অপারেশনে এই টেবিলে কখনো কোনো &lt;code&gt;UPDATE&lt;/code&gt; বা &lt;code&gt;DELETE&lt;/code&gt; কোয়েরি চালানো হয় না। এই টেবিলের core columns-গুলো হলো: &lt;code&gt;message_id&lt;/code&gt; (UUID), &lt;code&gt;conversation_id&lt;/code&gt; (Indexed UUID), &lt;code&gt;sender_id&lt;/code&gt; (UUID), &lt;code&gt;payload&lt;/code&gt; (Text/Blob), এবং &lt;code&gt;created_at&lt;/code&gt; (Timestamp)।&lt;/p&gt;
&lt;h3 id=&quot;b-conversationparticipants-table-the-view-state-engine&quot;&gt;B. &lt;code&gt;conversation_participants&lt;/code&gt; Table (The View State Engine)&lt;/h3&gt;
&lt;p&gt;এটি হলো আমাদের সিস্টেমের আসল ম্যাজিক বক্স, যা প্রতিটি ইউজারের পার্সোনাল স্টেট এবং ভিউ বাউন্ডারি ট্র্যাক করে। এই টেবিলের core columns-গুলোর মধ্যে রয়েছে &lt;code&gt;conversation_id&lt;/code&gt;, &lt;code&gt;user_id&lt;/code&gt;, &lt;code&gt;last_read_timestamp&lt;/code&gt;, এবং সবচাইতে গুরুত্বপূর্ণ &lt;code&gt;cleared_at_timestamp&lt;/code&gt; (যা একটি invisible wall বা অদৃশ্য দেয়াল হিসেবে কাজ করে)।&lt;/p&gt;
&lt;h3 id=&quot;the-query-mechanics&quot;&gt;The Query Mechanics&lt;/h3&gt;
&lt;p&gt;যখন কোনো ইউজার তার ইনবক্স লোড করে বা কোনো নির্দিষ্ট চ্যাট থ্রেড ওপেন করে, তখন আমাদের backend engine কখনোই সাধারণ &lt;code&gt;SELECT *&lt;/code&gt; কোয়েরি চালায় না। এর বদলে সিস্টেম একটি filtered read query এক্সিকিউট করে। কোয়েরির SQL logic-টি দেখতে ঠিক নিচের মতো হয়:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;style&gt;.expressive-code{font-family:var(--ec-uiFontFml);font-size:var(--ec-uiFontSize);font-weight:var(--ec-uiFontWg);line-height:var(--ec-uiLineHt);text-size-adjust:none;-webkit-text-size-adjust:none}.expressive-code *:not(:is(svg, svg *)){all:revert;box-sizing:border-box}.expressive-code pre{display:flex;margin:0;padding:0;border:var(--ec-brdWd) solid var(--ec-brdCol);border-radius:calc(var(--ec-brdRad) + var(--ec-brdWd));background:var(--ec-codeBg)}.expressive-code pre:focus-visible{outline:3px solid var(--ec-focusBrd);outline-offset:-3px}.expressive-code pre &gt; code{all:unset;display:block;flex:1 0 100%;padding:var(--ec-codePadBlk) 0;color:var(--ec-codeFg);font-family:var(--ec-codeFontFml);font-size:var(--ec-codeFontSize);font-weight:var(--ec-codeFontWg);line-height:var(--ec-codeLineHt)}.expressive-code pre{overflow-x:auto}.expressive-code pre.wrap .ec-line .code{white-space:pre-wrap;overflow-wrap:break-word;min-width:min(20ch, var(--ecMaxLine, 20ch))}.expressive-code pre.wrap .ec-line .code span.indent{white-space:pre}.expressive-code pre::-webkit-scrollbar,.expressive-code pre::-webkit-scrollbar-track{background-color:inherit;border-radius:calc(var(--ec-brdRad) + var(--ec-brdWd));border-top-left-radius:0;border-top-right-radius:0}.expressive-code pre::-webkit-scrollbar-thumb{background-color:var(--ec-sbThumbCol);border:4px solid transparent;background-clip:content-box;border-radius:10px}.expressive-code pre::-webkit-scrollbar-thumb:hover{background-color:var(--ec-sbThumbHoverCol)}.expressive-code pre::-webkit-scrollbar-corner{background:transparent}.expressive-code .ec-line{direction:ltr;unicode-bidi:isolate;display:grid;grid-template-areas:&apos;gutter code&apos;;grid-template-columns:auto 1fr;position:relative}.expressive-code .ec-line .gutter{grid-area:gutter;color:var(--ec-gtrFg)}.expressive-code .ec-line .gutter &gt; *{pointer-events:none;user-select:none;-webkit-user-select:none}.expressive-code .ec-line .gutter ~ .code{--ecLineBrdCol:var(--ec-gtrBrdCol)}.expressive-code .ec-line.highlight .gutter{color:var(--ec-gtrHlFg)}.expressive-code .ec-line .code{grid-area:code;position:relative;box-sizing:content-box;padding-inline-start:calc(var(--ecIndent, 0ch) + var(--ec-codePadInl) - var(--ecGtrBrdWd));padding-inline-end:var(--ec-codePadInl);text-indent:calc(var(--ecIndent, 0ch) * -1)}.expressive-code .ec-line .code::before,.expressive-code .ec-line .code::after,.expressive-code .ec-line .code :where(*){text-indent:0}.expressive-code .ec-line .code{--ecGtrBrdWd:var(--ec-gtrBrdWd);border-inline-start:var(--ecGtrBrdWd) solid var(--ecLineBrdCol, transparent)}.expressive-code .sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0, 0, 0, 0);white-space:nowrap;border-width:0}.expressive-code .ec-line.mark{--tmLineBgCol:var(--ec-tm-markBg)}.expressive-code .ec-line.mark .code{--ecLineBrdCol:var(--ec-tm-markBrdCol)}.expressive-code .ec-line.ins{--tmLineBgCol:var(--ec-tm-insBg);--tmLabel:var(--ec-tm-insDiffIndContent)}.expressive-code .ec-line.ins .code{--ecLineBrdCol:var(--ec-tm-insBrdCol)}.expressive-code .ec-line.ins .code::before{color:var(--ec-tm-insDiffIndCol)}.expressive-code .ec-line.del{--tmLineBgCol:var(--ec-tm-delBg);--tmLabel:var(--ec-tm-delDiffIndContent)}.expressive-code .ec-line.del .code{--ecLineBrdCol:var(--ec-tm-delBrdCol)}.expressive-code .ec-line.del .code::before{color:var(--ec-tm-delDiffIndCol)}.expressive-code .ec-line.mark,.expressive-code .ec-line.ins,.expressive-code .ec-line.del{background:var(--tmLineBgCol)}.expressive-code .ec-line.mark .code,.expressive-code .ec-line.ins .code,.expressive-code .ec-line.del .code{--ecGtrBrdWd:var(--ec-tm-lineMarkerAccentWd)}.expressive-code .ec-line.mark .code::before,.expressive-code .ec-line.ins .code::before,.expressive-code .ec-line.del .code::before{display:block;position:absolute;left:0;box-sizing:border-box;content:var(--tmLabel, &apos; &apos;);padding-inline-start:var(--ec-tm-lineDiffIndMargLeft);text-align:center;white-space:pre}.expressive-code .ec-line.mark.tm-label .code::before,.expressive-code .ec-line.ins.tm-label .code::before,.expressive-code .ec-line.del.tm-label .code::before{background:var(--ecLineBrdCol);padding:0 calc(var(--ec-tm-lineMarkerLabelPadInl) + var(--ec-tm-lineMarkerAccentWd)) 0 var(--ec-tm-lineMarkerLabelPadInl);color:var(--ec-tm-lineMarkerLabelCol)}.expressive-code .ec-line mark{--tmInlineBgCol:var(--ec-tm-markBg);--tmInlineBrdCol:var(--ec-tm-markBrdCol)}.expressive-code .ec-line ins{--tmInlineBgCol:var(--ec-tm-insBg);--tmInlineBrdCol:var(--ec-tm-insBrdCol)}.expressive-code .ec-line del{--tmInlineBgCol:var(--ec-tm-delBg);--tmInlineBrdCol:var(--ec-tm-delBrdCol)}.expressive-code .ec-line mark,.expressive-code .ec-line ins,.expressive-code .ec-line del{all:unset;display:inline-block;position:relative;--tmBrdL:var(--ec-tm-inlMarkerBrdWd);--tmBrdR:var(--ec-tm-inlMarkerBrdWd);--tmRadL:var(--ec-tm-inlMarkerBrdRad);--tmRadR:var(--ec-tm-inlMarkerBrdRad);margin-inline:0.025rem;padding-inline:var(--ec-tm-inlMarkerPad);border-radius:var(--tmRadL) var(--tmRadR) var(--tmRadR) var(--tmRadL);background:var(--tmInlineBgCol);background-clip:padding-box}.expressive-code .ec-line mark.open-start,.expressive-code .ec-line ins.open-start,.expressive-code .ec-line del.open-start{margin-inline-start:0;padding-inline-start:0;--tmBrdL:0px;--tmRadL:0}.expressive-code .ec-line mark.open-end,.expressive-code .ec-line ins.open-end,.expressive-code .ec-line del.open-end{margin-inline-end:0;padding-inline-end:0;--tmBrdR:0px;--tmRadR:0}.expressive-code .ec-line mark::before,.expressive-code .ec-line ins::before,.expressive-code .ec-line del::before{content:&apos;&apos;;position:absolute;pointer-events:none;display:inline-block;inset:0;border-radius:var(--tmRadL) var(--tmRadR) var(--tmRadR) var(--tmRadL);border:var(--ec-tm-inlMarkerBrdWd) solid var(--tmInlineBrdCol);border-inline-width:var(--tmBrdL) var(--tmBrdR)}.expressive-code .frame{all:unset;position:relative;display:block;--header-border-radius:calc(var(--ec-brdRad) + var(--ec-brdWd));--tab-border-radius:calc(var(--ec-frm-edTabBrdRad) + var(--ec-brdWd));--button-spacing:0.4rem;--code-background:var(--ec-frm-edBg);border-radius:var(--header-border-radius);box-shadow:var(--ec-frm-frameBoxShdCssVal)}.expressive-code .frame .header{display:none;z-index:1;position:relative;border-radius:var(--header-border-radius) var(--header-border-radius) 0 0}.expressive-code .frame.has-title pre,.expressive-code .frame.has-title code,.expressive-code .frame.is-terminal pre,.expressive-code .frame.is-terminal code{border-top:none;border-top-left-radius:0;border-top-right-radius:0}.expressive-code .frame .title:empty:before{content:&apos;\a0&apos;}.expressive-code .frame.has-title:not(.is-terminal){--button-spacing:calc(1.9rem + 2 * (var(--ec-uiPadBlk) + var(--ec-frm-edActTabIndHt)))}.expressive-code .frame.has-title:not(.is-terminal) .title{position:relative;color:var(--ec-frm-edActTabFg);background:var(--ec-frm-edActTabBg);background-clip:padding-box;margin-block-start:var(--ec-frm-edTabsMargBlkStart);padding:calc(var(--ec-uiPadBlk) + var(--ec-frm-edActTabIndHt)) var(--ec-uiPadInl);border:var(--ec-brdWd) solid var(--ec-frm-edActTabBrdCol);border-radius:var(--tab-border-radius) var(--tab-border-radius) 0 0;border-bottom:none;overflow:hidden}.expressive-code .frame.has-title:not(.is-terminal) .title::after{content:&apos;&apos;;position:absolute;pointer-events:none;inset:0;border-top:var(--ec-frm-edActTabIndHt) solid var(--ec-frm-edActTabIndTopCol);border-bottom:var(--ec-frm-edActTabIndHt) solid var(--ec-frm-edActTabIndBtmCol)}.expressive-code .frame.has-title:not(.is-terminal) .header{display:flex;background:linear-gradient(to top, var(--ec-frm-edTabBarBrdBtmCol) var(--ec-brdWd), transparent var(--ec-brdWd)),linear-gradient(var(--ec-frm-edTabBarBg), var(--ec-frm-edTabBarBg));background-repeat:no-repeat;padding-inline-start:var(--ec-frm-edTabsMargInlStart)}.expressive-code .frame.has-title:not(.is-terminal) .header::before{content:&apos;&apos;;position:absolute;pointer-events:none;inset:0;border:var(--ec-brdWd) solid var(--ec-frm-edTabBarBrdCol);border-radius:inherit;border-bottom:none}.expressive-code .frame.is-terminal{--button-spacing:calc(1.9rem + var(--ec-brdWd) + 2 * var(--ec-uiPadBlk));--code-background:var(--ec-frm-trmBg)}.expressive-code .frame.is-terminal .header{display:flex;align-items:center;justify-content:center;padding-block:var(--ec-uiPadBlk);padding-block-end:calc(var(--ec-uiPadBlk) + var(--ec-brdWd));position:relative;font-weight:500;letter-spacing:0.025ch;color:var(--ec-frm-trmTtbFg);background:var(--ec-frm-trmTtbBg);border:var(--ec-brdWd) solid var(--ec-brdCol);border-bottom:none}.expressive-code .frame.is-terminal .header::before{content:&apos;&apos;;position:absolute;pointer-events:none;left:var(--ec-uiPadInl);width:2.1rem;height:0.56rem;line-height:0;background-color:var(--ec-frm-trmTtbDotsFg);opacity:var(--ec-frm-trmTtbDotsOpa);-webkit-mask-image:var(--ec-frm-trmIcon);-webkit-mask-repeat:no-repeat;mask-image:var(--ec-frm-trmIcon);mask-repeat:no-repeat}.expressive-code .frame.is-terminal .header::after{content:&apos;&apos;;position:absolute;pointer-events:none;inset:0;border-bottom:var(--ec-brdWd) solid var(--ec-frm-trmTtbBrdBtmCol)}.expressive-code .frame pre{background:var(--code-background)}.expressive-code .copy{display:flex;gap:0.25rem;flex-direction:row;position:absolute;inset-block-start:calc(var(--ec-brdWd) + var(--button-spacing));inset-inline-end:calc(var(--ec-brdWd) + var(--ec-uiPadInl) / 2)}@media (scripting: none){.expressive-code .copy{display:none}}.expressive-code .copy{direction:ltr;unicode-bidi:isolate}.expressive-code .copy button{position:relative;align-self:flex-end;margin:0;padding:0;border:none;border-radius:0.2rem;z-index:1;cursor:pointer;transition-property:opacity, background, border-color;transition-duration:0.2s;transition-timing-function:cubic-bezier(0.25, 0.46, 0.45, 0.94);width:2.5rem;height:2.5rem;background:var(--code-background);opacity:0.75}.expressive-code .copy button div{position:absolute;inset:0;border-radius:inherit;background:var(--ec-frm-inlBtnBg);opacity:var(--ec-frm-inlBtnBgIdleOpa);transition-property:inherit;transition-duration:inherit;transition-timing-function:inherit}.expressive-code .copy button::before{content:&apos;&apos;;position:absolute;pointer-events:none;inset:0;border-radius:inherit;border:var(--ec-brdWd) solid var(--ec-frm-inlBtnBrd);opacity:var(--ec-frm-inlBtnBrdOpa)}.expressive-code .copy button::after{content:&apos;&apos;;position:absolute;pointer-events:none;inset:0;background-color:var(--ec-frm-inlBtnFg);-webkit-mask-image:var(--ec-frm-copyIcon);-webkit-mask-repeat:no-repeat;mask-image:var(--ec-frm-copyIcon);mask-repeat:no-repeat;margin:0.475rem;line-height:0}.expressive-code .copy button:hover,.expressive-code .copy button:focus:focus-visible{opacity:1}.expressive-code .copy button:hover div,.expressive-code .copy button:focus:focus-visible div{opacity:var(--ec-frm-inlBtnBgHoverOrFocusOpa)}.expressive-code .copy button:active{opacity:1}.expressive-code .copy button:active div{opacity:var(--ec-frm-inlBtnBgActOpa)}.expressive-code .copy .feedback{--tooltip-arrow-size:0.35rem;--tooltip-bg:var(--ec-frm-tooltipSuccessBg);color:var(--ec-frm-tooltipSuccessFg);pointer-events:none;user-select:none;-webkit-user-select:none;position:relative;align-self:center;background-color:var(--tooltip-bg);z-index:99;padding:0.125rem 0.75rem;border-radius:0.2rem;margin-inline-end:var(--tooltip-arrow-size);opacity:0;transition-property:opacity, transform;transition-duration:0.2s;transition-timing-function:ease-in-out;transform:translate3d(0, 0.25rem, 0)}.expressive-code .copy .feedback::after{content:&apos;&apos;;position:absolute;pointer-events:none;top:calc(50% - var(--tooltip-arrow-size));inset-inline-end:calc(-2 * (var(--tooltip-arrow-size) - 0.5px));border:var(--tooltip-arrow-size) solid transparent;border-inline-start-color:var(--tooltip-bg)}.expressive-code .copy .feedback.show{opacity:1;transform:translate3d(0, 0, 0)}@media (hover: hover){.expressive-code{}.expressive-code .copy button{opacity:0;width:2rem;height:2rem}.expressive-code .frame:hover .copy button:not(:hover),.expressive-code .frame:focus-within :focus-visible ~ .copy button:not(:hover),.expressive-code .frame .copy .feedback.show ~ button:not(:hover){opacity:0.75}}.expressive-code :nth-child(1 of .ec-line) .code{padding-inline-end:calc(2rem + var(--ec-codePadInl))}:root{--ec-brdRad:0.75rem;--ec-brdWd:1.5px;--ec-brdCol:var(--code-line);--ec-codeFontFml:var(--font-code);--ec-codeFontSize:0.875rem;--ec-codeFontWg:400;--ec-codeLineHt:1.75;--ec-codePadBlk:1rem;--ec-codePadInl:1.125rem;--ec-codeBg:var(--code-bg);--ec-codeFg:#e6edf3;--ec-codeSelBg:#264f78;--ec-gtrFg:#6e7681;--ec-gtrBrdCol:#6e768133;--ec-gtrBrdWd:1.5px;--ec-gtrHlFg:#e6edf3;--ec-uiFontFml:var(--font-mono);--ec-uiFontSize:0.75rem;--ec-uiFontWg:400;--ec-uiLineHt:1.65;--ec-uiPadBlk:0.25rem;--ec-uiPadInl:1rem;--ec-uiSelBg:#6e768166;--ec-uiSelFg:#e6edf3;--ec-focusBrd:#1f6feb;--ec-sbThumbCol:#8b949e33;--ec-sbThumbHoverCol:#8b949e3d;--ec-tm-lineMarkerAccentMarg:0rem;--ec-tm-lineMarkerAccentWd:0.15rem;--ec-tm-lineMarkerLabelPadInl:0.2rem;--ec-tm-lineMarkerLabelCol:white;--ec-tm-lineDiffIndMargLeft:0.3rem;--ec-tm-inlMarkerBrdWd:1.5px;--ec-tm-inlMarkerBrdRad:0.2rem;--ec-tm-inlMarkerPad:0.15rem;--ec-tm-insDiffIndContent:&apos;+&apos;;--ec-tm-delDiffIndContent:&apos;-&apos;;--ec-tm-markBg:#264a8980;--ec-tm-markBrdCol:#5570b3d0;--ec-tm-insBg:#26561c80;--ec-tm-insBrdCol:#4e7e41d0;--ec-tm-insDiffIndCol:#7eb070d0;--ec-tm-delBg:#81322b80;--ec-tm-delBrdCol:#ae594fd0;--ec-tm-delDiffIndCol:#e68a7ed0;--ec-frm-shdCol:#0000005b;--ec-frm-frameBoxShdCssVal:none;--ec-frm-edActTabBg:var(--code-bg);--ec-frm-edActTabFg:var(--code-muted);--ec-frm-edActTabBrdCol:transparent;--ec-frm-edActTabIndHt:1.5px;--ec-frm-edActTabIndTopCol:transparent;--ec-frm-edActTabIndBtmCol:#0d1117;--ec-frm-edTabsMargInlStart:0;--ec-frm-edTabsMargBlkStart:0;--ec-frm-edTabBrdRad:0.75rem;--ec-frm-edTabBarBg:var(--code-bg);--ec-frm-edTabBarBrdCol:var(--code-line);--ec-frm-edTabBarBrdBtmCol:var(--code-line);--ec-frm-edBg:var(--code-bg);--ec-frm-trmTtbFg:var(--code-muted);--ec-frm-trmTtbDotsFg:var(--code-muted);--ec-frm-trmTtbDotsOpa:0.15;--ec-frm-trmTtbBg:var(--code-bg);--ec-frm-trmTtbBrdBtmCol:var(--code-line);--ec-frm-trmBg:var(--code-bg);--ec-frm-inlBtnBg:var(--code-ink);--ec-frm-inlBtnBgIdleOpa:0;--ec-frm-inlBtnBgHoverOrFocusOpa:0.2;--ec-frm-inlBtnBgActOpa:0.3;--ec-frm-inlBtnFg:var(--code-ink);--ec-frm-inlBtnBrd:var(--code-line);--ec-frm-inlBtnBrdOpa:0.4;--ec-frm-tooltipSuccessBg:var(--color-emerald);--ec-frm-tooltipSuccessFg:var(--color-bg);--ec-frm-copyIcon:url(&quot;data:image/svg+xml,%3Csvg%20xmlns%3D&apos;http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg&apos;%20viewBox%3D&apos;0%200%2024%2024&apos;%20fill%3D&apos;none&apos;%20stroke%3D&apos;black&apos;%20stroke-width%3D&apos;1.75&apos;%3E%3Cpath%20d%3D&apos;M3%2019a2%202%200%200%201-1-2V2a2%202%200%200%201%201-1h13a2%202%200%200%201%202%201&apos;%2F%3E%3Crect%20x%3D&apos;6&apos;%20y%3D&apos;5&apos;%20width%3D&apos;16&apos;%20height%3D&apos;18&apos;%20rx%3D&apos;1.5&apos;%20ry%3D&apos;1.5&apos;%2F%3E%3C%2Fsvg%3E&quot;);--ec-frm-trmIcon:url(&quot;data:image/svg+xml,%3Csvg%20xmlns%3D&apos;http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg&apos;%20viewBox%3D&apos;0%200%2060%2016&apos;%20preserveAspectRatio%3D&apos;xMidYMid%20meet&apos;%3E%3Ccircle%20cx%3D&apos;8&apos;%20cy%3D&apos;8&apos;%20r%3D&apos;8&apos;%2F%3E%3Ccircle%20cx%3D&apos;30&apos;%20cy%3D&apos;8&apos;%20r%3D&apos;8&apos;%2F%3E%3Ccircle%20cx%3D&apos;52&apos;%20cy%3D&apos;8&apos;%20r%3D&apos;8&apos;%2F%3E%3C%2Fsvg%3E&quot;)}.expressive-code .ec-line :where(span[style^=&apos;--&apos;]:not([class])){color:var(--0, inherit);background-color:var(--0bg, transparent);font-style:var(--0fs, inherit);font-weight:var(--0fw, inherit);text-decoration:var(--0td, inherit)}&lt;/style&gt;&lt;script type=&quot;module&quot; src=&quot;/_astro/ec.0vx5m.js&quot;&gt;&lt;/script&gt;&lt;figure class=&quot;frame has-title&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;SQL&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;sql&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;SELECT&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; message_id, sender_id, payload, created_at&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;FROM&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; messages&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;WHERE&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; conversation_id &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;&apos;conv_12345&apos;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;AND&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; created_at &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; (&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;SELECT&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; cleared_at_timestamp&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;FROM&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; conversation_participants&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;WHERE&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; conversation_id &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;&apos;conv_12345&apos;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;AND&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; user_id &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#A5D6FF&quot;&gt;&apos;user_A&apos;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;ORDER BY&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt; created_at &lt;/span&gt;&lt;span style=&quot;--0:#FF7B72&quot;&gt;ASC&lt;/span&gt;&lt;span style=&quot;--0:#E6EDF3&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;div aria-live=&quot;polite&quot;&gt;&lt;/div&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;SELECT message_id, sender_id, payload, created_atFROM messagesWHERE conversation_id = &amp;#x27;conv_12345&amp;#x27;  AND created_at &gt; (      SELECT cleared_at_timestamp      FROM conversation_participants      WHERE conversation_id = &amp;#x27;conv_12345&amp;#x27; AND user_id = &amp;#x27;user_A&amp;#x27;  )ORDER BY created_at ASC;&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;h3 id=&quot;index-optimization-b-tree-lsm-tree&quot;&gt;Index Optimization (B-Tree / LSM-Tree)&lt;/h3&gt;
&lt;p&gt;টেবিল থেকে কোটি কোটি মেসেজের মধ্যে এই কোয়েরি দ্রুত চালানোর জন্য full table scan এড়ানো অত্যন্ত জরুরি। এর জন্য আমরা &lt;code&gt;(conversation_id, created_at)&lt;/code&gt;-এর ওপর একটি composite index তৈরি করি। যখন কোয়েরিটি ডাটাবেজে হিট করে, তখন database engine তার B-Tree বা LSM-Tree ইনডেক্স ধরে Big-O(log N) time complexity-তে ট্রি ট্রাভার্স করে। ইনডেক্সিং অর্ডারের কারণে &lt;code&gt;cleared_at_timestamp&lt;/code&gt;-এর আগের সব পুরনো মেসেজ মেমোরি লেভেলেই বাইপাস হয়ে যায়, যা query execution-কে করে তোলে আলোর মতো দ্রুতগতিসম্পন্ন।&lt;/p&gt;
&lt;figure&gt;&lt;img src=&quot;https://raw.githubusercontent.com/rafeuddaraj/rafes-blog-assets/refs/heads/messenger-delete-conversation-architecture-deep-dive/assets/timestamp-boundary-query-execution.svg&quot; alt=&quot;Low Level B-Tree Index Traversal with Timestamp Boundary&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;800&quot; height=&quot;450&quot;&gt;&lt;figcaption&gt;Low Level B-Tree Index Traversal with Timestamp Boundary&lt;/figcaption&gt;&lt;/figure&gt;
&lt;hr&gt;
&lt;h2 id=&quot;step-by-step-execution-trace-ও-code-mechanics&quot;&gt;Step-by-Step Execution Trace ও Code Mechanics&lt;/h2&gt;
&lt;p&gt;আপনি যখন অ্যাপের ইন্টারফেসে &quot;Delete Conversation&quot; বাটনে চাপ দেন, তখন আসলে under-the-hood কী ঘটে, চলুন তার একটি step-by-step execution trace দেখে নেওয়া যাক।&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Step 1: User Triggers &quot;Delete Conversation&quot;: ক্লায়েন্ট অ্যাপ্লিকেশন থেকে backend-এর &lt;code&gt;POST /api/v1/conversations/{id}/clear&lt;/code&gt; এন্ডপয়েন্টে একটি রিকোয়েস্ট পাঠানো হয়। এই রিকোয়েস্ট পাওয়ার পর database-এর &lt;code&gt;messages&lt;/code&gt; টেবিলে কোনো হাত দেওয়া হয় না। সিস্টেম কেবল &lt;code&gt;conversation_participants&lt;/code&gt; টেবিলে উক্ত ইউজারের &lt;code&gt;cleared_at_timestamp&lt;/code&gt;-এর ভ্যালু আপডেট করে বর্তমান সময়ের timestamp বসিয়ে দেয়। একই সাথে, দ্রুত read performance নিশ্চিত করতে Redis বা application cache থেকে পুরনো মেটাডাটা evict করা হয়।&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Step 2: The Inbox List Re-render: টাইমস্ট্যাম্প আপডেট হওয়ার সাথে সাথে যখন ইনবক্স রেন্ডার করার জন্য filtered query রান করা হয়, তখন &lt;code&gt;cleared_at_timestamp&lt;/code&gt;-এর চেয়ে বড় কোনো মেসেজ না থাকায় query result count &lt;code&gt;0&lt;/code&gt; আসে। এর ফলে অ্যাপ্লিকেশনের UI থেকে চ্যাট উইন্ডোটি সম্পূর্ণ হাইড হয়ে যায় বা ব্ল্যাংক দেখায়।&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Step 3: New Message Arrival: কিছুক্ষণ পর অপর ইউজার যদি আপনাকে একটি নতুন মেসেজ পাঠায়, তবে সেই নতুন মেসেজটি যথারীতি &lt;code&gt;messages&lt;/code&gt; টেবিলে append হয়। এরপর একটি message broker (যেমন Kafka বা RabbitMQ) হয়ে আপনার ডিভাইসে push notification পাঠানো হয়।&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Step 4: The Re-emergence in Inbox: আপনি যখন অ্যাপটি ওপেন করেন, তখন আবার আমাদের filtered query রান হয়। যেহেতু নতুন মেসেজের &lt;code&gt;created_at&lt;/code&gt; টাইমস্ট্যাম্প আপনার ফিল্টার বাউন্ডারি অর্থাৎ &lt;code&gt;cleared_at_timestamp&lt;/code&gt;-এর চেয়ে বড়, তাই এই মেসেজটি কোয়েরি রেজাল্টে ফেরত আসে। UI সাথে সাথে চ্যাট বক্সটি রি-অ্যাক্টিভেট করে ইউজারকে কেবল নতুন মেসেজটি দেখায়, আর পুরনো সব মেসেজ সেই invisible wall-এর পেছনেই আটকা থেকে যায়।&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;figure&gt;&lt;img src=&quot;https://raw.githubusercontent.com/rafeuddaraj/rafes-blog-assets/refs/heads/messenger-delete-conversation-architecture-deep-dive/assets/timeline-state-transition-flow.svg&quot; alt=&quot;Timeline State Transition Flow After Delete Action&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;800&quot; height=&quot;350&quot;&gt;&lt;figcaption&gt;Timeline State Transition Flow After Delete Action&lt;/figcaption&gt;&lt;/figure&gt;
&lt;div class=&quot;callout&quot; role=&quot;note&quot; data-type=&quot;note&quot;&gt;
&lt;p class=&quot;callout-title&quot;&gt;Important&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Soft Delete vs. Timestamp Boundary&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;প্রতিটি মেসেজে আলাদাভাবে &lt;code&gt;is_deleted&lt;/code&gt; ফ্ল্যাগ বসানো (Soft Delete) একটি অত্যন্ত ধীরগতির এবং ব্যয়বহুল প্রক্রিয়া, কারণ এতে প্রতিটি row আপডেট করতে হয়। এর বদলে একটি সিঙ্গেল &lt;code&gt;cleared_at_timestamp&lt;/code&gt; মেটাডাটা আপডেট করা Big-O(1) time complexity নিশ্চিত করে, যা সিস্টেমের write amplification শূন্যে নামিয়ে আনে।&lt;/p&gt;
&lt;/div&gt;
&lt;hr&gt;
&lt;h2 id=&quot;edge-cases-pitfalls-এবং-architectural-trade-offs&quot;&gt;Edge Cases, Pitfalls এবং Architectural Trade-offs&lt;/h2&gt;
&lt;p&gt;একটি স্কেলাবল আর্কিটেকচার ডিজাইন করার সময় কেবল হ্যাপি পাথ (happy path) চিন্তা করলেই চলে না। extreme production load এবং মেমোরি সীমাবদ্ধতার মধ্যে আমাদের কিছু গুরুত্বপূর্ণ edge cases এবং trade-offs মাথায় রাখতে হয়।&lt;/p&gt;
&lt;h3 id=&quot;a-storage-growth-vs-garbage-collection-gdpr-compliance&quot;&gt;A. Storage Growth vs. Garbage Collection (GDPR Compliance)&lt;/h3&gt;
&lt;p&gt;সমস্যা: আমরা যদি মূল মেসেজগুলো কখনোই ডিলিট না করি এবং অনন্তকাল ধরে ডাটা জমাতে থাকি, তবে storage cost আকাশছোঁয়া হয়ে যাবে। এছাড়া বিভিন্ন দেশের privacy law (যেমন ইউরোপের GDPR compliance) অনুযায়ী ইউজারের ডিলিট করা ডাটা আজীবন রেখে দেওয়া আইনত দণ্ডনীয়।&lt;/p&gt;
&lt;p&gt;সমাধান: এই সমস্যা সমাধানে আমাদের ব্যাকগ্রাউন্ড asynchronous garbage collection (GC) বা cron job চালাতে হয়। এই জবটি নিয়মিত চেক করে, যখন কোনো কনভারসেশনের উভয় ইউজারের &lt;code&gt;cleared_at&lt;/code&gt; টাইমস্ট্যাম্প কোনো নির্দিষ্ট মেসেজের &lt;code&gt;created_at&lt;/code&gt;-এর চেয়ে বড় হয়ে যায় (অর্থাৎ দুজনের কেউই আর মেসেজটি দেখতে চান না), কেবল তখনই সেই মেসেজগুলোকে disk থেকে hard delete করা হয়।&lt;/p&gt;
&lt;div class=&quot;callout&quot; role=&quot;note&quot; data-type=&quot;warning&quot;&gt;
&lt;p class=&quot;callout-title&quot;&gt;Warning&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The Compliance &amp;#x26; Privacy Trap&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;আপনার সিস্টেমে যদি automated data retention policy এবং dual-deletion purge মেকানিজম না থাকে, তবে timestamp-based filtering ব্যবহার করলেও আপনি বড় ধরনের লিগ্যাল রিস্কের মুখে পড়বেন। ইউজারের প্রাইভেসি সুরক্ষায় background GC implement করা বাধ্যতামূলক।&lt;/p&gt;
&lt;/div&gt;
&lt;h3 id=&quot;b-index-bloating-ও-performance-degradation&quot;&gt;B. Index Bloating ও Performance Degradation&lt;/h3&gt;
&lt;p&gt;সমস্যা: লাখ লাখ ডিলিট করা মেসেজ টেবিলে জমতে থাকলে, ইনডেক্স ট্রাভার্স করার সময় database engine-কে প্রচুর মৃত বা invisible node বাইপাস করতে হয়। এর ফলে read latency ধীরে ধীরে বৃদ্ধি পেতে পারে।&lt;/p&gt;
&lt;p&gt;সমাধান: এই performance degradation ঠেকাতে database partitions এবং time-series bucketing ব্যবহার করা হয়। নির্দিষ্ট সময় পার হয়ে যাওয়া পুরনো ডাটাগুলোকে আমরা active index থেকে সরিয়ে cold storage-এ পাঠিয়ে দিই, যাতে গরম বা active index সবসময় ছোট এবং দ্রুতগতির থাকে।&lt;/p&gt;
&lt;h3 id=&quot;c-clock-skew-in-distributed-servers&quot;&gt;C. Clock Skew in Distributed Servers&lt;/h3&gt;
&lt;p&gt;সমস্যা: distributed systems-এ পৃথিবীর বিভিন্ন রিজিয়নে ছড়িয়ে থাকা সার্ভারগুলোর ঘড়ির মধ্যে মিলি-সেকেন্ডের পার্থক্য বা clock skew থাকতে পারে। এর ফলে timestamp mismatch হয়ে race condition তৈরি হতে পারে, যেখানে নতুন মেসেজও ভুলবশত invisible wall-এর পেছনে হাইড হয়ে যেতে পারে।&lt;/p&gt;
&lt;p&gt;সমাধান: এই ধরনের race condition এড়াতে কখনোই লোকাল সার্ভার টাইম ব্যবহার করা যাবে না। এর বদলে database-generated UTC timestamp অথবা Google TrueTime ও Snowflake ID-র মতো centralized monotonically increasing time-source ব্যবহার করতে হবে।&lt;/p&gt;
&lt;div class=&quot;callout&quot; role=&quot;note&quot; data-type=&quot;tip&quot;&gt;
&lt;p class=&quot;callout-title&quot;&gt;Tip&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Query Optimization Pro-Tip&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;ডাটাবেজে composite index তৈরি করার সময় সবসময় Leftmost Prefix Rule মেনে চলুন। আমাদের কোয়েরি প্যাটার্ন অনুযায়ী &lt;code&gt;(conversation_id, created_at)&lt;/code&gt; ইনডেক্সে &lt;code&gt;conversation_id&lt;/code&gt;-কে অবশ্যই আগে রাখতে হবে এবং &lt;code&gt;created_at&lt;/code&gt;-কে পরে রাখতে হবে। এতে করে ডাটাবেজ প্রথমে সঠিক চ্যাট থ্রেডটি আইসোলেট করে, তারপর টাইমস্ট্যাম্প বাউন্ডারি ফিল্টার করে।&lt;/p&gt;
&lt;/div&gt;
&lt;hr&gt;
&lt;h2 id=&quot;summary-এবং-production-decision-rules&quot;&gt;Summary এবং Production Decision Rules&lt;/h2&gt;
&lt;p&gt;পুরো Deep Dive থেকে আমাদের কোর লেসন হলো: স্কেলাবল সিস্টেম তৈরিতে ব্রুট-ফোর্স ডাটাবেজ অপারেশনের বদলে সবসময় স্মার্ট মেটাডাটা এবং কোয়েরি বাউন্ডারি ব্যবহার করতে হবে। আপনি যখন আপনার পরবর্তী প্রজেক্টের আর্কিটেকচার ডিজাইন করবেন, তখন নিচের production decision matrix-টি গাইডলাইন হিসেবে ব্যবহার করতে পারেন:&lt;/p&gt;
&lt;section class=&quot;table-wrap&quot; tabindex=&quot;0&quot; aria-label=&quot;Table 1&quot;&gt;
























&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th class=&quot;align-left&quot;&gt;আর্কিটেকচারাল মডেল&lt;/th&gt;&lt;th class=&quot;align-left&quot;&gt;কখন ব্যবহার করবেন?&lt;/th&gt;&lt;th class=&quot;align-left&quot;&gt;মূল সুবিধা ও অসুবিধা (Trade-offs)&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;align-left&quot;&gt;&lt;strong&gt;Duplicated Data Model&lt;/strong&gt;&lt;/td&gt;&lt;td class=&quot;align-left&quot;&gt;ছোট স্কেলের অ্যাপ্লিকেশন অথবা যেখানে সম্পূর্ণ আইসোলেটেড E2E (End-to-End) এনক্রিপশন প্রয়োজন।&lt;/td&gt;&lt;td class=&quot;align-left&quot;&gt;প্রতি ইউজারের সম্পূর্ণ ডাটা কন্ট্রোল থাকে, কিন্তু write amplification এবং storage cost অত্যন্ত বেশি।&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class=&quot;align-left&quot;&gt;&lt;strong&gt;Row-Level Soft Delete&lt;/strong&gt;&lt;/td&gt;&lt;td class=&quot;align-left&quot;&gt;যখন ইউজার কোনো নির্দিষ্ট সিঙ্গেল মেসেজ ডিলিট (যেমন: Unsend বা Delete for everyone) করতে চায়।&lt;/td&gt;&lt;td class=&quot;align-left&quot;&gt;নির্দিষ্ট মেসেজ টার্গেট করা সহজ, কিন্তু পুরো চ্যাট ক্লিয়ার করার ক্ষেত্রে এটি database-এর ওপর প্রচণ্ড চাপ তৈরি করে।&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class=&quot;align-left&quot;&gt;&lt;strong&gt;Timestamp-Based View Filtering&lt;/strong&gt;&lt;/td&gt;&lt;td class=&quot;align-left&quot;&gt;যখন ইউজার পুরো চ্যাট থ্রেড বা ইনবক্স ফিড এক ক্লিকে ক্লিয়ার করতে চায়।&lt;/td&gt;&lt;td class=&quot;align-left&quot;&gt;Zero write amplification এবং Big-O(1) complexity নিশ্চিত করে। তবে ব্যাকগ্রাউন্ডে garbage collection এবং timestamp synchronicity পরিচালনা করতে হয়।&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/section&gt;
&lt;p&gt;আশা করি, এখন থেকে আপনি যখনই কোনো high-throughput অ্যাপ্লিকেশনের ডাটাবেজ বা চ্যাট সিস্টেম ডিজাইন করবেন, তখন এই timestamp-based bounded filtering লজিকটি আপনার সিস্টেমকে আরও নির্ভুল এবং পারফরম্যান্ট করতে সাহায্য করবে। হ্যাপি কোডিং!&lt;/p&gt;</content:encoded><category>System Design</category><category>Deep Dive</category><category>Under the hood</category><category>Architecture</category><category>Distributed Systems</category><category>Database Design</category><category>Big-O</category><category>Scalability</category><category>Backend Engineering</category></item></channel></rss>