Interrupting Events in Automation

In my BPMN Method and Style training, we use examples like the one below to illustrate the difference between interrupting and non-interrupting boundary events:

Here an Order process with four subprocesses could possibly be cancelled by the Customer at any time. As you can see, a single physical Cancellation message from Customer is modeled as multiple message flows. That's because the Cancellation message is caught by four different message boundary events, representing four different ways the message is handled depending the state of the process when Cancellation occurs. Note that if the message is received during Prepare invoice, i.e., after Ship order is complete, the Order process cannot be terminated, and explanatory information is instead sent to the Customer. And this is a fine way to show, in descriptive models - i.e., non-executable BPMN - the behavior expected with exceptions like Customer Cancellation.

But as I have begun to get more involved with Automation models - executable BPMN - I am discovering that modeling exception handling in this way is not ideal. The BPMN spec says that an interrupting boundary event terminates the activity immediately. As far as the process engine is concerned, the instance just goes away, along with all its data. A user performing some task inside a cancelled subprocess is unaware of this until the task is complete; the Performer gets no notification that their work on this Order is for naught. That's the main problem. There is also the problem that some actions performed in the activity prior to cancellation may need to be undone. That can be done on the exception flow, so the main difficulty, as I see it, is notifying the user performing some task when the Cancellation occurs.

Let's focus on the first subprocess, Enter order. In this simplified example, the Order is first logged into the Order table, then inventory is checked for each Order item, reserving the Order quantity for each one. If some items are out of stock, we need to Update Order table. An Order Acknowledgment message is sent to the Customer containing the OrderID, a unique identifier in the system. The Customer would need to provide this in any Cancellation message. These are all automated activities, occurring very fast. Then a User task Check credit authorizes the purchase for this Customer. That could take a while, so if the Customer decides to cancel shortly after submitting the order, it's likely going to occur during Check credit. And if that happens, we don't want the user performing Check credit to waste any more time on this Order, as would happen with an interrupting boundary event.

So instead we model it as a non-interrupting event subprocess. We could do it with a non-interrupting boundary event on the subprocess, but this way I think is cleaner. Now if the Cancellation message is received, before we terminate Enter order we do a bit of cleanup, including Update Order table to show a status of "Cancelled by Customer" and notifying the Check credit performer by email to stop working on this instance, after which we terminate the subprocess with an Error end event. The exception flow from this Error event in the parent level allows additional exception handling for the Cancellation.

The required exception handling requires some additional information about the process instance. We need to know who is the task performer of Check credit. This is platform-dependent, but on the Trisotech Low-Code Automation platform you can use a FEEL extension function to retrieve the current task performer. In a more complex subprocess, we may also need to know its state when the cancellation occurred, which tasks have been completed and may need to be undone. For this, Trisotech has provided additional extension functions as well. Cleaning up when a process instance is cancelled in-flight can be messy, but it's still within the reach of Low-Code Business Automation.