Hibernate errors with Singleton RuntimeManager and outer transaction in BPM Suite

Solution Unverified - Updated

Environment

  • Red Hat JBoss BPM Suite
    • 6.4
  • jBPM library embedded application
  • Singleton RuntimeManager strategy
  • Spans a transaction in user application

Issue

Hibernate errors with Singleton RuntimeManager and outer transaction in BPM Suite

  • An application embeds jBPM libraries. Sometimes I get the following errors
2018-05-15 13:36:36,410 WARN  [org.jbpm.shared.services.impl.TransactionalCommandService] (default task-87) Could not commit session: javax.persistence.PersistenceException: org.hibernate.HibernateException: Found shared references to a collection: org.jbpm.services.task.impl.model.TaskImpl.deadlines.endDeadlines
        at org.hibernate.jpa.spi.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:1692)
        at org.hibernate.jpa.spi.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:1602)
        at org.hibernate.jpa.internal.QueryImpl.getResultList(QueryImpl.java:492)
        at org.jbpm.shared.services.impl.JpaPersistenceContext.queryStringWithParameters(JpaPersistenceContext.java:190)
        at org.jbpm.shared.services.impl.JpaPersistenceContext.queryWithParametersInTransaction(JpaPersistenceContext.java:57)
        at org.jbpm.shared.services.impl.commands.QueryNameCommand.execute(QueryNameCommand.java:49)
        at org.jbpm.shared.services.impl.TransactionalCommandService.execute(TransactionalCommandService.java:71)
        at org.jbpm.kie.services.impl.RuntimeDataServiceImpl.getTasksByStatusByProcessInstanceId(RuntimeDataServiceImpl.java:880)
        at org.jbpm.services.cdi.impl.RuntimeDataServiceCDIImpl$Proxy$_$$_WeldClientProxy.getTasksByStatusByProcessInstanceId(Unknown Source)
        at com.example.MyService.findTaskIdsByProcessInstanceId(MyService.java:135)
        ...
Caused by: org.hibernate.HibernateException: Found shared references to a collection: org.jbpm.services.task.impl.model.TaskImpl.deadlines.endDeadlines
        at org.hibernate.engine.internal.Collections.processReachableCollection(Collections.java:183)
        at org.hibernate.event.internal.FlushVisitor.processCollection(FlushVisitor.java:46)
        at org.hibernate.event.internal.AbstractVisitor.processValue(AbstractVisitor.java:104)
        at org.hibernate.event.internal.AbstractVisitor.processValue(AbstractVisitor.java:65)
        at org.hibernate.event.internal.AbstractVisitor.processValues(AbstractVisitor.java:44)
        at org.hibernate.event.internal.AbstractVisitor.processComponent(AbstractVisitor.java:85)
        at org.hibernate.event.internal.AbstractVisitor.processValue(AbstractVisitor.java:110)
        at org.hibernate.event.internal.AbstractVisitor.processValue(AbstractVisitor.java:65)
        at org.hibernate.event.internal.AbstractVisitor.processEntityPropertyValues(AbstractVisitor.java:59)
        at org.hibernate.event.internal.DefaultFlushEntityEventListener.onFlushEntity(DefaultFlushEntityEventListener.java:155)
        at org.hibernate.event.internal.AbstractFlushingEventListener.flushEntities(AbstractFlushingEventListener.java:216)
        at org.hibernate.event.internal.AbstractFlushingEventListener.flushEverythingToExecutions(AbstractFlushingEventListener.java:85)
        at org.hibernate.event.internal.DefaultAutoFlushEventListener.onAutoFlush(DefaultAutoFlushEventListener.java:44)
        at org.hibernate.internal.SessionImpl.autoFlushIfRequired(SessionImpl.java:1251)
        at org.hibernate.internal.SessionImpl.list(SessionImpl.java:1319)
        at org.hibernate.internal.QueryImpl.list(QueryImpl.java:87)
        at org.hibernate.jpa.internal.QueryImpl.list(QueryImpl.java:606)
        at org.hibernate.jpa.internal.QueryImpl.getResultList(QueryImpl.java:483)
        ... 276 more
