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

Event Sourcing: event log থেকে state ও replay

Event Sourcing, Replay, and Schema Evolution

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

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

  • Event log-কে source of truth হিসেবে দেখুন
  • Replay ও snapshot-এর ভূমিকা বুঝুন
  • Schema evolution এবং side effect আলাদা করুন

সমস্যা দিয়ে শুরু

Wallet-এর balance ৫০০ টাকা কমল, কিন্তু current row দেখে কেন কমেছে বোঝা যাচ্ছে না। Audit log অসম্পূর্ণ। Team প্রতিটি business change authoritative history হিসেবে রাখতে চায়, যাতে balance আবার হিসাব করা ও পুরোনো সিদ্ধান্ত বোঝা যায়।

সহজ করে বুঝি

Event sourcing-এ state-এর বদলে ordered immutable domain events authoritative থাকে। বর্তমান state events fold করে পাওয়া যায়। Snapshot replay দ্রুত করার derived checkpoint, মূল history-এর বিকল্প নয়। শুধু logs লেখা বা event bus ব্যবহার করা event sourcing নয়।

পরিচিত একটি উপমা

ব্যাংকের খাতায় জমা ও উত্তোলনের entry থেকে balance বের হয়। শুধু শেষ balance লিখলে history হারায়। ভুল entry কাটাকাটি না করে corrective entry দিলে audit থাকে। Software event-এও অর্থ ও version স্থায়ীভাবে বোঝা জরুরি।

নকশাটি দেখুন

Diagram লোড হচ্ছে…

Event log-কে source of truth হিসেবে দেখুন
Diagram-এর text flow দেখুন
flowchart LR
 C[Command and Expected Version] --> E[(Append Event Stream)]
 E --> F[Fold Events]
 F --> S[Current Balance]
 E --> P[Read Projection]
 E --> N[Snapshot Cache]

Command expected version দিয়ে append করে; concurrent append conflict হলে সিদ্ধান্ত আবার যাচাই হয়। Fold একই ordered events থেকে state বানায়। Projection query shape দেয়। Snapshot version থেকে বাকি events replay করে দ্রুত state পাওয়া যায়। Replay-এ পুরোনো email বা charge আবার পাঠানো যাবে না।

PHP ও Laravel-এ প্রয়োগ

PHP fold function-এর fragment; amount integer minor units, events versioned এবং validated। Laravel repository append-এর সময় aggregate_id,sequence unique constraint রাখবে। এই function শুধু deterministic state rebuild করে; external side effect ইচ্ছাকৃতভাবে নেই।

php
function rebuildBalance(array $events): int
{
    $balance = 0;
    foreach ($events as $event) {
        $amount = $event['amount_minor'];
        $balance = match ($event['type']) {
            'WalletCredited.v1' => $balance + $amount,
            'WalletDebited.v1' => $balance - $amount,
            default => throw new RuntimeException('Unknown event version'),
        };
    }
    return $balance;
}

$balance = rebuildBalance([
    ['type' => 'WalletCredited.v1', 'amount_minor' => 10000],
    ['type' => 'WalletDebited.v1', 'amount_minor' => 2500],
]);

এটি PHP 8.3+ ও Laravel 12-এর শিক্ষামূলক fragment; সম্পূর্ণ application নয়। সংশ্লিষ্ট route-এ authentication ও resource authorization প্রয়োগ করতে হবে। নিচের অনুশীলনে failure ইচ্ছা করে তৈরি করুন; শুধু সফল response দেখে correctness ধরে নেবেন না।

সুবিধা, সীমাবদ্ধতা ও trade-off

Auditability, temporal debugging ও new projection শক্তিশালী হয়। কিন্তু event schema দীর্ঘমেয়াদি contract, personal data deletion কঠিন এবং migration strategy লাগে। অধিকাংশ CRUD app-এর জন্য অতিরিক্ত complexity; সত্যিকারের history requirement ছাড়া ব্যবহার নয়।

সাধারণ ভুল

  • Replay চলাকালে email বা payment আবার পাঠানো।
  • পুরোনো events-এর অর্থ বদলে নতুন code চালানো।
  • Snapshot-কে source of truth বানিয়ে original history মুছে ফেলা।

আরও একটু গভীরে

Upcaster পুরোনো schema read করার সময় নতুন representation দেয়; historical meaning মুছতে পারে না। Optimistic concurrency expected sequence দিয়ে conflicting command detect করে। Event append success ও downstream publish-এর মধ্যে outbox-style ব্যবস্থা এখনও দরকার।

একই history দুইবার fold করে একই balance চাই। Unknown event version-এ নীরব skip না করে failure দেখুন। Snapshot version 50 থেকে বাকি history replay করে full replay-এর ফল মিলান। Replay run-এ external side effect counter শূন্য থাকা চাই।

মনে রাখুন

  • Immutable event history authoritative।
  • Replay deterministic ও side-effect-free।
  • Versioning lifetime commitment।

নিজে চেষ্টা করুন

OrderPlaced, ItemAdded ও OrderCancelled events দিয়ে order rebuild-এর rule লিখুন। Cancelled order-এ পরে ItemAdded command এলে কী হবে ব্যাখ্যা করুন।

নিজের বোঝা যাচাই করুন

1. Audit log থাকলেই?

না। Event history-ই authoritative state source হলে event sourcing; secondary logging আলাদা।

2. Snapshot কেন?

লম্বা replay দ্রুত করতে; corresponding version ও remaining events দিয়ে state মেলে।

3. Replay email পাঠাবে?

না। Rebuild state এবং live side effect-এর path আলাদা রাখতে হয়।

4. পুরোনো schema?

Version-aware reader বা upcaster দরকার; নীরবে ignore করলে state ভুল হবে।

5. Concurrent command?

Expected version ও unique sequence constraint conflict detect করে; পরে business rules আবার যাচাই করতে হয়।

আরও পড়ুন

এই পাঠের কুইজ

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

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

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

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

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