AbstractCommand

  HystrixCommand和HystrixObservableCommand的父类。每个command对应一个HystrixCommandKey、HystrixThreadPoolKey和HystrixCommandGroupKey。内部有HystrixCircuitBreaker、HystrixThreadPool、HystrixCommandProperties、HystrixCommandMetrics、HystrixCommandExecutionHook、HystrixConcurrencyStrategy、HystrixRequestCache、HystrixRequestLog、HystrixEventNotifier组件来实现各个功能。

构造函数

  创建时,首先初始化内部的各个组件对象。

  1. protected AbstractCommand(HystrixCommandGroupKey group, HystrixCommandKey key, HystrixThreadPoolKey threadPoolKey, HystrixCircuitBreaker circuitBreaker, HystrixThreadPool threadPool,
  2. HystrixCommandProperties.Setter commandPropertiesDefaults, HystrixThreadPoolProperties.Setter threadPoolPropertiesDefaults,
  3. HystrixCommandMetrics metrics, TryableSemaphore fallbackSemaphore, TryableSemaphore executionSemaphore,
  4. HystrixPropertiesStrategy propertiesStrategy, HystrixCommandExecutionHook executionHook) {
  5. this.commandGroup = initGroupKey(group);
  6. this.commandKey = initCommandKey(key, getClass());
  7. this.properties = initCommandProperties(this.commandKey, propertiesStrategy, commandPropertiesDefaults);
  8. this.threadPoolKey = initThreadPoolKey(threadPoolKey, this.commandGroup, this.properties.executionIsolationThreadPoolKeyOverride().get());
  9. this.metrics = initMetrics(metrics, this.commandGroup, this.threadPoolKey, this.commandKey, this.properties);
  10. this.circuitBreaker = initCircuitBreaker(this.properties.circuitBreakerEnabled().get(), circuitBreaker, this.commandGroup, this.commandKey, this.properties, this.metrics);
  11. this.threadPool = initThreadPool(threadPool, this.threadPoolKey, threadPoolPropertiesDefaults);
  12. //Strategies from plugins
  13. this.eventNotifier = HystrixPlugins.getInstance().getEventNotifier();
  14. this.concurrencyStrategy = HystrixPlugins.getInstance().getConcurrencyStrategy();
         //开始commandpublisher
  15. HystrixMetricsPublisherFactory.createOrRetrievePublisherForCommand(this.commandKey, this.commandGroup, this.metrics, this.circuitBreaker, this.properties);
  16. this.executionHook = initExecutionHook(executionHook);
  17. this.requestCache = HystrixRequestCache.getInstance(this.commandKey, this.concurrencyStrategy);
  18. this.currentRequestLog = initRequestLog(this.properties.requestLogEnabled().get(), this.concurrencyStrategy);
  19. /* 设置fallback的并发量 */
  20. this.fallbackSemaphoreOverride = fallbackSemaphore;
  21. /* 设置excution的并发量 */
  22. this.executionSemaphoreOverride = executionSemaphore;
  23. }

  通过HystrixPropertiesFactory获得指定commandKey的HystrixCommandProperties。

  1. private static HystrixCommandProperties initCommandProperties(HystrixCommandKey commandKey, HystrixPropertiesStrategy propertiesStrategy, HystrixCommandProperties.Setter commandPropertiesDefaults) {
  2. if (propertiesStrategy == null) {
  3. return HystrixPropertiesFactory.getCommandProperties(commandKey, commandPropertiesDefaults);
  4. } else {
  5. // used for unit testing
  6. return propertiesStrategy.getCommandProperties(commandKey, commandPropertiesDefaults);
  7. }
  8. }

  通过HystrixCommandMetrics获得指定commandKey的HystrixCommandMetrics。

  1. private static HystrixCommandMetrics initMetrics(HystrixCommandMetrics fromConstructor, HystrixCommandGroupKey groupKey,
  2. HystrixThreadPoolKey threadPoolKey, HystrixCommandKey commandKey,
  3. HystrixCommandProperties properties) {
  4. if (fromConstructor == null) {
  5. return HystrixCommandMetrics.getInstance(commandKey, groupKey, threadPoolKey, properties);
  6. } else {
  7. return fromConstructor;
  8. }
  9. }

  通过HystrixCircuitBreaker.Factory获得指定commandKey的HystrixCircuitBreaker。

  1. private static HystrixCircuitBreaker initCircuitBreaker(boolean enabled, HystrixCircuitBreaker fromConstructor,
  2. HystrixCommandGroupKey groupKey, HystrixCommandKey commandKey,
  3. HystrixCommandProperties properties, HystrixCommandMetrics metrics) {
  4. if (enabled) {
  5. if (fromConstructor == null) {
  6. // get the default implementation of HystrixCircuitBreaker
  7. return HystrixCircuitBreaker.Factory.getInstance(commandKey, groupKey, properties, metrics);
  8. } else {
  9. return fromConstructor;
  10. }
  11. } else {
  12. return new NoOpCircuitBreaker();
  13. }
  14. }

  通过HystrixThreadPool.Factory获得指定threadPoolKey的HystrixThreadPool。

  1. private static HystrixThreadPool initThreadPool(HystrixThreadPool fromConstructor, HystrixThreadPoolKey threadPoolKey, HystrixThreadPoolProperties.Setter threadPoolPropertiesDefaults) {
  2. if (fromConstructor == null) {
  3. // get the default implementation of HystrixThreadPool
  4. return HystrixThreadPool.Factory.getInstance(threadPoolKey, threadPoolPropertiesDefaults);
  5. } else {
  6. return fromConstructor;
  7. }
  8. }

  通过HystrixPlugins获得自定义插架HystrixCommandExecutionHook。

  1. private static HystrixCommandExecutionHook initExecutionHook(HystrixCommandExecutionHook fromConstructor) {
  2. if (fromConstructor == null) {
  3. return new ExecutionHookDeprecationWrapper(HystrixPlugins.getInstance().getCommandExecutionHook());
  4. } else {
  5. // used for unit testing
  6. if (fromConstructor instanceof ExecutionHookDeprecationWrapper) {
  7. return fromConstructor;
  8. } else {
  9. return new ExecutionHookDeprecationWrapper(fromConstructor);
  10. }
  11. }
  12. }

  通过HystrixPlugins获得自定义插架HystrixEventNotifier、HystrixConcurrencyStrategy。

  1. this.eventNotifier = HystrixPlugins.getInstance().getEventNotifier();
  2. this.concurrencyStrategy = HystrixPlugins.getInstance().getConcurrencyStrategy();

  通过HystrixRequestCache获得指定commandKey的HystrixRequestCache。

  1. this.requestCache = HystrixRequestCache.getInstance(this.commandKey, this.concurrencyStrategy);

  通过HystrixRequestLog获得当前的HystrixRequestLog。

  1. private static HystrixRequestLog initRequestLog(boolean enabled, HystrixConcurrencyStrategy concurrencyStrategy) {
  2. if (enabled) {
  3. /* store reference to request log regardless of which thread later hits it */
  4. return HystrixRequestLog.getCurrentRequest(concurrencyStrategy);
  5. } else {
  6. return null;
  7. }
  8. }

