使用Camunda服务任务的OptimisticLockingException

时间:2013-11-05 11:22:55

标签: java bpm camunda

我们在Camunda流程中看到了使用以下场景的OptimisticLockingExceptions:

该过程包括一个UserTask,后跟一个Gateway和一个ServiceTask。 UserTask执行

runtimeService.setVariable(execId, "object", out);`. 
taskService.complete(taskId);

以下ServiceTask使用" object"作为输入变量(不修改它),并在完成后抛出OptimisticLockingException。我的问题似乎源于这样一个事实:taskService.complete()在刷新UserTask中设置的变量之前立即执行ServiceTask。

我遇到了另一个相关问题,当我在一个UserTask中执行runtimeService.setVariable(Map<Strong, Boolean>)并尝试在该UserTask之后的网关中访问Map的成员作为过渡保护时。

我发现了以下文章:http://forums.activiti.org/content/urgenterror-updated-another-transaction-concurrently这似乎与我的问题有关。但是,我不清楚这是否是(非)想要的行为以及我如何从UserTask访问DelegateExecution - 对象的问题。

2 个答案:

答案 0 :(得分:2)

经过漫长而繁琐的搜索后,我们认为,我们已经解决了两个与camunda有关的问题(加在一起)导致了原始问题的异常。

  1. Camunda对序列化对象(由字节数组表示)使用equals来确定是否必须将进程变量写回数据库。即使只读取和未设置变量,也会发生这种情况。由于equals是由数组上的指针标识定义的,所以如果serializabled-Object已被多次序列化,则它永远不会被确定为“相等”。我们发现,runtimeService.setVariable()时单个completeTask()导致四次数据库更新(一次用于setVariable本身,另外三次用于各种camunda内部验证操作)。我们认为这是一个错误,并会向camunda提交错误报告。

  2. 显然,有两种方法可以设置变量。一种方法是使用runtimeService.setVariable(),另一种方法是使用delegateTask/delegateExecution.setVariable()。在同时使用两种方式时存在一些缺陷。虽然我们无法将设置简化为简单的单元测试,但我们已经确定了几个必须涉及异常的组件:

  3. 2.1我们使用TaskListener在任务开始时设置一些上下文变量,这个任务 - 监听器使用runtimeService.setVariable()而不是delegateTask.setVariable()。在我们改变之后,Exception消失了。

    2.2我们在任务执行期间使用(并且仍在使用)runtimeService.setVariable()。在我们切换到completeTask(Variables)并省略runtimeService.setVariable()次调用之后,Exception也消失了。但是,这不是永久解决方案,因为我们必须在任务执行期间存储流程变量。

    2.3只有在以delegate<X>.getVariable()方式读取或写入的过程变量时才会发生异常(通过我们的代码或隐式地在使用网关和serviceTasks或completeTask(HashMap)的juel解析的camunda实现中)

    非常感谢您的所有投入。

答案 1 :(得分:0)

您可以考虑在服务任务上使用异步延续。这将确保在新的事务/命令上下文中执行服务任务。 考虑阅读camunda documentation on transactions and asynchronous continuations

DelegateExecution对象用于提供服务任务(JavaDelegate)实现对流程实例变量的访问。它并不打算在用户任务中使用。