Introduction
Proto.Actor provides a powerful feature called EventStream, which acts as a multi-channel publisher/subscriber dispatcher. This article explores how to use this mechanism to implement event-driven communication between actors.  
Event Stream
The EventStream enables a publish/subscribe pattern in Proto.Actor, allowing actors (identified by their Process ID, or PID) to subscribe to specific event types. It also serves as a critical component for managing infrastructure events like undelivered messages (e.g., DeadLetter handling).  
Requirements
- .NET 8+
- NuGet packages:
Actors
For this example, we implement two actors to demonstrate event-driven interaction.
OrderActor
The OrderActor creates orders and publishes an OrderCreated event via the EventStream:
public class OrderActor : IActor
{
    private readonly List<Order> _orders = [];
    public Task ReceiveAsync(IContext context)
    {
        if (context.Message is CreateOrder createOrder)
        {
            var order = new Order(createOrder.Id, createOrder.Amount);
            _orders.Add(order);
            context.Respond(order);
            // Publish event to the EventStream
            context.System.EventStream.Publish(new OrderCreated(order)); // 
        }
        else if (context.Message is AllOrder)
        {
            context.Respond(_orders.ToList());
        }
        return Task.CompletedTask;
    }
}
PaymentActor
The PaymentActor subscribes to OrderCreated events and maintains a list of orders awaiting payment:
public class PaymentActor : IActor
{
    private List<Order> _waitingForPayment = [];
    public Task ReceiveAsync(IContext context)
    {
        if (context.Message is OrderCreated orderCreated)
        {
            _waitingForPayment.Add(orderCreated.Order); // React to event
        }
        else if (context.Message is OrderPaid orderPaid)
        {
            _waitingForPayment.RemoveAll(x => x.Id == orderPaid.Id);
        }
        else if (context.Message is IsWaitingForPayment isWaitingForPayment)
        {
            context.Respond(_waitingForPayment.Any(x => x.Id == isWaitingForPayment.Id));
        }
        return Task.CompletedTask;
    }
}
Subscription to an Event
To subscribe an actor to an event:
- Spawn the actor using the actor system.
- Use EventStream.Subscribe<T>()to register the actor for a specific event type:
// Creating actors
var actorOrder = system.Root.Spawn(Props.FromProducer(() => new OrderActor()));
var actorPayment = system.Root.Spawn(Props.FromProducer(() => new PaymentActor()));
// Subscribing to OrderCreated events
system.EventStream.Subscribe<OrderCreated>(system.Root, actorPayment); // 
Key Concepts
- EventStream Lifecycle: Events are published to all subscribers, and subscriptions persist until explicitly unsubscribed.
- 
DeadLetter Handling: The EventStreamalso queues undelivered messages (e.g., when sending to a terminated actor).
Conclusion
Proto.Actor's EventStream simplifies event-driven architectures by decoupling actors through a robust pub/sub mechanism. This pattern is ideal for scenarios like event sourcing, monitoring, or cross-cutting concerns (e.g., logging).  
 
 
              

 
    
Top comments (0)