পাঠ্যক্রম খুলুন
মধ্যবর্তী পর্যায়

Distributed Transaction: 2PC, Saga ও compensation

Two-Phase Commit and Saga

এই পাঠের কুইজ ↓৫ মিনিট পড়াPHP 8.3+ · Laravel 12
এই পাঠের সূচিপত্র

এই পাঠে যা শিখবেন

  • 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 লোড হচ্ছে…

Local ও distributed transaction আলাদা করুন
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 ধরে করে দেখানো হয়নি।

php
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 যথেষ্ট নয়।

আরও পড়ুন

এই পাঠের কুইজ

এই পাঠ থেকে ২টি প্রশ্ন। উত্তর দিয়ে ব্যাখ্যা দেখুন; অধ্যায়ের কুইজ আলাদাভাবে দিতে হবে।

এই পাঠের ২টি প্রশ্নের উত্তর দিন। পাস করতে দুটিই সঠিক হতে হবে।

জমা দেওয়ার পর সঠিক উত্তর ও ব্যাখ্যা দেখবেন। ফলাফল এই ব্রাউজারে সংরক্ষিত থাকবে। অনুশীলনের ফল অধ্যায় সম্পন্নের হিসাবে যোগ হয় না।

সব বিষয় মিলিয়ে অনুশীলন করুন →

অগ্রগতি এই ব্রাউজারে সংরক্ষিত থাকে। শুধু পাঠ খুললে সম্পন্ন হয় না।