observe方法

  使用了ReplaySubject缓存了toObservable的消息,使得执行后再监听也可以收到所有消息。

  1. public Observable<R> observe() {
  2. // us a ReplaySubject to buffer the eagerly subscribed-to Observable
  3. ReplaySubject<R> subject = ReplaySubject.create();
  4. // eagerly kick off subscription
  5. final Subscription sourceSubscription = toObservable().subscribe(subject);
  6. // return the subject that can be subscribed to later while the execution has already started
  7. return subject.doOnUnsubscribe(new Action0() {
  8. @Override
  9. public void call() {
  10. sourceSubscription.unsubscribe();
  11. }
  12. });
  13. }

toObservable方法

  1. public Observable<R> toObservable() {
         ...
    return Observable.defer(new Func0<Observable<R>>() {
  2. @Override
  3. public Observable<R> call() {
  4. /* 每个command对象,只能被执行一次 */
  5. if (!commandState.compareAndSet(CommandState.NOT_STARTED, CommandState.OBSERVABLE_CHAIN_CREATED)) {
  6. IllegalStateException ex = new IllegalStateException("This instance can only be executed once. Please instantiate a new instance.");
  7. //TODO make a new error type for this
  8. throw new HystrixRuntimeException(FailureType.BAD_REQUEST_EXCEPTION, _cmd.getClass(), getLogMessagePrefix() + " command executed multiple times - this is not permitted.", ex, null);
  9. }
  10.  
  11. commandStartTimestamp = System.currentTimeMillis();
  12.          //如果开启了记录请求,则向HystrixRequestLog添加执行命令
  13. if (properties.requestLogEnabled().get()) {
  14. // log this command execution regardless of what happened
  15. if (currentRequestLog != null) {
  16. currentRequestLog.addExecutedCommand(_cmd);
  17. }
  18. }
             //是否开启缓存,如果开启缓存并且实现了getCacheKey方法,则首先从HystrixRequestCache获取结果数据
  19. final boolean requestCacheEnabled = isRequestCachingEnabled();
  20. final String cacheKey = getCacheKey();
  21. /* try from cache first */
  22. if (requestCacheEnabled) {
  23. HystrixCommandResponseFromCache<R> fromCache = (HystrixCommandResponseFromCache<R>) requestCache.get(cacheKey);
  24. if (fromCache != null) {
  25. isResponseFromCache = true;
  26. return handleRequestCacheHitAndEmitValues(fromCache, _cmd);
  27. }
  28. }
  29.          //执行命令返回结果
  30. Observable<R> hystrixObservable =
  31. Observable.defer(applyHystrixSemantics)
  32. .map(wrapWithAllOnNextHooks);
  33.  
  34. Observable<R> afterCache;
  35.               
  36. // 是否开启缓存,如果开启缓存并且实现了getCacheKey方法,将结果放到HystrixRequestCache
  37. if (requestCacheEnabled && cacheKey != null) {
  38. // wrap it for caching
  39. HystrixCachedObservable<R> toCache = HystrixCachedObservable.from(hystrixObservable, _cmd);
  40. HystrixCommandResponseFromCache<R> fromCache = (HystrixCommandResponseFromCache<R>) requestCache.putIfAbsent(cacheKey, toCache);
  41. if (fromCache != null) {
  42. // another thread beat us so we'll use the cached value instead
  43. toCache.unsubscribe();
  44. isResponseFromCache = true;
  45. return handleRequestCacheHitAndEmitValues(fromCache, _cmd);
  46. } else {
  47. // we just created an ObservableCommand so we cast and return it
  48. afterCache = toCache.toObservable();
  49. }
  50. } else {
  51. afterCache = hystrixObservable;
  52. }
  53.  
  54. return afterCache
  55. .doOnTerminate(terminateCommandCleanup) // perform cleanup once (either on normal terminal state (this line), or unsubscribe (next line))
  56. .doOnUnsubscribe(unsubscribeCommandCleanup) // perform cleanup once
  57. .doOnCompleted(fireOnCompletedHook);
  58. }
  59. });
  60. }

  在获取缓存结束后,需要更新command状态,记录执行时间,输出metrics,发送消息。

  1. private Observable<R> handleRequestCacheHitAndEmitValues(final HystrixCommandResponseFromCache<R> fromCache, final AbstractCommand<R> _cmd) {
  2. try {
  3. executionHook.onCacheHit(this);
  4. } catch (Throwable hookEx) {
  5. logger.warn("Error calling HystrixCommandExecutionHook.onCacheHit", hookEx);
  6. }
  7.  
  8. return fromCache.toObservableWithStateCopiedInto(this)
  9. .doOnTerminate(new Action0() {
  10. @Override
  11. public void call() {
  12. if (commandState.compareAndSet(CommandState.OBSERVABLE_CHAIN_CREATED, CommandState.TERMINAL)) {
  13. cleanUpAfterResponseFromCache(false); //user code never ran
  14. } else if (commandState.compareAndSet(CommandState.USER_CODE_EXECUTED, CommandState.TERMINAL)) {
  15. cleanUpAfterResponseFromCache(true); //user code did run
  16. }
  17. }
  18. })
  19. .doOnUnsubscribe(new Action0() {
  20. @Override
  21. public void call() {
  22. if (commandState.compareAndSet(CommandState.OBSERVABLE_CHAIN_CREATED, CommandState.UNSUBSCRIBED)) {
  23. cleanUpAfterResponseFromCache(false); //user code never ran
  24. } else if (commandState.compareAndSet(CommandState.USER_CODE_EXECUTED, CommandState.UNSUBSCRIBED)) {
  25. cleanUpAfterResponseFromCache(true); //user code did run
  26. }
  27. }
  28. });
  29. }
  30.  
  31. private void cleanUpAfterResponseFromCache(boolean commandExecutionStarted) {
  32. Reference<TimerListener> tl = timeoutTimer.get();
  33. if (tl != null) {
  34. tl.clear();
  35. }
  36.  
  37. final long latency = System.currentTimeMillis() - commandStartTimestamp;
  38. executionResult = executionResult
  39. .addEvent(-1, HystrixEventType.RESPONSE_FROM_CACHE)
  40. .markUserThreadCompletion(latency)
  41. .setNotExecutedInThread();
  42. ExecutionResult cacheOnlyForMetrics = ExecutionResult.from(HystrixEventType.RESPONSE_FROM_CACHE)
  43. .markUserThreadCompletion(latency);
  44. metrics.markCommandDone(cacheOnlyForMetrics, commandKey, threadPoolKey, commandExecutionStarted);
  45. eventNotifier.markEvent(HystrixEventType.RESPONSE_FROM_CACHE, commandKey);
  46. }

  在如果不是通过缓存在结束后,也需要更新command状态,记录执行时间,输出metrics,发送消息。

  1. final Action0 terminateCommandCleanup = new Action0() {
  2.  
  3. @Override
  4. public void call() {
  5. if (_cmd.commandState.compareAndSet(CommandState.OBSERVABLE_CHAIN_CREATED, CommandState.TERMINAL)) {
  6. handleCommandEnd(false); //user code never ran
  7. } else if (_cmd.commandState.compareAndSet(CommandState.USER_CODE_EXECUTED, CommandState.TERMINAL)) {
  8. handleCommandEnd(true); //user code did run
  9. }
  10. }
  11. };
  12. final Action0 unsubscribeCommandCleanup = new Action0() {
  13. @Override
  14. public void call() {
  15. circuitBreaker.markNonSuccess();
  16. if (_cmd.commandState.compareAndSet(CommandState.OBSERVABLE_CHAIN_CREATED, CommandState.UNSUBSCRIBED)) {
  17. if (!_cmd.executionResult.containsTerminalEvent()) {
  18. _cmd.eventNotifier.markEvent(HystrixEventType.CANCELLED, _cmd.commandKey);
  19. try {
  20. executionHook.onUnsubscribe(_cmd);
  21. } catch (Throwable hookEx) {
  22. logger.warn("Error calling HystrixCommandExecutionHook.onUnsubscribe", hookEx);
  23. }
  24. _cmd.executionResultAtTimeOfCancellation = _cmd.executionResult
  25. .addEvent((int) (System.currentTimeMillis() - _cmd.commandStartTimestamp), HystrixEventType.CANCELLED);
  26. }
  27. handleCommandEnd(false); //user code never ran
  28. } else if (_cmd.commandState.compareAndSet(CommandState.USER_CODE_EXECUTED, CommandState.UNSUBSCRIBED)) {
  29. if (!_cmd.executionResult.containsTerminalEvent()) {
  30. _cmd.eventNotifier.markEvent(HystrixEventType.CANCELLED, _cmd.commandKey);
  31. try {
  32. executionHook.onUnsubscribe(_cmd);
  33. } catch (Throwable hookEx) {
  34. logger.warn("Error calling HystrixCommandExecutionHook.onUnsubscribe", hookEx);
  35. }
  36. _cmd.executionResultAtTimeOfCancellation = _cmd.executionResult
  37. .addEvent((int) (System.currentTimeMillis() - _cmd.commandStartTimestamp), HystrixEventType.CANCELLED);
  38. }
  39. handleCommandEnd(true); //user code did run
  40. }
  41. }
  42. };
  43. final Action0 fireOnCompletedHook = new Action0() {
  44. @Override
  45. public void call() {
  46. try {
  47. executionHook.onSuccess(_cmd);
  48. } catch (Throwable hookEx) {
  49. logger.warn("Error calling HystrixCommandExecutionHook.onSuccess", hookEx);
  50. }
  51. }
  52. };
  53. private void handleCommandEnd(boolean commandExecutionStarted) {
  54. Reference<TimerListener> tl = timeoutTimer.get();
  55. if (tl != null) {
  56. tl.clear();
  57. }
  58.  
  59. long userThreadLatency = System.currentTimeMillis() - commandStartTimestamp;
  60. executionResult = executionResult.markUserThreadCompletion((int) userThreadLatency);
  61. if (executionResultAtTimeOfCancellation == null) {
  62. metrics.markCommandDone(executionResult, commandKey, threadPoolKey, commandExecutionStarted);
  63. } else {
  64. metrics.markCommandDone(executionResultAtTimeOfCancellation, commandKey, threadPoolKey, commandExecutionStarted);
  65. }
  66.  
  67. if (endCurrentThreadExecutingCommand != null) {
  68. endCurrentThreadExecutingCommand.call();
  69. }
  70. }

  如果没有获取到缓存,则需要执行命令获得结果。命令执行流程如下:

  1. private Observable<R> applyHystrixSemantics(final AbstractCommand<R> _cmd) {// executionHook调用
  2. executionHook.onStart(_cmd);
  3. /* determine if we're allowed to execute */
  4. if (circuitBreaker.attemptExecution()) { //使用熔断器判断是否熔断
  5. final TryableSemaphore executionSemaphore = getExecutionSemaphore();
  6. final AtomicBoolean semaphoreHasBeenReleased = new AtomicBoolean(false);
  7. final Action0 singleSemaphoreRelease = new Action0() {
  8. @Override
  9. public void call() {
  10. if (semaphoreHasBeenReleased.compareAndSet(false, true)) {
  11. executionSemaphore.release();
  12. }
  13. }
  14. };
  15.  
  16. final Action1<Throwable> markExceptionThrown = new Action1<Throwable>() {
  17. @Override
  18. public void call(Throwable t) {
  19. eventNotifier.markEvent(HystrixEventType.EXCEPTION_THROWN, commandKey);
  20. }
  21. };
  22.  
  23. if (executionSemaphore.tryAcquire()) {//执行并发信号量
  24. try {
  25. /* used to track userThreadExecutionTime */
  26. executionResult = executionResult.setInvocationStartTime(System.currentTimeMillis());
  27. return executeCommandAndObserve(_cmd) //执行命令
  28. .doOnError(markExceptionThrown)
  29. .doOnTerminate(singleSemaphoreRelease)
  30. .doOnUnsubscribe(singleSemaphoreRelease);
  31. } catch (RuntimeException e) {
  32. return Observable.error(e);
  33. }
  34. } else {
  35. return handleSemaphoreRejectionViaFallback();//超过并发信号量fallback
  36. }
  37. } else {
  38. return handleShortCircuitViaFallback();//执行熔断fallback
  39. }
  40. }

