目录
1.背景:
在断电测试中,发现client端拉取job时,若在job执行过程中server端服务宕机(client未发送completeCommand到server端),重启server端后,刚执行到一半的任务会重新执行,而且一般是在server端重启后5分钟左右重新执行, 针对这一现在分析zeebe代码实现的原理。
2.时序图:
简化了细节,详细实现可参考下一节:
3.代码分析:
3.1 5分钟的重试间隔
客户端通过发送activeCommand从server端拉取任务,在拉取任务时,默认指定了job的超时时间为5min,该设置就是重试在5分钟之后执行的原因。
ZeebeClientBuilderImpl#defaultJobTimeout
该配置可以在创建客户端时显式配置:
io.camunda.zeebe.client.impl.ZeebeClientBuilderImpl#defaultJobTimeout
修改该值后,任务的重试间隔将会变为1分钟
3.2 server端计算deadline
gatewya在创建 BrokerActivateJobsRequest 会传递该timeout值
io.camunda.zeebe.gateway.RequestMapper#toActivateJobsRequest
timeout属性的传递路径为:
——>RequestMapper#toActivateJobsRequest
——>BrokerActivateJobsRequest#setTimeout
——>JobBatchRecord#setTimeout
最终赋值给 JobBatchRecord#timeoutProp
计算job的 超时时间:
io.camunda.zeebe.engine.processing.job.JobBatchCollector#collectJobs
3.3 超时重试机制:
每次activeJob时,会往deadline的列簇中插入数据,之后周期性轮询其中的记录是否超时,取出超时的任务进行对应的处理
3.3.1 往deadline的列簇中插入数据
io.camunda.zeebe.engine.state.instance.DbJobState#activate
3.3.2 遍历deadline的列簇并处理
io.camunda.zeebe.engine.processing.job.JobTimeoutTrigger#scheduleDeactivateTimedOutJobsTask
周期性执行的逻辑为:
数据库遍历超时的记录 DbJobState#forEachTimedOutEntry
此处的callback方法,即上述方法中传入的: taskResultBuilder.appendCommandRecord(key, JobIntent.TIME_OUT, record)
基于 JobEventProcessors#addJobProcessors 可知 JobIntent.TIME_OUT 对应的处理器为 JobTimeOutProcessor,因此进一步查看该processor
所有超时的任务都在这里处理 jobTimeOutProcessor#onCommand
可以看到,仅对于执行到一半(activated状态)的job数据,进行进一步的处理;该类数据即客户端已成功拉取,但未返回completeCommand
此处对应的处理逻辑较为简单,即操作数据库将job的状态从activated修改未activable ,还原了job的状态后,客户端就能成功poll到job,进而恢复流程实例的执行
io.camunda.zeebe.engine.state.appliers.JobTimedOutApplier#applyState
4. 其它说明:
4.1 JobTimeoutTrigger#scheduleDeactivateTimedOutJobsTask 的触发时机:
StreamProcessor#startProcessing 执行过程中,会调用 JobTimeoutTrigger#onRecovered
完成 scheduleDeactivateTimedOutJobsTask 的调用