Hi devs,
Microservices architecture is all about breaking down systems into smaller, autonomous services that work together. But here’s the catch: how do these services coordinate their work? That’s where Choreography, Orchestration, and even the Event Broker pattern come into play.
These are different ways to manage workflows between services. Choosing the right one isn’t just about technical preferences—it’s about how your system evolves, scales, and handles complexity. Let’s break it down with examples in C# and explore how Event Brokers can improve Choreography.
Choreography: Let Services Dance Together
Choreography is like a dance. Each service knows its part and responds to events independently. There’s no central controller dictating the steps—it’s all about reacting to what’s happening around you.
This approach shines when services need to stay loosely coupled and adaptable.
Real-Life Example: Employee Onboarding
Let’s say you’re building an HR system to onboard new employees. You might have these services:
- Employee Service: Registers the new hire.
- IT Service: Sets up email accounts and devices.
- Payroll Service: Prepares salary details.
Here’s how they might communicate through events:
Step 1: Employee Service Registers a New Hire
public class EmployeeService
{
private readonly IEventBus _eventBus;
public EmployeeService(IEventBus eventBus)
{
_eventBus = eventBus;
}
public void RegisterEmployee(string employeeId, string name)
{
Console.WriteLine("Employee registered!");
_eventBus.Publish(new EmployeeRegisteredEvent { EmployeeId = employeeId, Name = name });
}
}
Step 2: IT Service Listens to the Event and Sets Up an Account
public class ITService
{
public void HandleEmployeeRegistered(EmployeeRegisteredEvent eventData)
{
Console.WriteLine($"Setting up IT account for {eventData.Name}...");
}
}
Step 3: Payroll Service Prepares the Employee’s Payroll
public class PayrollService
{
public void HandleEmployeeRegistered(EmployeeRegisteredEvent eventData)
{
Console.WriteLine($"Preparing payroll for {eventData.Name}...");
}
}
Adding an Event Broker to Choreography
While pure Choreography allows services to react to each other's events directly, this can become messy and hard to manage in complex systems. That’s where an Event Broker improves the model.
An Event Broker acts as a mediator between services, ensuring events are distributed reliably without services directly depending on one another.
Benefits of Event Brokers in Choreography:
- Decoupling: Services don’t need to know about each other.
- Scalability: The broker handles large volumes of events efficiently.
- Resilience: Supports retries and failure handling.
- Monitoring: Centralized logging and tracking of events.
Example with Azure Service Bus
Instead of services directly listening to events, the Event Broker becomes the communication hub.
- Employee Service publishes an event:
public class EventBroker
{
private readonly ITopicClient _topicClient;
public EventBroker(ITopicClient topicClient)
{
_topicClient = topicClient;
}
public async Task PublishAsync<T>(T eventMessage) where T : class
{
var message = new Message(Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(eventMessage)));
await _topicClient.SendAsync(message);
Console.WriteLine($"Event published: {typeof(T).Name}");
}
}
- Other services subscribe to these events via the broker:
public async Task SubscribeToEmployeeEvents(string subscriptionName, Action<Message> processMessage)
{
var subscriptionClient = new SubscriptionClient("ServiceBusConnectionString", subscriptionName);
subscriptionClient.RegisterMessageHandler(async (message, token) =>
{
processMessage(message);
await subscriptionClient.CompleteAsync(message.SystemProperties.LockToken);
});
}
In this model, the IT Service and Payroll Service are subscribers to the Event Broker, and the broker ensures events are reliably delivered without direct service-to-service communication.
Orchestration: A Conductor Directs the Workflow
Now imagine a conductor leading an orchestra. That’s what Orchestration is all about—a single service controls the entire workflow, calling each service in turn.
This approach works well for processes that require strict order and visibility.
Orchestrator Example
public class OnboardingOrchestrator
{
private readonly IEmployeeService _employeeService;
private readonly IITService _itService;
private readonly IPayrollService _payrollService;
public OnboardingOrchestrator(
IEmployeeService employeeService,
IITService itService,
IPayrollService payrollService)
{
_employeeService = employeeService;
_itService = itService;
_payrollService = payrollService;
}
public async Task OnboardEmployeeAsync(string employeeId, string name)
{
Console.WriteLine("Starting onboarding...");
await _employeeService.RegisterEmployeeAsync(employeeId, name);
await _itService.CreateAccountAsync(employeeId);
await _payrollService.SetupPayrollAsync(employeeId);
Console.WriteLine("Onboarding complete!");
}
}
Comparing the Patterns
Feature | Choreography | Orchestration | Event Broker |
---|---|---|---|
Control | Decentralized | Centralized | Centralized Event Distribution |
Coupling | Loose | Tight | Loose |
Scalability | High | Limited by orchestrator bottlenecks | High with reliable brokers |
Error Handling | Complex and distributed | Centralized and simpler | Managed by broker |
Visibility | Hard to trace | Full control | Improved logging and traceability |
Final Thoughts
Microservices are all about choosing the right tool for the job. While Choreography offers loose coupling, adding an Event Broker helps keep the system manageable and robust. Orchestration, on the other hand, is ideal when you need centralized control and strict workflows.
Keep coding
Top comments (0)