The idea was, we have to send the escalation email notification in both cases:
None action is taken during the timer Duration period (process has not finished yet - e.g. “Check conditions, set process variables” takes too long)
Action A is taken (escalation occurs after 30 seconds of the timer)
And the notification must not be sent, when Action B is taken before 30 seconds!
Implementation: java service task, delegate expression - extension of AbstractBpmnActivityBehavior (execute() and signal() methods).
Not only “terminate” end event terminates the process instance, but also “none” end event does the same.
Result is, when our porcess is “sleeping” and waiting for signal() callback in service task “Check conditions, set process variables” and 30 s timer executes “Escalation service task”, process instance is terminated and the actual signal() callback for “Check conditions, set process variables” cannot find running instance (resulting in an error).
Is it intended behavior, or some kind of bug?
If it’s intended, can you please fix the Termination chapter of the tutorial (BPMN 2.0 Symbols - A complete guide with examples. - Camunda) so it’s clear, you cannot do it in execution and also provide some hint, how to modify the process to do the same the right way?
I would suggest thinking about this a different way. Rather than setup the send notification with a delay and cancelling, think about what you want to happen after a time has passed. Hence consider using a non interrupting boundary event which then sends an email alert…
As a set of principles, ask these questions;
Do I want to delay an activity or initiate an activity at the expiration of a time period?
Use an intermediate timer catch event to delay an activity which will occur.
Use an interrupting or non-interrupting boundary event to initiate an activity which may occur.
My advice to my developers in these kinds of contexts is try not to program in BPMN. They need to turn off their programming brains and switch on their modelling brain. In other words model the desired behaviour first rather than program the desired behaviour.
I have included below an alternate approach using a non interrupting event sub-process to capture common behaviour. It may be a little ‘over-engineered’, but I have been deliberate in this to demonstrate whats possible with a more model driven approach.
This is actually expected behavior (although you are using internal API by extending AbstractBpmnActivityBehavior, so there is probably no actual expected behavior in terms of Camunda features anyway). Executing the timer does not actually end the process instance, but the ID of the execution that is responsible for the Check conditions activity changes. That is why using RuntimeService#signal with the execution ID won’t work afterwards and is not a robust solution. May the external task feature is a better solution to implement that activity externally. Or you redesign your process as Rob suggests.