Most of us are working on distributed systems. Most of us are implementing long running processes. Of course we would like all our long running processes to be:
- simple
- fast
- decoupled
- reliable
- easy to implement
- easy to understand
- easy to change
- easy to monitor
But this is impossible, so you need to make trade offs. This is why it’s important to have the right tool for the job. But, much of the information out there describes one tool – RPC style integration (e.g. services calling each other over the web, through HTTP). And although this is a good tool, it’s not the best tool in every situation. The purpose of this blog post series is to present some message based patterns that are useful when designing and implementing long running processes.
What is a long running process
First, let’s start with what is a process. A process is a set of operations that are executed in a given order as result of a trigger.
public Task Handle(PlaceOrder message, IMessageHandlerContext context)
{
Data.OrderId = message.OrderId;
Data.TotalValue = message.TotalValue;
Log.Info($"Placing Order with Id {message.OrderId}");
RequestTimeout(context, TimeSpan.FromSeconds(1), new BuyersRemorseTimeout());
return Task.CompletedTask;
}
In this example, the trigger is the PlaceOrder message, and the instructions are in the body of the method.
A long running process is a process that needs to handle more than one message.
{
public Task Handle(PlaceOrder message, IMessageHandlerContext context)
{
Data.OrderId = message.OrderId;
Data.TotalValue = message.TotalValue;
Log.Info($"Placing Order with Id {message.OrderId}");
RequestTimeout(context, TimeSpan.FromSeconds(1), new BuyersRemorseTimeout());
return Task.CompletedTask;
}
public Task Timeout(BuyersRemorseTimeout state, IMessageHandlerContext context)
{
context.Publish<IOrderPlaced>(
o =>
{
o.OrderId = Data.OrderId;
o.TotalValue = Data.TotalValue;
});
MarkAsComplete();
return Task.CompletedTask;
}
}
As you can see, in the handler of the PlaceOrder message, we set some state (the OrderId and TotalValue) and we raise a timeout. In the second handler, when we receive the BuyersRemorseTimeout, we read the state that we saved in the first handler and publish an event.
Long running means that the same process instance will handle multiple messages. That’s it! Long running doesn’t mean long in the sense of time. At least not for people. Such a process could complete in microseconds. Also, a long running process does not need to be actively processing its entire lifetime. Most of the time, it will probably just wait for the next trigger.
Continue Reading