executeCommandAndObserve方法

 调用命令方法执行,并对执行的各种事件进行响应。

  1. Observable<R> execution;
  2. if (properties.executionTimeoutEnabled().get()) {
  3. execution = executeCommandWithSpecifiedIsolation(_cmd)
  4. .lift(new HystrixObservableTimeoutOperator<R>(_cmd));
  5. } else {
  6. execution = executeCommandWithSpecifiedIsolation(_cmd);
  7. }
  8.  
  9. return execution.doOnNext(markEmits)
  10. .doOnCompleted(markOnCompleted)
  11. .onErrorResumeNext(handleFallback)
  12. .doOnEach(setRequestContext);

  命令返回数据时

  1. final Action1<R> markEmits = new Action1<R>() {
  2. @Override
  3. public void call(R r) {
  4. if (shouldOutputOnNextEvents()) {
  5. executionResult = executionResult.addEvent(HystrixEventType.EMIT);
  6. eventNotifier.markEvent(HystrixEventType.EMIT, commandKey);//发送emit事件
  7. }
  8. if (commandIsScalar()) {
  9. long latency = System.currentTimeMillis() - executionResult.getStartTimestamp();
  10. eventNotifier.markEvent(HystrixEventType.SUCCESS, commandKey);//发送SUCCESS事件
  11. executionResult = executionResult.addEvent((int) latency, HystrixEventType.SUCCESS);
  12. eventNotifier.markCommandExecution(getCommandKey(), properties.executionIsolationStrategy().get(), (int) latency, executionResult.getOrderedList());
  13. circuitBreaker.markSuccess();
  14. }
  15. }
  16. };

   命令完成时

  1. final Action0 markOnCompleted = new Action0() {
  2. @Override
  3. public void call() {
  4. if (!commandIsScalar()) {
  5. long latency = System.currentTimeMillis() - executionResult.getStartTimestamp();
  6. eventNotifier.markEvent(HystrixEventType.SUCCESS, commandKey);
  7. executionResult = executionResult.addEvent((int) latency, HystrixEventType.SUCCESS);
  8. eventNotifier.markCommandExecution(getCommandKey(), properties.executionIsolationStrategy().get(), (int) latency, executionResult.getOrderedList());
  9. circuitBreaker.markSuccess();
  10. }
  11. }
  12. };

  命令出现异常时

  1. final Func1<Throwable, Observable<R>> handleFallback = new Func1<Throwable, Observable<R>>() {
  2. @Override
  3. public Observable<R> call(Throwable t) {
  4. circuitBreaker.markNonSuccess();
  5. Exception e = getExceptionFromThrowable(t);
  6. executionResult = executionResult.setExecutionException(e);
  7. if (e instanceof RejectedExecutionException) {
  8. return handleThreadPoolRejectionViaFallback(e);
  9. } else if (t instanceof HystrixTimeoutException) {
  10. return handleTimeoutViaFallback();
  11. } else if (t instanceof HystrixBadRequestException) {
  12. return handleBadRequestByEmittingError(e);
  13. } else {
  14. /*
  15. * Treat HystrixBadRequestException from ExecutionHook like a plain HystrixBadRequestException.
  16. */
  17. if (e instanceof HystrixBadRequestException) {
  18. eventNotifier.markEvent(HystrixEventType.BAD_REQUEST, commandKey);
  19. return Observable.error(e);
  20. }
  21. return handleFailureViaFallback(e);
  22. }
  23. }
  24. };

