Architecture, NServiceBus

In the previous article we’ve seen some examples of long running processes. The purpose of this blog post is to show how to model long running processes by using choreography or orchestration.

Requirement

To better understand the differences between these two approaches, let’s take a long running process and implement it with both. Since we already talked about the Order Fulfillment enterprise process in the last post, let’s use that.

Order Fulfillment

When a customer places an order, we need to approve it, charge the customer’s credit card, pack the order and ship it.

Choreography

Let’s first implement this requirement with choreography. Choreography is all about distributed decision making. When something important happens in a service (or bounded context), the service will publish an event. Other services can subscribe to that event and make decisions based on it.

Choreography

Continue Reading

Architecture

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

Quirks

Today I found an interesting quirk of sp_rename: renaming a view, stored procedure, function or trigger will not update the object’s definition that is returned by the OBJECT_DEFINITION function. This is documented, but I think it might take people by surprise.

Example

So, if you first create the following view:

CREATE VIEW dbo.InitialViewName
AS
SELECT Id
FROM dbo.SampleTable

Then, you update its name:

EXEC sp_rename 'InitialViewName', 'UpdatedViewName'

Now, when you get the view’s definition:

SELECT OBJECT_DEFINITION(OBJECT_ID('UpdatedViewName'));

The result might surprise you

CREATE VIEW dbo.InitialViewName  AS  SELECT        Id  FROM            dbo.SampleTable

Notice it’s still InitialViewName. So, if you use the OBJECT_DEFINITION in your SQL scripts, you better stick to dropping and re-creating these objects.