Hi Frederik,
you wrote:
> But it seems that your process doesn't have an async nature …
Ok, I think so too.
> … the only option is to create the mutex mechanism to prevent 2 tasks from starting.
> But if this is a DB-mutex, again this can create the same issues (unless a full-table lock is done)…
Look at the following figure:
[attachment=0]lock.png[/attachment]
Locking the task completion has to take place in an own, isolated database transaction before taskService.complete() is called.
As soon as taskService.complete() returns (or throws an exception) the task must be unlocked. This has to take place also in an own isolated transaction.
We want to lock because the service task may contain non-transactional operations (sending emails, producing cards, …) which can't be rolled back and which must be prevented to be executed several times.
Locking must be done via database (instead of java.util.HashMap) because there might be several JVMs involved in case of load balancing etc.
The locking transactions must be own and isolated because we want to fail fast (i.e. before the first complete call is executed completely).
Locking/unlocking can be achieved by inserting/deleting a new record in an additional database table with the taskId as key.
This way only one of the simultaneously working users succeeds in completing the task, all other calling users will fail immediately.
I assume that this approach will reliably work also across process boundaries and hosts - provided that the system does not crash.
If a machine crashs and the unlocking is skipped there will remain a locked taskId in the additional database table.
Years ago, in our previous product we implemented a database based mutex with an additional thread which did a "heartbeat" on every active locking record:
Every few seconds the locking record was updated with a current timestamp and an individual ID by the thread which held the lock.
A competing locking thread in another JVM was allowed to replace the record by it's own ID and current timestamp if and only if it detected a foreign old timestamp (e.g. older than one minute).
In this situation the first thread probably has died unexpectedly.
Some more years ago we used a simpler database based locking mechanism which needed user interaction after system has crashed.
Probably the simple solution which needs user interaction after system crash is not state of the art.
So we must implement the heartbeat based mutex in our current product.
On the other hand the requirement to lock taskIds is not specific to our product.
I assume that most users of Activiti will place some non-transactional operations in their processes following user tasks.
Therefore it would be a good idea to implement this feature inside Activiti, isn't it?
Kind regards,
Markus Müller