handleThreadPoolRejectionViaFallback、handleTimeoutViaFallback、handleBadRequestByEmittingError、handleFailureViaFallback地层都调用了getFallbackOrThrowException方法。

  1. private Observable<R> handleThreadPoolRejectionViaFallback(Exception underlying) {
  2. eventNotifier.markEvent(HystrixEventType.THREAD_POOL_REJECTED, commandKey);
  3. threadPool.markThreadRejection();
  4. return getFallbackOrThrowException(this, HystrixEventType.THREAD_POOL_REJECTED, FailureType.REJECTED_THREAD_EXECUTION, "could not be queued for execution", underlying);
  5. }
  6. private Observable<R> handleTimeoutViaFallback() {
  7. return getFallbackOrThrowException(this, HystrixEventType.TIMEOUT, FailureType.TIMEOUT, "timed-out", new TimeoutException());
  8. }
  9. private Observable<R> handleBadRequestByEmittingError(Exception underlying) {
  10. Exception toEmit = underlying;
  11. try {
  12. long executionLatency = System.currentTimeMillis() - executionResult.getStartTimestamp();
  13. eventNotifier.markEvent(HystrixEventType.BAD_REQUEST, commandKey);
  14. executionResult = executionResult.addEvent((int) executionLatency, HystrixEventType.BAD_REQUEST);
  15. Exception decorated = executionHook.onError(this, FailureType.BAD_REQUEST_EXCEPTION, underlying);
  16. if (decorated instanceof HystrixBadRequestException) {
  17. toEmit = decorated;
  18. } else {
  19. logger.warn("ExecutionHook.onError returned an exception that was not an instance of HystrixBadRequestException so will be ignored.", decorated);
  20. }
  21. } catch (Exception hookEx) {
  22. logger.warn("Error calling HystrixCommandExecutionHook.onError", hookEx);
  23. }
  24. return Observable.error(toEmit);
  25. }
  26.  
  27. private Observable<R> handleFailureViaFallback(Exception underlying) {// report failure
  28. eventNotifier.markEvent(HystrixEventType.FAILURE, commandKey);
  29. // record the exception
  30. executionResult = executionResult.setException(underlying);
  31. return getFallbackOrThrowException(this, HystrixEventType.FAILURE, FailureType.COMMAND_EXCEPTION, "failed", underlying);
  32. }

