Distributed Transaction: 2PC, Saga ও compensation
Two-Phase Commit and Saga
এই পাঠের সূচিপত্র
এই পাঠে যা শিখবেন
- Local ও distributed transaction আলাদা করুন
- Saga compensation-এর অর্থ বুঝুন
- Pending state ও recovery design করুন
সমস্যা দিয়ে শুরু
Order service stock reserve করল, payment service charge করল, কিন্তু shipping booking ব্যর্থ হলো। তিন service-এর আলাদা database। একটি Laravel DB transaction দিয়ে সব rollback করা যায় না। Customer-এর order এখন কোন অবস্থায় আছে, তা durable workflow-এ রাখতে হবে।
সহজ করে বুঝি
Two-phase commit participant-গুলোকে prepare করিয়ে coordinator decision অনুযায়ী commit বা abort করায়; blocking ও operational complexity থাকে। Saga local transaction-এর sequence, failure হলে compensating action চালায়। Compensation আগের history মুছে দেয় না: refund হলো নতুন financial action, charge ঘটেনি এমন নয়।
পরিচিত একটি উপমা
ভ্রমণে আলাদা hotel ও train বুকিং করেন। Train না পেলে hotel cancellation করেন; cancellation fee থাকতে পারে। এক দোকানের receipt ছিঁড়লেই অন্য দোকানের টাকা ফেরে না। প্রতিটি booking ও cancellation-এর নিজস্ব পরিচয় ও ফল থাকে।
নকশাটি দেখুন
Diagram লোড হচ্ছে…
Diagram-এর text flow দেখুন
flowchart LR O[Order pending] --> S[Reserve stock] S --> P[Charge payment] P --> H[Book shipment] H --> D[Order confirmed] H -.-> F[Refund payment] F --> R[Release stock] R --> C[Order compensated]
সফল path stock, payment ও shipping অতিক্রম করে। Shipping ব্যর্থ হলে refund এবং stock release-এর compensating path চলে। Refund নিজেও ব্যর্থ হতে পারে; workflow তখন compensated দাবি না করে compensation_pending রাখে এবং retry বা manual review করে।
PHP ও Laravel-এ প্রয়োগ
Laravel service fragment-এ order_sagas row durable orchestration state ধরে। এটি একটি step-এর claim, সম্পূর্ণ saga engine নয়। Payment API-তে same saga-derived idempotency key লাগবে; remote HTTP call transaction-এর row lock ধরে করে দেখানো হয়নি।
use Illuminate\Support\Facades\DB;
$claimed = DB::table('order_sagas')
->where('id', $sagaId)
->where('state', 'stock_reserved')
->update([
'state' => 'payment_requested',
'updated_at' => now(),
]);
if ($claimed === 1) {
logger()->info('saga.payment_requested', [
'saga_id' => $sagaId,
'idempotency_key' => 'saga:'.$sagaId.':charge',
]);
}
// A durable outbox must atomically accompany this transition.
// A reconciler resumes payment_requested states after a crash.এটি PHP 8.3+ ও Laravel 12-এর শিক্ষামূলক fragment; সম্পূর্ণ application নয়। সংশ্লিষ্ট route-এ authentication ও resource authorization প্রয়োগ করতে হবে। নিচের অনুশীলনে failure ইচ্ছা করে তৈরি করুন; শুধু সফল response দেখে correctness ধরে নেবেন না।
সুবিধা, সীমাবদ্ধতা ও trade-off
Saga service autonomy ও দীর্ঘ workflow সামলায়, কিন্তু intermediate state দৃশ্যমান এবং compensation অসম্পূর্ণ হতে পারে। 2PC atomic decision শক্তিশালী করলেও participant support, coordinator recovery ও held resources লাগে। ছোট local transaction সম্ভব হলে সেটিই সহজ।
সাধারণ ভুল
- Compensation-কে database rollback-এর সমান বলা।
- Workflow state শুধু queue payload-এ রাখা।
- Refund ব্যর্থ হলেও order cancelled ও fully refunded দেখানো।
আরও একটু গভীরে
Orchestration একটি coordinator-এ steps রাখে; choreography events দিয়ে coordination করে। প্রথমটি flow দেখা সহজ করে, দ্বিতীয়টি coupling ছড়িয়ে দিতে পারে। উভয় ক্ষেত্রেই step idempotency, timeout, retries ও stuck-state monitoring দরকার।
Payment success-এর পরে shipping failure inject করুন। Refund request timeout হলে saga কোন state-এ থাকবে নির্ধারণ করুন। Duplicate callback ও repeated compensation-এ একবার refund চাই। Reconciler যেন provider-এর সত্য দেখে workflow এগোয়; local timeout দিয়ে charge বাতিল ধরে না।
মনে রাখুন
- Service boundary পেরোলেই local atomicity শেষ।
- Compensation নতুন business action।
- Saga progress durable রাখুন।
নিজে চেষ্টা করুন
Order saga-এর state table বানান: current state, event, next state ও compensation। Refund pending-এর customer message-ও লিখুন।
নিজের বোঝা যাচাই করুন
1. DB transaction সব service ঢাকে?
না। সাধারণ Laravel transaction নিজের connection-এর database scope-এ সীমিত।
2. Saga atomic rollback?
না। Intermediate effect থাকে এবং compensation সব সময় আগের বাস্তব অবস্থা ফিরিয়ে দিতে পারে না।
3. Refund কেন idempotent?
Compensation retry ও duplicate event-এ একই customer-কে বারবার টাকা ফেরানো ঠেকাতে।
4. 2PC-এর খরচ?
Prepared participant resources ধরে রাখতে পারে এবং coordinator failure-এ recovery জটিল হয়।
5. Stuck saga কীভাবে?
Durable state age monitor, deadline এবং provider reconciliation দিয়ে; শুধু worker restart যথেষ্ট নয়।
আরও পড়ুন
এই পাঠের কুইজ
এই পাঠ থেকে ২টি প্রশ্ন। উত্তর দিয়ে ব্যাখ্যা দেখুন; অধ্যায়ের কুইজ আলাদাভাবে দিতে হবে।
এই পাঠের ২টি প্রশ্নের উত্তর দিন। পাস করতে দুটিই সঠিক হতে হবে।
জমা দেওয়ার পর সঠিক উত্তর ও ব্যাখ্যা দেখবেন। ফলাফল এই ব্রাউজারে সংরক্ষিত থাকবে। অনুশীলনের ফল অধ্যায় সম্পন্নের হিসাবে যোগ হয় না।
অগ্রগতি এই ব্রাউজারে সংরক্ষিত থাকে। শুধু পাঠ খুললে সম্পন্ন হয় না।