let´s assume there is a process model with a User Task that has multiple boundary timer events configured with a different User Task. The timer events are configured with different durations and times as well as cancelling and non-cancelling behavior. The process instance is suspended at the time when the timer events would fire. If the process instance is now resumed, our observation is that the a non-cancelling timer event that should have fired before the cancelling timer event is not handled. Instead the non-cancelling timer event is fired first which terminates the User Task. If the process instance is not suspended, the timer events fire in the expected order.
What can we expect from activiti on the order of handling timer events on suspended instances? We are currently on activiti 5.21.0. But I would like to understand the behavior in general (assuming it is similar to flowable 5).
Checked the logic for the current Flowable master code, but the analysis should be the same for previous versions. The order of the timers fired is not deterministic (i.e. depends on the database), as the query for fetching the timers fetches all timers where the due date has passed the threshold. Even if the query would be updated to include ordering, the async executor later fetches the timer jobs that are ready to execute and executes them in a parallel, non-deterministic order (threadpool/message queue is the same).
Trying to understand the use case, suppose there are 3 boundary timer events:
- send email after 1 hour
- send email after 2 hours
- cancel the user task and escalate after 3 hours
If the process instance has been suspended for 4 hours, when activating, only the last one should happen in this particular case. However, probably use cases exist where all should fire.
One potential solution could be to add a (new type of) custom listener that is triggered when timer jobs get activated which gives the opportunity to either reschedule or remove timers. Would that fit your use case?
thanks for your input.
Our expectation would be that, in the example given by you, two emails are sent and only after this the user task is being cancelled. Our assumption was that the jobs are read from the database ordered by their due date. However, you are right that the async executor still might change the order.
For the time being it is fine for us. We simply wanted to be clear on the behavior first. We will give it try using the approach you mentioned.
Looking in the code, it might be possible with the current eventing, however probably it’s easier to extend the org.flowable.job.service.impl.asyncexecutor.DefaultJobManager logic (moveJobToTimerJob method) to do something with those jobs before they’re handed off to the executor.