getFallbackOrThrowException

  核心就是调用用户定义的fallback方法,并在各自情况下调用eventNotifier事件和返回executionResult。

  1. ...
  2. if (fallbackSemaphore.tryAcquire()) {
  3. try {
  4. if (isFallbackUserDefined()) {
  5. executionHook.onFallbackStart(this);
  6. fallbackExecutionChain = getFallbackObservable();
  7. } else {
  8. //same logic as above without the hook invocation
  9. fallbackExecutionChain = getFallbackObservable();
  10. }
  11. } catch (Throwable ex) {
  12. //If hook or user-fallback throws, then use that as the result of the fallback lookup
  13. fallbackExecutionChain = Observable.error(ex);
  14. }
  15.  
  16. return fallbackExecutionChain
  17. .doOnEach(setRequestContext)
  18. .lift(new FallbackHookApplication(_cmd))
  19. .doOnNext(markFallbackEmit)
  20. .doOnCompleted(markFallbackCompleted)
  21. .onErrorResumeNext(handleFallbackError)
  22. .doOnTerminate(singleSemaphoreRelease)
  23. .doOnUnsubscribe(singleSemaphoreRelease);
  24. } else {
  25. return handleFallbackRejectionByEmittingError();
  26. }
  27. ...

timeout实现

  1. private static class HystrixObservableTimeoutOperator<R> implements Operator<R, R> {
  2.  
  3. final AbstractCommand<R> originalCommand;
  4.  
  5. public HystrixObservableTimeoutOperator(final AbstractCommand<R> originalCommand) {
  6. this.originalCommand = originalCommand;
  7. }
  8.  
  9. @Override
  10. public Subscriber<? super R> call(final Subscriber<? super R> child) {
  11. final CompositeSubscription s = new CompositeSubscription();
  12. // if the child unsubscribes we unsubscribe our parent as well
  13. child.add(s);
  14.  
  15. //capture the HystrixRequestContext upfront so that we can use it in the timeout thread later
  16. final HystrixRequestContext hystrixRequestContext = HystrixRequestContext.getContextForCurrentThread();
  17.  
  18. TimerListener listener = new TimerListener() {
  19.  
  20. @Override
  21. public void tick() {
  22. // if we can go from NOT_EXECUTED to TIMED_OUT then we do the timeout codepath
  23. // otherwise it means we lost a race and the run() execution completed or did not start
  24. if (originalCommand.isCommandTimedOut.compareAndSet(TimedOutStatus.NOT_EXECUTED, TimedOutStatus.TIMED_OUT)) {
  25. // report timeout failure
  26. originalCommand.eventNotifier.markEvent(HystrixEventType.TIMEOUT, originalCommand.commandKey);
  27.  
  28. // shut down the original request
  29. s.unsubscribe();
  30.  
  31. final HystrixContextRunnable timeoutRunnable = new HystrixContextRunnable(originalCommand.concurrencyStrategy, hystrixRequestContext, new Runnable() {
  32.  
  33. @Override
  34. public void run() {
  35. child.onError(new HystrixTimeoutException());
  36. }
  37. });
  38.  
  39. timeoutRunnable.run();
  40. //if it did not start, then we need to mark a command start for concurrency metrics, and then issue the timeout
  41. }
  42. }
  43.  
  44. @Override
  45. public int getIntervalTimeInMilliseconds() {
  46. return originalCommand.properties.executionTimeoutInMilliseconds().get();
  47. }
  48. };
  49.  
  50. final Reference<TimerListener> tl = HystrixTimer.getInstance().addTimerListener(listener);
  51.  
  52. // set externally so execute/queue can see this
  53. originalCommand.timeoutTimer.set(tl);
  54.  
  55. /**
  56. * If this subscriber receives values it means the parent succeeded/completed
  57. */
  58. Subscriber<R> parent = new Subscriber<R>() {
  59.  
  60. @Override
  61. public void onCompleted() {
  62. if (isNotTimedOut()) {
  63. // stop timer and pass notification through
  64. tl.clear();
  65. child.onCompleted();
  66. }
  67. }
  68.  
  69. @Override
  70. public void onError(Throwable e) {
  71. if (isNotTimedOut()) {
  72. // stop timer and pass notification through
  73. tl.clear();
  74. child.onError(e);
  75. }
  76. }
  77.  
  78. @Override
  79. public void onNext(R v) {
  80. if (isNotTimedOut()) {
  81. child.onNext(v);
  82. }
  83. }
  84.  
  85. private boolean isNotTimedOut() {
  86. // if already marked COMPLETED (by onNext) or succeeds in setting to COMPLETED
  87. return originalCommand.isCommandTimedOut.get() == TimedOutStatus.COMPLETED ||
  88. originalCommand.isCommandTimedOut.compareAndSet(TimedOutStatus.NOT_EXECUTED, TimedOutStatus.COMPLETED);
  89. }
  90.  
  91. };
  92.  
  93. // if s is unsubscribed we want to unsubscribe the parent
  94. s.add(parent);
  95.  
  96. return parent;
  97. }
  98.  
  99. }

