AnsweredAssumed Answered

ActivitiOptimisticLockingException from RuntimeService.signa()

Question asked by flowmonkey on May 9, 2014
Latest reply on Jul 9, 2014 by flowmonkey
I have a seemingly common use case for a round robin processing distribution.

An Activiti process holds a collection of items to process. The processing of the items is handled by an external service and can be executed in parallel on a number of external processors. I created a multi-instance subprocess, each instance of which removes one item from the parent's collection and sends it to its corresponding external processor along with its execution ID. It then waits for the processing to complete (in a receive task) and then loops if there are any more items left in the parent's collection to be processed.

Once an external processor completes processing of an item it sends back a message containing the execution ID. A thread waiting for these messages (external to the engine) then calls RuntimeService.signal() method to resume the corresponding execution. The multi-instance executes exclusively so there is at most one instance of the subprocess running at a time. This running instance modifies the parent's collection (removes the next item to process).

What I occasionally see is an ActivitiOptimisticLockingException thrown to the thread calling RuntimeService.signal() complaining that the parent's collection was modified concurrently. Granted, it was likely modified while this particular execution was waiting in a receive task, but there should be no concurrent modifications of any kind because there is no asynchronous non-exclusive tasks/subprocesses anywhere in the process definition.

I also noticed that signal() flushed updates to the database (where the exception is thrown from). Is this intended? If the main process thread has the lock (running a different instance of the multi-instance) and the external thread calling signal() writes to the database then the exception makes sense but isn't signal() only supposed to mark the execution to be picked up by the job executor?

What am I doing wrong?