AnsweredAssumed Answered

RuntimeService.deleteProcessInstance is causing ActivitiOptimisticLockingExceptions

Question asked by hepcibha on Apr 9, 2015
Latest reply on Jun 2, 2015 by jbarrez
Hi,

In my application, for some use cases, we have to terminate currently running workflow instances and create a new one with new runtime variables. To implement this, as suggested in the activiti forums, we used runtimeService.deleteProcessInstance to terminate the currently running workflows and sued runtimeService.createProcess to create a new process instance.

Very often when this usecase executes, we see ActivitiOptimisticLockingExceptions in the logs. This impacts the functionality - the old workflows that are supposed to be terminated are still executing.

org.activiti.engine.ActivitiOptimisticLockingException: JobEntity [id=56c7ce96-de12-11e4-aac1-000c2995d32a] was updated by another transaction concurrently
org.activiti.engine.ActivitiOptimisticLockingException: JobEntity [id=56c7ce96-de12-11e4-aac1-000c2995d32a] was updated by another transaction concurrently
   at org.activiti.engine.impl.db.DbSqlSession$CheckedDeleteOperation.execute(DbSqlSession.java:229)
   at org.activiti.engine.impl.db.DbSqlSession.flushDeletes(DbSqlSession.java:575)
   at org.activiti.engine.impl.db.DbSqlSession.flush(DbSqlSession.java:443)
   at org.activiti.engine.impl.interceptor.CommandContext.flushSessions(CommandContext.java:169)
   at org.activiti.engine.impl.interceptor.CommandContext.close(CommandContext.java:116)
   at org.activiti.engine.impl.interceptor.CommandContextInterceptor.execute(CommandContextInterceptor.java:70)
   at org.activiti.spring.SpringTransactionInterceptor$1.doInTransaction(SpringTransactionInterceptor.java:42)
   at org.springframework.transaction.support.TransactionTemplate.execute(TransactionTemplate.java:130)
   at org.activiti.spring.SpringTransactionInterceptor.execute(SpringTransactionInterceptor.java:40)
   at org.activiti.engine.impl.interceptor.LogInterceptor.execute(LogInterceptor.java:31)
   at org.activiti.engine.impl.RuntimeServiceImpl.deleteProcessInstance(RuntimeServiceImpl.java:87)


I understnad that this exception is thrown when one or more threads are trying to concurrently trying to update the same process. Meaning one thread could be continuing to execute the workflow while the other is trying to terminate it.

As per the use case, we need the actively runnign process to be terminated or brought to a halt and then deleted. We tried to call suspendProcessInstanceById prior to deleteProcessInstance with a hope that suspend will bring the currently running workflow to a halt and then delete will be successful after that. But that did not help.

This is happening in production and we have to apply a hotfix asap so stop the mess it is creating - so we put a hack in place and are trying to test it out before we can drop it in prod. I just wanted to check with the experts here to see if there is a better way to solve this issue.

Our work around (hack) is - to catch the optimistic locking exception and spawn a separate thread that will keep retrying for 10 times or until the process is deleted which ever comes early.


private void cleanUpAllWorkflows(List<String> workflowInstances, String deleteReason)
    {
        for (String workflowId : workflowInstances)
        {
            try
            {
               runtimeService.suspendProcessInstanceById(workflowId);
               runtimeService.deleteProcessInstance(workflowId, deleteReason);
            }
            catch (ActivitiOptimisticLockingException e)
            {
                this.diagnosticMethodSignature.setMethodName("cleanUpAllWorkflows");
                this.customLogger.logMessage(diagnosticMethodSignature, DiagnosticType.WARNING,
                      "error on cleanUpAllWorkflows, starting retry thread", e);
               
                // initial delete failed so retry
               DeleteExecutor thread = new DeleteExecutor(workflowId, deleteReason, runtimeService);
               taskExecutor.execute(thread);      
           }
        }
    }


In deleteExecutor, teh execute method looks like this



public void run() {
      
boolean deleted = false;

for (int k=0;k<10;k++) {
   if (!deleted) {
      try   {   
         

         wait(1000);
         runtimeService.deleteProcessInstance(workflowID, deleteReason);
         deleted = true;
         k = 10;
      } catch (ActivitiOptimisticLockingException e) {
         customLogger.logMessage(this.diagnosticMethodSignature, DiagnosticType.WARNING,"error on delete workflows, retry count : " + k);

      } catch (InterruptedException i) {
         
      }
   }
}Please let me know if there is a better way to achieve this using activiti engine apis, instead of writing our own custom code.

Thanks for your help!
Hepci

Outcomes