executeCommandWithSpecifiedIsolation方法

  真正执行命令的方法,有两种方式执行,一种是使用线程池执行,一种是使用当前线程执行。

  1. private Observable<R> executeCommandWithSpecifiedIsolation(final AbstractCommand<R> _cmd) {
  2. if (properties.executionIsolationStrategy().get() == ExecutionIsolationStrategy.THREAD) {
  3. //使用线程池执行
  4. return Observable.defer(new Func0<Observable<R>>() {
  5. @Override
  6. public Observable<R> call() {
  7. executionResult = executionResult.setExecutionOccurred();
  8. if (!commandState.compareAndSet(CommandState.OBSERVABLE_CHAIN_CREATED, CommandState.USER_CODE_EXECUTED)) {
  9. return Observable.error(new IllegalStateException("execution attempted while in state : " + commandState.get().name()));
  10. }
  11.  
  12. metrics.markCommandStart(commandKey, threadPoolKey, ExecutionIsolationStrategy.THREAD);//调用命令开始执行metrics
  13.  
  14. if (isCommandTimedOut.get() == TimedOutStatus.TIMED_OUT) {
  15. // the command timed out in the wrapping thread so we will return immediately
  16. // and not increment any of the counters below or other such logic
  17. return Observable.error(new RuntimeException("timed out before executing run()"));
  18. }
  19. if (threadState.compareAndSet(ThreadState.NOT_USING_THREAD, ThreadState.STARTED)) {//修改threadState状态
  20. //we have not been unsubscribed, so should proceed
  21. HystrixCounters.incrementGlobalConcurrentThreads();
  22. threadPool.markThreadExecution(); //调用线程池开始方法metrics
  23. // store the command that is being run
  24. endCurrentThreadExecutingCommand = Hystrix.startCurrentThreadExecutingCommand(getCommandKey());
  25. executionResult = executionResult.setExecutedInThread();//设置在线程池中执行
  26. try {
  27. executionHook.onThreadStart(_cmd);//调用hook的onThread
  28. executionHook.onRunStart(_cmd);//调用hook的onRunStart
  29. executionHook.onExecutionStart(_cmd);//调用hook的onExecutionStart
  30. return getUserExecutionObservable(_cmd);
  31. } catch (Throwable ex) {
  32. return Observable.error(ex);
  33. }
  34. } else {
  35. //command has already been unsubscribed, so return immediately
  36. return Observable.empty();
  37. }
  38. }
  39. }).doOnTerminate(new Action0() {
  40. @Override
  41. public void call() {
  42. if (threadState.compareAndSet(ThreadState.STARTED, ThreadState.TERMINAL)) {
  43. handleThreadEnd(_cmd);
  44. }
  45. if (threadState.compareAndSet(ThreadState.NOT_USING_THREAD, ThreadState.TERMINAL)) {
  46. //if it was never started and received terminal, then no need to clean up (I don't think this is possible)
  47. }
  48. //if it was unsubscribed, then other cleanup handled it
  49. }
  50. }).doOnUnsubscribe(new Action0() {
  51. @Override
  52. public void call() {
  53. if (threadState.compareAndSet(ThreadState.STARTED, ThreadState.UNSUBSCRIBED)) {
  54. handleThreadEnd(_cmd);
  55. }
  56. if (threadState.compareAndSet(ThreadState.NOT_USING_THREAD, ThreadState.UNSUBSCRIBED)) {
  57. //if it was never started and was cancelled, then no need to clean up
  58. }
  59. //if it was terminal, then other cleanup handled it
  60. }
  61. }).subscribeOn(threadPool.getScheduler(new Func0<Boolean>() {//使用线程池执行
  62. @Override
  63. public Boolean call() {
  64. return properties.executionIsolationThreadInterruptOnTimeout().get() && _cmd.isCommandTimedOut.get() == TimedOutStatus.TIMED_OUT;
  65. }
  66. }));
  67. } else {
  68. return Observable.defer(new Func0<Observable<R>>() {
  69. @Override
  70. public Observable<R> call() {
  71. executionResult = executionResult.setExecutionOccurred();
  72. if (!commandState.compareAndSet(CommandState.OBSERVABLE_CHAIN_CREATED, CommandState.USER_CODE_EXECUTED)) {
  73. return Observable.error(new IllegalStateException("execution attempted while in state : " + commandState.get().name()));
  74. }
  75. metrics.markCommandStart(commandKey, threadPoolKey, ExecutionIsolationStrategy.SEMAPHORE);//调用命令开始执行metrics
  76. // semaphore isolated
  77. // store the command that is being run
  78. endCurrentThreadExecutingCommand = Hystrix.startCurrentThreadExecutingCommand(getCommandKey());
  79. try {
  80. executionHook.onRunStart(_cmd);//调用hook的onRunStart
  81. executionHook.onExecutionStart(_cmd);//调用hook的onExecutionStart
  82. return getUserExecutionObservable(_cmd); //the getUserExecutionObservable method already wraps sync exceptions, so this shouldn't throw
  83. } catch (Throwable ex) {
  84. //If the above hooks throw, then use that as the result of the run method
  85. return Observable.error(ex);
  86. }
  87. }
  88. });
  89. }
  90. }

 