2018-05-15 13:36:36,763 ERROR [org.hibernate.AssertionFailure] (default task-2) HHH000099: an assertion failure occured (this may indicate a bug in Hibernate, but is more likely due to unsafe use of the session): org.hibernate.AssertionFailure: possible nonthreadsafe access to session
2018-05-15 13:36:36,763 WARN  [org.jbpm.services.task.persistence.TaskTransactionInterceptor] (default task-2) Could not commit session: org.hibernate.AssertionFailure: possible nonthreadsafe access to session
	at org.hibernate.action.internal.EntityUpdateAction.execute(EntityUpdateAction.java:160)
	at org.hibernate.engine.spi.ActionQueue.executeActions(ActionQueue.java:582)
	at org.hibernate.engine.spi.ActionQueue.executeActions(ActionQueue.java:456)
	at org.hibernate.event.internal.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:337)
	at org.hibernate.event.internal.DefaultAutoFlushEventListener.onAutoFlush(DefaultAutoFlushEventListener.java:50)
	at org.hibernate.internal.SessionImpl.autoFlushIfRequired(SessionImpl.java:1251)
	at org.hibernate.internal.SessionImpl.list(SessionImpl.java:1319)
	at org.hibernate.internal.QueryImpl.list(QueryImpl.java:87)
	at org.hibernate.jpa.internal.QueryImpl.list(QueryImpl.java:606)
	at org.hibernate.jpa.internal.QueryImpl.getResultList(QueryImpl.java:483)
	at org.jbpm.services.task.persistence.JPATaskPersistenceContext.queryStringWithParameters(JPATaskPersistenceContext.java:575)
	at org.jbpm.services.task.persistence.JPATaskPersistenceContext.queryWithParametersInTransaction(JPATaskPersistenceContext.java:398)
	at org.jbpm.services.task.impl.TaskDeadlinesServiceImpl.unschedule(TaskDeadlinesServiceImpl.java:137)
	at org.jbpm.services.task.commands.CancelDeadlineCommand.execute(CancelDeadlineCommand.java:71)
	at org.jbpm.services.task.commands.CancelDeadlineCommand.execute(CancelDeadlineCommand.java:33)
	at org.jbpm.services.task.commands.CompositeCommand.execute(CompositeCommand.java:145)
	at org.jbpm.services.task.commands.TaskCommandExecutorImpl$SelfExecutionCommandService.execute(TaskCommandExecutorImpl.java:65)
	at org.drools.core.command.impl.AbstractInterceptor.executeNext(AbstractInterceptor.java:41)
	at org.jbpm.services.task.persistence.TaskTransactionInterceptor.execute(TaskTransactionInterceptor.java:69)
	at org.drools.core.command.impl.AbstractInterceptor.executeNext(AbstractInterceptor.java:41)
	at org.drools.persistence.jta.TransactionLockInterceptor.execute(TransactionLockInterceptor.java:73)
	at org.drools.core.command.impl.AbstractInterceptor.executeNext(AbstractInterceptor.java:41)
	at org.drools.persistence.jpa.OptimisticLockRetryInterceptor.execute(OptimisticLockRetryInterceptor.java:82)
	at org.jbpm.services.task.commands.TaskCommandExecutorImpl.execute(TaskCommandExecutorImpl.java:40)
	at org.jbpm.services.task.impl.command.CommandBasedTaskService.complete(CommandBasedTaskService.java:177)
	at org.jbpm.runtime.manager.impl.task.SynchronizedTaskService.complete(SynchronizedTaskService.java:119)
	at org.jbpm.kie.services.impl.UserTaskServiceImpl.complete(UserTaskServiceImpl.java:189)
	at org.jbpm.services.cdi.impl.UserTaskServiceCDIImpl$Proxy$_$$_WeldClientProxy.complete(Unknown Source)
	at com.example.MyService.completeTask(MyService.java:272)

Resolution

Singleton strategy with JTA transactions (UserTransaction or CMT) would cause hibernate concurrent issues. If outer transaction is required for the application, change the strategy to PerProcessInstance or PerRequest.

https://access.redhat.com/documentation/en-us/red_hat_jboss_bpm_suite/6.4/html-single/development_guide/index#sect_transactions

Warning

Using the (runtime manager) Singleton strategy with JTA transactions (UserTransaction or CMT) is not recommended because of a race condition. It can result in an IllegalStateException with a message similar to "Process instance X is disconnected".

Avoid this condition by explicitly synchronizing around the KieSession instance when invoking the transaction in the user application code:

synchronized (ksession) {
  try {
    tx.begin();

    // use ksession application logic

    tx.commit();
  } catch (Exception e) {
    ...
  }
}

The "synchronized" approach is the only workaround if you have to use Singleton + outer transaction. But usually, there is no reason to stick to Singleton.

Diagnostic Steps

  • Check RuntimeManager strategy
  • Review application source codes to check if an outer transaction is spanned around jBPM API calls

This solution is part of Red Hat’s fast-track publication program, providing a huge library of solutions that Red Hat engineers have created while supporting our customers. To give you the knowledge you need the instant it becomes available, these articles may be presented in a raw and unedited form.