Honey, I Shrunk the SOA

I’ve recently been thinking what would happen if we applied the principles of SOA (done properly, using asynchronous messaging) to the design of code running within a single process. In other words, the code would consist of independent services that could only communicate asynchronously via some kind of message bus. What would this look like? Would it have any benefits?

Before I go any further, I should point out that I did some research and discovered that Svein Arne Ackenhausen had not only been thinking along these lines, but was also using them in production. His blog post summarises the benefits as he sees them, and he linked to his standard implementation. However I’ve not been able to find any other articles discussing these ideas, so I thought I’d write up my thoughts in the hope that I can get some useful feedback.

Svein’s implementation is a very nice, simple approach (a good thing!) which clearly demonstrates that there aren’t any great technological barriers to adopting this design pattern. However, I think it may benefit from some additions.

Firstly, as Svein mentions, stateful services have to be modelled very carefully because the service can be handling multiple messages concurrently. What if we sidestepped this problem by combining the message bus concept with the Actor Model so that each service behaves as an actor that processes messages sequentially? Now we can use stateful services where appropriate without having to worry about concurrency.

Secondly, it only really deals with publishing events: there is no concept of request/response. We could mimic request/response by convention (handlers of IFoo must themselves publish a message of type IFooResponse in return), but as Svein pointed out in his blog post, one of the benefits of this approach is that:

By making sure that your code feature produces an output in the shape of a message you have made that code feature a stand alone piece of code. It can now make sense beyond the contract that would have otherwise been passed to it. Being a stand alone piece of code it becomes a natural place for integration. Integration that would happen through consuming a message or producing a message that other participants can consume through the message dispatcher.

To maximise this benefit I feel we should be making explicit the difference between publishing an event and sending a command or querying for data. This is something that, for example, NServiceBus makes explicit via the Publish() and Send() methods on its service bus interface.

So what would such an API look like? First we need the message handling interfaces that services can implement:

public interface IEventHandler<TEvent>
    void HandleEvent(TEvent message);

public interface IRequestHandler<TRequest, TResponse>
    Task<TResponse> HandleRequest(TRequest message);

By returning a Task the IRequestHandler will integrate nicely with the async features of C# 5.

Next we need the message bus interface:

public interface IMessageBus
    public void RegisterEventHandler<TEvent>(IEventHandler<TEvent> handler);
    public void RegisterRequestHandler<TRequest, TResponse>(IRequestHandler<TRequest, TResponse> handler);
    public void Publish<TEvent>(TEvent message);
    public Task<TResponse> Send<TRequest, TResponse>(TRequest message);

Then at the application root we can configure the system by registering services with the message bus:

var serviceA = new ServiceA; // implements IEventHandler
bus.RegisterEventHandler(IEventHandler serviceA);

var serviceB = new ServiceB; // implements IRequestHandler
bus.RegisterRequestHandler(IRequestHandler serviceB);

And services can interact with the bus like so:

public async void DoStuff()
    // some actions...

    // this will send the ReqA message and asynchronously await the response
    var result = await bus.Send(new ReqA());

    // do other stuff with the result...

Whilst it is a nice idea to avoid concurrent message processing in the services, we need a way of handling the situation where the service cannot process the messages quickly enough. The solution comes from considering the SOA approach: simply add multiple service instances behind a load balancer! For example:

public class EventLoadBalancer : IEventHandler<TEvent>
    public LoadBalancer(Func<IEventHandler<TEvent>> slaveFactory)
        // set up appropriate queues etc to hold slave instances

    public void HandleEvent(TEvent message)
        // forward message to chosen slave instance

Because the load balancer is itself an IEventHandler<TEvent>, we can simply pass it to the RegisterEventHandler method on the message bus instead of passing the service instance.

So far, so theoretical. How can we implement the actor functionality? Luckily, F# already supports agents (F# terminology for actors) via its MailboxProcessor class. So all we need to do is place an F# Agent between each service and the message bus (this can be done by the RegisterEventHandler and RegisterRequestHandler methods of the message bus):

So, the F# Agent will be responsible for forwarding the message to the appropriate message handler interface of the service and it also ensures that the service does not process multiple messages concurrently.

This approach could be the high level architecture, and would in no way constrain lower level design choices. So, individual services could be implemented in a traditional OO manner, a pure functional manner, or anything in-between. A service could even be decomposed into sub-services and use an internal message bus.

In the next post I’ll look in more detail at a proof-of-concept implementation. In the meantime, I’ll point out a couple of things I found out whilst writing this post:

  1. The next version of NServiceBus will likely have an in-process mode. It will be interesting to see what form this takes.
  2. Alan Kay, who coined the term “object oriented” believes that the messaging between objects is far more important than the objects themselves. Maybe we are heading back closer to his original vision?

One thought on “Honey, I Shrunk the SOA

  1. Pingback: Message Bus In Action | GET http://localhost…200 OK

Leave a Reply