hystrix源码之AbstractCommand的更多相关文章

  1. Hystrix源码解析

    1. Hystrix源码解析 1.1. @HystrixCommand原理 直接通过Aspect切面来做的 1.2. feign hystrix原理 它的本质原理就是对HystrixCommand的动 ...

  2. 【一起学源码-微服务】Hystrix 源码一:Hystrix基础原理与Demo搭建

    说明 原创不易,如若转载 请标明来源! 欢迎关注本人微信公众号:壹枝花算不算浪漫 更多内容也可查看本人博客:一枝花算不算浪漫 前言 前情回顾 上一个系列文章讲解了Feign的源码,主要是Feign动态 ...

  3. hystrix源码之概述

    概述 hystrix核心原理是通过代理执行用户命令,记录命令执行的metrics信息,通过这些metrics信息进行降级和熔断. 源码结构包括一下几个部分: 熔断器 熔断器就是hystrix用来判断调 ...

  4. 【一起学源码-微服务】Hystrix 源码二:Hystrix核心流程:Hystix非降级逻辑流程梳理

    说明 原创不易,如若转载 请标明来源! 欢迎关注本人微信公众号:壹枝花算不算浪漫 更多内容也可查看本人博客:一枝花算不算浪漫 前言 前情回顾 上一讲我们讲了配置了feign.hystrix.enabl ...

  5. 【一起学源码-微服务】Hystrix 源码三:Hystrix核心流程:Hystix降级、熔断等原理剖析

    说明 原创不易,如若转载 请标明来源! 欢迎关注本人微信公众号:壹枝花算不算浪漫 更多内容也可查看本人博客:一枝花算不算浪漫 前言 前情回顾 上一讲我们讲解了Hystrix在配合feign的过程中,一 ...

  6. hystrix 源码分析以及属性的配置

    一.feign与hystix结合 1.1测试环境搭建 架构如图: 非常简单,就是Order服务通过feign调用product服务的一个获取商品信息的一个接口: package com.yang.xi ...

  7. Feign整合Ribbon和Hystrix源码解析

    在上篇文章Feign自动装配中,我们提到了Feign的自动装配的原理,以及Feign整合Ribbon和Hystrix的核心在类FeignClientFactoryBean中,那么本篇文章就来揭开这个类 ...

  8. hystrix源码小贴士之之hystrix-metrics-event-stream

    hystrix-metrics-event-stream主要提供了一些servlet,可以让用户通过http请求获取metrics信息. HystrixSampleSseServlet 继承了Http ...

  9. hystrix源码小贴士之调用异常处理

    executeCommandAndObserve方法处理onerror异常. return execution.doOnNext(markEmits) .doOnCompleted(markOnCom ...

随机推荐

  1. Markdown实验样例

    一级标题 二级标题 三级标题 重新开始一个段落 这是新的段落 斜体文本 粗体文本 粗斜体文本 下面是分隔线 删除线 下划线 脚注[1] 无序列表 第一项 嵌套元素1 嵌套元素2 第二项 嵌套元素1 嵌 ...

  2. python 05 列表 元组 (序列)

    循环(loop),指的是在满足条件的情况下,重复执行同一段代码.比如,while语句. [ 循环则技能对应集合,列表,数组等,也能对执行代码进行操作.] 迭代(iterate),指的是按照某种顺序逐个 ...

  3. JavaScript学习系列博客_26_JavaScript 数组的一些方法

    数组的一些方法 - push() - 用来向数组的末尾添加一个或多个元素,并返回数组新的长度 - 语法:数组.push(元素1,元素2,元素N) - pop() - 用来删除数组的最后一个元素,并返回 ...

  4. ucore学习

    1.启动操作系统的bootloader,用于了解操作系统启动前的状态和要做的准备工作,了解运行操作系统的硬件支持,操作系统如何加载到内存中,理解两类中断--"外设中断"," ...

  5. linux 使用 FIO 测试磁盘的iops

    原文链接:https://www.iteye.com/blog/elf8848-2168876 一,FIO安装wget http://brick.kernel.dk/snaps/fio-2.2.5.t ...

  6. 文华财经赢顺外盘期货行情数据API接口开放代码

    文华财经赢顺外盘期货行情数据API接口开放代码        怎么才能获取到外盘期货行情数据API接口呢?不少朋友就会考虑到文华财经行情API接口,本身文华财经就是一个软件提供商,提供行情API接口也 ...

  7. Git仓库由HTTPS切换成ssh秘钥连接

    Git关联远程仓库可以使用https协议或者ssh协议. [特点/优缺点] ssh: 一般使用22端口: 通过先在本地生成SSH密钥对再把公钥上传到服务器: 速度较慢点 https: 一般使用443端 ...

  8. 使用Seq搭建免费的日志服务

    Seq简介 Seq是老外开发的一个针对.NET平台非常友好的日志服务.支持容器部署,提供一个单用户免费的开发版本. 官网:https://datalust.co/seq 使用文档:https://do ...

  9. Kubernetes Operator基础入门

    本文转自Rancher Labs 你是否曾经想过SRE团队是如何有效地成功管理复杂的应用?在Kubernetes生态系统中,Kubernetes Operator可以给你答案.在本文中,我们将研究Op ...

  10. React的几种组件

    一.函数组件 该函数在React中是一个有效的组件,可以接收唯一带有数据的props(代表属性)对象,并返回一个React元素.函数式组件要特别注意,组件名称首字母一定要大写.这种方式也成为无状态组件 ...