This post is about modeling asynchronous service invocations in BPMN.
An asynchronous service invocation is a composite interaction following the Request / Acknowledge / Callback pattern. The overall interaction is effectively composed of two separate interactions:
- In the first interaction the process engine sends a message to the service and receives an acknowledgement
- In the second interaction the service responds which a callback message.
The following UML sequence diagram is an adaptation of the one which can be found on the Service Design Patterns site:
I have blogged about asynchronous service invocations before.
The main advantage of an asynchronous service invocation over a synchronous one is that the process engine is not blocked while the service computes the invocation result. This is especially useful if the service performs a complex calculation which takes some time. The main downside is the added complexity of having to implement the callback.
From a modeling perspective, it raises the question whether the composite nature of the interaction should be made explicit in the BPMN diagram or not.
Option 1: Send and Receive Tasks
Let’s first make the asynchronous nature of the interaction explicit in the diagram:
I use a BPMN Send Task to model the first interaction in which the process engine makes the request to the service. Second, I use a BPMN Receive Task to model the second interaction in which the service sends the callback message with the response.
Most of the time when I see this pattern applied, a messaging system is used (JMS, AMQP, …). In that case the process engine publishes the request message to some kind of Queue or Topic and consumes the callbacks from such a Queue as well. This makes the BPMN messaging tasks a good fit since they make the underlying messaging layer transparent.
I have also seen the pattern being used with queuing “behind the service boundary”, ie. the process engine makes a regular REST request to the service and the request queuing is performed transparently (from the point of view of the process engine). In that case the Service Task is a better fit and should be used instead of the Send Task. The callback is still modeled using a Receive Task.
Option 2: Single Service Tasks
It is also possible to implement asynchronous service invocations using a single BPMN Service Task.
When the process engine executes the Service Task, it first sends the request message. It then waits in the Service Task for the callback to arrive. Once the callback arrives, it completes the Service Task and continues.
If you are interested in how to implement this pattern using the open source BPMN Workflow Engine from Camunda, there is an example available on GitHub.
Which Option is better?
As always, it depends on many factors.
A short anecdote: I once visited a customer of ours at Camunda, who uses asynchronous service invocations extensively. In their architecture, asynchronous messaging is employed to decouple the process engine from the services used in the processes. Basically, every service invocation was asynchronous. Since they were not aware of the possibility to model the asynchronous service invocation using a single Service Task, their processes were cluttered with sequences of Send Tasks followed by a Receive Task. In fact, their processes were like 80% this pattern with some gateways in between.
I talked to the architect and he said that everybody was unhappy with that.
The developers were unhappy since they felt that explicitly modeling the callbacks with receive tasks each and every time was an unnecessary complexity and increased the size of their diagrams by a factor of roughly times 2. They also said that if they were to change their architecture in the future and not use messaging any more, then they would have to change all their BPMN diagrams.
The business analysts were also unhappy since they felt that asynchronous implementation of service invocations was a technical detail they should not be concerned with. In fact, when they initially created new models, they used Service Tasks which were then replaced with sequences of Send / Receive Tasks by the developers.
After I showed them how they can implement the service invocations using a single Service Task, acceptance for BPMN (and Camunda BPM Platform :) ) grew significantly. Most importantly, both parties (developers and business analysts) felt that they could now work together in a better way. And for me, this is the key factor to successfully applying BPMN.
Let’s write down some general guidelines after all:
If the asynchronous nature of the service invocation is “just the way your infrastructure works” and basically every service invocation is asynchronous, go with Option 2 (single Service Task).
If the callback has a “business meaning” use Option 1 and model the callback explicitly. A good way to detect this situation is if your business analyst models the callback herself. In some situations, the callback is inherent to the business domain and in those cases it should be, by all means, visible in the diagram.
A good BPMN Workflow Engine should provide you with the flexibility to apply BPMN in a way which reflects the business semantics of the model in the best way and thus leaves these kinds of choices up to you.