Skip to content
mookid8000 edited this page Apr 17, 2013 · 5 revisions

Since message dispatch is such an important part of Rebus, I think it's fair to dedicate a page to explain how it happens... here goes :)

What is it?

Message dispatch is what happens when a Rebus endpoint receives a message - and by message, I mean a transport message. A transport message is a serialized thing that has headers and a body, and the body will contain 1 or more logical messages. When you're using the default Rebus operations as exposed directly on IBus, you will always be shipping one single logical message at a time.

"Logical messages"?

Since Rebus supports batching on the client side, a sender/publisher can optionally send/publish multiple messages at once by using the batch API: bus.Advanced.Batch.Send(IEnumerable ofMessages) and bus.Advanced.Batch.Publish(IEnumerable ofMessages).

When batching messages, the entire batch will be packed into one single transport message which will be handled "at once" by the receiver.

Handling a transport message

When a transport message has been properly deserialized in the receiving end, Rebus has a sequence of one or more logical messages that must be dispatched.

For each logical message, Rebus will resolve - with multiple calls to the current implementation of IActivateHandlers - all possible handlers for that logical message. This means that at least two calls will be made for each logical message:

  • Resolve IHandleMessages<YourMessage>
  • Resolve IHandleMessages<object>

which also means that if your message has more base types in its inheritance hierarchy, additional calls will be made.

At this point, no handler has been called yet - Rebus has just resolved all handlers and put them in a sequence.

Ordering the handler pipeline

Now, with this potentially giant pipeline of handlers, Rebus can - if you've configured it to do so - order the pipeline in accordance with the specification made like so:

Configure.With(...)
    .(...)
    .SpecifyOrderOfHandlers(s => s.First<MustBeFirst>().Then<MustBeSecond>())
    .(...)

where you can keep calling .Then<AnotherHandlerType>() as many times as you want. This is just the built-in mechanism however, you can go and implement IInspectHandlerPipeline yourself if you want even more control.

The actual dispatch

Now, finally, we're ready to actually call some handlers! We have a sequence of messages and a sequence of handlers, and the handlers must be called in the right order.

Therefore, we dispatch like this (not actual C# code ;)):

  • For each handler h ** For each logical message m *** If m can be dispatched to h: Do it

AND - this is important - the message queue transaction AND the Rebus unit of work (if you're using that) span this entire process. This means that a single transport message can and should be handled as a single unit of work, either committing or rolling back the whole thing atomically.

Clone this wiki locally