Hystrix超时入口是在AbstractCommand类中,如图:
Observable<R> execution;
if (properties.executionTimeoutEnabled().get()) {
execution = executeCommandWithSpecifiedIsolation(_cmd)
.lift(new HystrixObservableTimeoutOperator<R>(_cmd));
} else {
execution = executeCommandWithSpecifiedIsolation(_cmd);
}
当我们的代码执行的时候会回调HystrixObservableTimeoutOperator.call()方法,超时的逻辑主要在这个方法中。
第一步:TimerListener listener = new TimerListener()创建了一个监听器,很明显这个监听器就是来监听我们的command是否超时的,那它是怎么判断我们的任务是否超时了呢?我们看他的tick()方法。
if(originalCommand.isCommandTimedOut.compareAndSet(TimedOutStatus.NOT_EXECUTED, TimedOutStatus.TIMED_OUT)) {
// report timeout failure
originalCommand.eventNotifier.markEvent(HystrixEventType.TIMEOUT, originalCommand.commandKey);
// shut down the original request
s.unsubscribe();
final HystrixContextRunnable timeoutRunnable = new HystrixContextRunnable(originalCommand.concurrencyStrategy, hystrixRequestContext, new Runnable() {
@Override
public void run() {
child.onError(new HystrixTimeoutException());
}
});
timeoutRunnable.run();
//if it did not start, then we need to mark a command start for concurrency metrics, and then issue the timeout
}
它的意思是,判断当前command的TimedOutStatus是否是NOT_EXECUTED,如果不是,则认为超时了,就把状态设置为TIMED_OUT,并抛出HystrixTimeoutException异常,如果是的话,则什么都不做。
第二步: final Reference<TimerListener> tl = HystrixTimer.getInstance().addTimerListener(listener);
获取单列的HystrixTimer,这里面维护了一个线程池ScheduledThreadPoolExecutor,我们老看看他的初始化方法initialize();
HystrixPropertiesStrategy propertiesStrategy = HystrixPlugins.getInstance().getPropertiesStrategy();
int coreSize = propertiesStrategy.getTimerThreadPoolProperties().getCorePoolSize().get();
ThreadFactory threadFactory = null;
if (!PlatformSpecific.isAppEngineStandardEnvironment()) {
threadFactory = new ThreadFactory() {
final AtomicInteger counter = new AtomicInteger();
@Override
public Thread newThread(Runnable r) {
Thread thread = new Thread(r, "HystrixTimer-" + counter.incrementAndGet());
thread.setDaemon(true);
return thread;
}
};
} else {
threadFactory = PlatformSpecific.getAppEngineThreadFactory();
}
executor = new ScheduledThreadPoolExecutor(coreSize, threadFactory);
initialized = true;
它构建了一个线程池ScheduledThreadPoolExecutor,默认的coreSize=8。
第三步:HystrixTimer.addTimerListener() 这个方法会把之前创建好的TimerListener加入HystrixTimer中,并把TimerListener.tick()封装为一个Runnable扔到线程池里。
public Reference<TimerListener> addTimerListener(final TimerListener listener) {
startThreadIfNeeded();
// add the listener
Runnable r = new Runnable() {
@Override
public void run() {
try {
listener.tick();
} catch (Exception e) {
logger.error("Failed while ticking TimerListener", e);
}
}
};
ScheduledFuture<?> f = executor.get().getThreadPool().scheduleAtFixedRate(r, listener.getIntervalTimeInMilliseconds(), listener.getIntervalTimeInMilliseconds(), TimeUnit.MILLISECONDS);
return new TimerReference(listener, f);
}
listener.getIntervalTimeInMilliseconds()这个参数就是我们设置的超时时间,所以这个任务会在我们设置的超时时间之后运行,来判断timedOutStatus的状态。
第四步:任务执行完了,怎么清理呢?看下面
private static class TimerReference extends SoftReference<TimerListener> {
private final ScheduledFuture<?> f;
TimerReference(TimerListener referent, ScheduledFuture<?> f) {
super(referent);
this.f = f;
}
@Override
public void clear() {
super.clear();
// stop this ScheduledFuture from any further executions
f.cancel(false);
}
}
f.cancel()就是清理Runnable的任务。
最后总结如图: