19
votes

I'm working on an Azure Service Fabric application here where I have certain actors that need to receive pings/hooks from other services on demand. The application is a sort of event distribution engine that is intended to work something like this:

  • An event router actor that can take an event in and then take care of distributing that event to all subscribers of that event type.
  • 0..N event subscription actors that somehow need to inform the router what type of events they wish to subscribe to and how they want them delivered (sync or async).
  • When the event router actor receives an event of the type MyEvent, it will identify what subscribers are listening and how they want the event delivered. For asynchronous delivery, a message will be popped in an Azure Service Bus topic. For synchronous delivery though, the router actor will invoke the subscription method on the subscribing actors directly, awaiting their response.

Most of this is fairly straight forward, but I'm not entirely sure how I'm going to pull off synchronous delivery of these events. I don't want the event router actor to in any way be aware of any internals in the actors subscribing to events - yet with the current ActorProxy implementations and similar, having access to the interfaces are required to invoke methods on other actors.

Say I subscribe to an event type, informing the event router that my address is fabric:/MyApp/MyEventSubscriberActor and that I want to subscribe to MyEvent. Is there any sensible way within the Service Fabric APIs I can programatically invoke a method on that actor without (for instance OnEventAsync(MyEvent ev) using the ActorProxy.Create<IMyEventSubscriberActor>() method? The source code of these APIs doesn't seem to be publicly available, so I have no direct way of checking how this is done under the hood.

1
I'm little curious on why you want to do both synchronous and asynchronous unless some events wanted to be routed to a different application which you want to send to the Azure Service Bus Topic. The other observation I have is, making a pub/sub won't help you with scalability because the router actor is blocked until subscriber actor completes the task. Have you thought about the "fire and forget" where the subscriber actors pick the events from a ReliableQueue.wonderful world
Actually I have been thinking a little about this myself; i think i'll be fine with just doing synchronous event delivery a cross the board and then have the subscriber itself determine if it should process the event immediately or just pop it on a ReliableQueue for async processing. Thanks for the input.Trond Nordheim
I think with a fire and forget asynchronous method, you may be able to process more events compared to processing the synchronous way.wonderful world

1 Answers

28
votes

The event subscription actor can implement an event subscription interface that contains an "event-available" method. It can pass that interface to an "subscribe-to-event" method on the event router actor interface.

The event router actor interface can keep a reference to the subscription interface as part of its state. When the event of interest to the subscriber occurs, it can call the "event-available" method on the interface that it received and saved earlier. All of this can be done without explicitly creating an actor proxy to communicate with the event subscription actor (the actors serialization infrastructure does this under the hood).

Here's a very basic example that omits the event type, assumes just one subscriber etc., but should give you an idea of the technique.

Interfaces:

interface IEventRouter : IActor
{
    void Subscribe(IEventSubscriber subscriber);
}

interface IEventSubscriber : IActor
{
    void EventAvailable();
}

Event subscriber code:

class EventSubscriber : Actor, IEventSubscriber
{
    void SubscribeToEvent()
    {
        IEventRouter router = ActorProxy.Create<IEventRouter>("fabric:/MyApp/MyEventRouterActor");
        router.Subscribe(this);
    }

    public void EventAvailable()
    {
        // Process the event
    }
}

Event router code:

// Define actor state
[DataContract]
class RouterState
{
    [DataMember]
    public IEventSubscriber Subscriber;
}

// Define actor
class EventRouter : Actor<RouterState>, IEventRouter
{
    public void Subscribe(IEventSubscriber subscriber)
    {
        this.State.Subscriber = subscriber;
    }

    void OnEventAvailable()
    {
        this.State.Subscriber.EventAvailable();
    }
}