我们在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
- 对象的问题。
答案 0 :(得分:2)
经过漫长而繁琐的搜索后,我们认为,我们已经解决了两个与camunda有关的问题(加在一起)导致了原始问题的异常。
Camunda对序列化对象(由字节数组表示)使用equals
来确定是否必须将进程变量写回数据库。即使只读取和未设置变量,也会发生这种情况。由于equals
是由数组上的指针标识定义的,所以如果serializabled-Object已被多次序列化,则它永远不会被确定为“相等”。我们发现,runtimeService.setVariable()
时单个completeTask()
导致四次数据库更新(一次用于setVariable本身,另外三次用于各种camunda内部验证操作)。我们认为这是一个错误,并会向camunda提交错误报告。
显然,有两种方法可以设置变量。一种方法是使用runtimeService.setVariable()
,另一种方法是使用delegateTask/delegateExecution.setVariable()
。在同时使用两种方式时存在一些缺陷。虽然我们无法将设置简化为简单的单元测试,但我们已经确定了几个必须涉及异常的组件:
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
)实现对流程实例变量的访问。它并不打算在用户任务中使用。