Let’s walk through a simple example of a choreography pattern using a hypothetical e-commerce system. We’ll use a combination of Python classes to simulate microservices and their event-driven interactions.
Scenario
In this example, we’ll have four services:
- OrderService: Manages customer orders.
- InventoryService: Checks and updates product inventory.
- PaymentService: Processes payments.
- ShippingService: Arranges shipping for the order.
Each service will emit and listen to specific events to perform its tasks. We’ll use a simple event bus to simulate the event-driven communication.
Implementation
Event Bus
First, we need an event bus to handle event subscriptions and publishing.
class EventBus:
def __init__(self):
self.subscribers = {}
def subscribe(self, event_type, handler):
if event_type not in self.subscribers:
self.subscribers[event_type] = []
self.subscribers[event_type].append(handler)
def publish(self, event_type, data):
if event_type in self.subscribers:
for handler in self.subscribers[event_type]:
handler(data)
event_bus = EventBus()
Services
Next, we implement the services, each with its own event handling methods.
class OrderService:
def __init__(self, event_bus):
self.event_bus = event_bus
self.event_bus.subscribe("OrderCreated", self.handle_order_created)
def create_order(self, order_data):
print(f"OrderService: Creating order {order_data['order_id']}")
self.event_bus.publish("OrderCreated", order_data)
def handle_order_created(self, order_data):
print(f"OrderService: Order {order_data['order_id']} created")
class InventoryService:
def __init__(self, event_bus):
self.event_bus = event_bus
self.event_bus.subscribe("OrderCreated", self.handle_order_created)
self.event_bus.subscribe("InventoryChecked", self.handle_inventory_checked)
def handle_order_created(self, order_data):
print(f"InventoryService: Checking inventory for order {order_data['order_id']}")
self.event_bus.publish("InventoryChecked", order_data)
def handle_inventory_checked(self, order_data):
print(f"InventoryService: Inventory checked for order {order_data['order_id']}")
class PaymentService:
def __init__(self, event_bus):
self.event_bus = event_bus
self.event_bus.subscribe("InventoryChecked", self.handle_inventory_checked)
self.event_bus.subscribe("PaymentProcessed", self.handle_payment_processed)
def handle_inventory_checked(self, order_data):
print(f"PaymentService: Processing payment for order {order_data['order_id']}")
self.event_bus.publish("PaymentProcessed", order_data)
def handle_payment_processed(self, order_data):
print(f"PaymentService: Payment processed for order {order_data['order_id']}")
class ShippingService:
def __init__(self, event_bus):
self.event_bus = event_bus
self.event_bus.subscribe("PaymentProcessed", self.handle_payment_processed)
self.event_bus.subscribe("ShippingArranged", self.handle_shipping_arranged)
def handle_payment_processed(self, order_data):
print(f"ShippingService: Arranging shipping for order {order_data['order_id']}")
self.event_bus.publish("ShippingArranged", order_data)
def handle_shipping_arranged(self, order_data):
print(f"ShippingService: Shipping arranged for order {order_data['order_id']}")
Running the Choreography
Now we create instances of the services and simulate placing an order.
# Instantiate services
order_service = OrderService(event_bus)
inventory_service = InventoryService(event_bus)
payment_service = PaymentService(event_bus)
shipping_service = ShippingService(event_bus)
# Simulate placing an order
order_data = {"order_id": 1, "product_id": 101, "quantity": 2}
order_service.create_order(order_data)
Output
When you run the above code, you should see the following output, showing the flow of events and how each service reacts:
OrderService: Creating order 1
OrderService: Order 1 created
InventoryService: Checking inventory for order 1
InventoryService: Inventory checked for order 1
PaymentService: Processing payment for order 1
PaymentService: Payment processed for order 1
ShippingService: Arranging shipping for order 1
ShippingService: Shipping arranged for order 1
This example illustrates the choreography model, where each service listens for specific events, processes them, and potentially triggers new events, all without a central coordinator.