最近执行esjob的时候,发现有一定的情况下,出现分布式监听执行了多次的情况,通过对比源码,我们发现一个问题
old version:
@Override
public final void beforeJobExecuted(final ShardingContexts shardingContexts) {
guaranteeService.registerStart(shardingContexts.getShardingItemParameters().keySet());
if (guaranteeService.isAllStarted()) {
doBeforeJobExecutedAtLastStarted(shardingContexts);
guaranteeService.clearAllStartedInfo();
return;
}
try {
Thread.sleep(500);
}catch (Exception ex){
ex.printStackTrace();
}
long before = timeService.getCurrentMillis();
try {
synchronized (startedWait) {
startedWait.wait(startedTimeoutMilliseconds);
}
} catch (final InterruptedException ex) {
Thread.interrupted();
}
if (timeService.getCurrentMillis() - before >= startedTimeoutMilliseconds) {
guaranteeService.clearAllStartedInfo();
handleTimeout(startedTimeoutMilliseconds);
}
}
逻辑是,现在zk注册节点,判断是否全部注册成功,全部成功,默认为最后一个注册的节点,执行befor方法,这个在单点机器上是没有问题的,但是在分布式环境就有问题,如果两个机器,很巧合的同时判断自己是最后一个节点(因为zk是多线程,不能保证时序进入)进入zk节点判断,都会做befor操作,为了解决这个问题,思路如下(只有0片节点判断是否结束,执行监听操作):
循环: