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

Event-Driven Architecture: event ও versioned contract

Event-Driven Architecture and Contracts

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

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

  • Command ও event-এর ভাষা আলাদা করুন
  • Versioned event contract লিখুন
  • Hidden coupling এবং eventual behavior দেখুন

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

Order service payment, shipping ও email API সরাসরি ডাকে। একটি নতুন loyalty service যোগ করতে order deploy করতে হচ্ছে। Dependency down হলে checkout আটকে যায়। Event ব্যবহার করতে গিয়ে আবার সবাই database table-এর ভেতরের column name-এর উপর নির্ভর করছে।

সহজ করে বুঝি

Event-driven architecture-এ ঘটেছে এমন fact প্রকাশ করা হয় এবং interested consumer নিজের কাজ করে। Command নির্দিষ্ট কাজের অনুরোধ; event অতীতের তথ্য। Stable event contract implementation details থেকে আলাদা হওয়া দরকার। Asynchronous flow coupling মুছে দেয় না; timing ও schema coupling অন্যভাবে আসে।

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

দোকান “বিক্রি সম্পন্ন” notice দেয়; হিসাবরক্ষক commission গোনেন, warehouse packing শুরু করে। Notice-এ হিসাবরক্ষককে কীভাবে spreadsheet সাজাতে হবে বলা হয় না। তবে বিক্রির অর্থ বা পরিচয় বদলালে সবার interpretation বদলে যেতে পারে।

নকশাটি দেখুন

Diagram লোড হচ্ছে…

Command ও event-এর ভাষা আলাদা করুন
Diagram-এর text flow দেখুন
flowchart LR
 O[Order Aggregate] --> E[OrderPaid v1]
 E --> W[Warehouse]
 E --> L[Loyalty]
 E --> A[Audit]
 W --> S[Shipment state]

Order aggregate নিজের সত্য থেকে fact তৈরি করে। Consumer নিজেদের state বদলায়, publisher-এর private schema query করার প্রয়োজন কমে। Warehouse failure loyalty থামায় না। Audit consumer একই event identity ধরে রাখে। Shipping complete event আবার নতুন fact হতে পারে।

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

Laravel event envelope তৈরির fragment। এটি publish transport নয়; outbox-এ atomic insert করে relay করা উত্তম। Amount minor units, currency explicit এবং occurred_at UTC রাখুন। Full Eloquent model serialize করলে অনিচ্ছাকৃত private field leak হতে পারে।

php
use Illuminate\Support\Str;

$event = [
    'id' => (string) Str::uuid(),
    'type' => 'commerce.order.paid',
    'version' => 1,
    'occurred_at' => now()->utc()->toIso8601String(),
    'subject' => 'orders/'.$order->id,
    'data' => [
        'order_id' => $order->id,
        'tenant_id' => $order->tenant_id,
        'amount_minor' => $order->total_minor,
        'currency' => 'BDT',
    ],
];
$payload = json_encode($event, JSON_THROW_ON_ERROR);

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

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

নতুন consumer publisher বদল ছাড়া যোগ করা যায়। কিন্তু end-to-end flow বুঝতে tracing ও contract registry দরকার। Immediate consistency চাইলে user-facing response শুধু event publish success-এর উপর নির্ভর করতে পারে না। Simple local operation-এ direct call পরিষ্কার হতে পারে।

সাধারণ ভুল

  • Event নামে send_email command লুকানো।
  • Consumer-কে producer database join করতে বাধ্য করা।
  • Breaking field change একই version-এ নীরবে চালু করা।

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

Schema compatibility syntax-এর চেয়ে বেশি: amount-এর unit বদলালে JSON number আগের মতো থাকলেও অর্থ ভাঙে। Additive optional field সাধারণত সহজ; required field rename migration চায়। Consumer-driven contract test known payload দিয়ে expected behavior যাচাই করতে পারে।

এক consumer পুরোনো version পড়ছে ধরে envelope-এ optional field যোগ করুন। তা যেন ভাঙে না দেখুন। তারপর currency unit বদলে কী silent error হয় লিখুন। Version migration-এ dual publishing করলে duplicate identity এবং double counting-এর policy লাগবে।

মনে রাখুন

  • Event fact, command অনুরোধ।
  • Public contract private schema নয়।
  • Asynchronous coupling দৃশ্যমান করুন।

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

OrderPaid contract-এ প্রয়োজনীয় ন্যূনতম field লিখুন। কোন personal data বাদ দেবেন এবং consumer missing field পেলে কী করবে জানান।

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

1. Event কী?

একটি ঘটেছে এমন business fact; consumer-এর কাজ করার নির্দেশের সমার্থক নয়।

2. Model পাঠালে সমস্যা?

Private fields, framework serialization এবং schema coupling বাড়ে; explicit payload বেশি নিয়ন্ত্রিত।

3. Publish হলেই workflow শেষ?

না। Consumer পরে চলে এবং ব্যর্থ হতে পারে; progress আলাদা দেখা দরকার।

4. Version কখন?

Meaning বা compatibility বদলালে migration contract দরকার; শুধু field count দেখে নয়।

5. সবকিছু event?

দরকার নেই। Simple synchronous invariant direct local call-এ পরিষ্কার হতে পারে।

আরও পড়ুন

এই পাঠের কুইজ

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

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

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

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

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