Saga implementation patterns – Observer

NServiceBus sagas, itself an implementation of the Process Manager pattern, often takes one of two main forms when implemented. It’s not a cut and dry distinction, but in general, I’ve found that saga implementations typically fall into one or the other.

The first kind would be the Observer pattern. As an Observer, this saga responds to events to coordinate an activity:

image

There are a few characteristics of the observer:

  • Messages are received as events
  • The Saga does not control the order in which messages are received

Since the Saga does not control message ordering and these messages are events, the saga behaves as an observer. It doesn’t influence these external services, but instead observes results through event each publishes.

Another interesting characteristic of an Observer saga is that typically, its purpose is to coordinate some activity after it has received all service events. It begins to look something like this:

image

This is similar to the Scatter/Gather pattern, but not quite. The saga itself often needs to keep track of which messages are received. Upon receiving a message, it will note that the message has been received, and check to see if all relevant messages have been received before proceeding onwards.

It’s a simple workflow pattern, with the caveat that it doesn’t know which messages will be received in which order.

To see this in action, let’s look at a real-world scenario where we can observe this pattern in play.

Fast food messaging – McDonald’s

The fun thing about learning distributed systems is that the examples of application are literally all around us. One great example of the saga observer pattern in actual real-world use is the fast food chain McDonald’s in-store ordering process.

Order preparation in McDonald’s (and many other fast food chains) is not a linear process. There are a number of stations performing work, but they do so relatively independently. In any given order, we might have:

  • Sandwiches
  • Drinks
  • Salads
  • Fries
  • Coffee

And so on. Each station is its own independent worker, with its own independent queue of work. A typical order looks something like this:

image

The order starts off with a customer placing an order (1). If the order is accepted (they have money), then an event is broadcasted to all relevant food preparation stations (2). Each station has a computer screen above it, representing a queue of work to be done.

Only the relevant orders show up on the relevant screens. If the order has no fries, the fry station screen does not show anything with that order.

Each station does its work independently of the other. The fry station doesn’t need information from the drink station to do its work.

As each station completes the order, they take the food back to the counter (3) – where each order to be delivered is separated by a food tray. Each station is responsible for figuring out which tray their food belongs to – correlated by the order number. On each station’s screen, orders are separated out by order number so that each station has some information to correlate a single order.

Each time a station brings a completed item to the tray, the employee checks the receipt on the tray to determine if the order is completed. This is done with each item brought to the tray, we must re-check the items to see if the order is completed. There is not one person in charge of this responsibility – every employee bringing finished items does this check.

Once an employee determines that the order is complete, they call out the order number and the original customer picks up their tray (4).

Well before sagas were implemented in NServiceBus, we had observer sagas in real life (though we never called it this).

Benefits and drawbacks

This pattern, like all others, has some benefits and drawbacks. McDonald’s implemented this pattern to maximize the efficiency of processing orders, but it’s not a universal pattern in fast food chains. The benefits include:

  • Each worker operates in parallel with others, upping the overall throughput
  • Each worker is independent of others, and is decoupled from other steps
  • We can add additional steps and workers fairly easily (McDonald’s added coffee recently, but this didn’t change their overall order delivery pattern)

However, this pattern is not without its drawbacks:

  • Resource contention is introduced. We can’t have two employees delivering food to the same tray at the same time – there’s just not physical room for them! The tray/saga becomes the choke point in our system – and this piece we can’t easily scale
  • Every step has to check to see if the saga is complete. This introduces extra logic to our saga to keep track of what’s done, and check to see if it’s complete

Next time you go to a fast food restaurant, see if they fulfill their orders this way. In a restaurant with highly independent steps, they’ve likely determined that this method of managing orders is most efficient.

However, it’s not always the best way. In the next post, we’ll look at the converse of the observer – the controller.

Related Articles:

Post Footer automatically generated by Add Post Footer Plugin for wordpress.

About Jimmy Bogard

I'm a technical architect with Headspring in Austin, TX. I focus on DDD, distributed systems, and any other acronym-centric design/architecture/methodology. I created AutoMapper and am a co-author of the ASP.NET MVC in Action books.
This entry was posted in Messaging, NServiceBus, SOA. Bookmark the permalink. Follow any comments here with the RSS feed for this post.
  • Mark

    You spend too much time in that restaurant… ;-)

  • Andreas Öhlund

    Did you draw the saga outside the services on purpose in the first image?
    I know that this is the way Greg advocates it while Udi is saying that there is no “in-between” and all sagas belongs to a given service.

    • jbogard

      Just an oversight – it’s inside a service. I assume that someone has to own the process, we’re not doing self-organizing services ;)

  • http://twitter.com/ntcoding Nick

    Use Visio Jimmy :)

    • jbogard

      Ha but it’s so ugly!

  • marcusswope

    Instead of having every step check whether the saga is complete, couldn’t you queue another message at the end to check the completion? If it is completed- send a notification. If not- requeue the same “Check Status” message again.

    I guess the only drawback here is that under high load, the message to check the status could keep getting shoved to the back of the line…?

    • jbogard

      That can work, and in fact, sit down restaurants often operate this way. Wait staff are the checkers here, going every now and then to see if the order is complete. But, we have that extra employee performing this extra management and “shepherding”. Since there is one person who actually delivers, that makes more sense.
      In fast food, we’re just calling a number. Not that either is better, but I do have the option in a polling model to worry about orders taking too long, for example.

    • http://twitter.com/thefringeninja João P. Bragança

      The saga could also call OnNext(new SagaCompleted()) on the observable it is subscribed to if it knew how many ItemCompleted it should receive.

  • Pingback: Saga implementation patterns – Controller | Jimmy Bogard's Blog

  • Pingback: Scott Banwart's Blog › Distributed Weekly 198

  • Pingback: Saga patterns: wrap up | Jimmy Bogard's Blog

  • Pingback: Saga Pattern | Itsy bitsy of Technology