This is the 14th day of my participation in Gwen Challenge
[a].
You may have a bad day, but that doesn’t mean you’ll have a bad life.
[Warm tips]
Continue from the previous article 🏹 “Hystrix” (2) parameter configuration details
-
I recommend it heremartinfowlerFuse introduction and authoritative guide, interested partners can study ha.
-
Main introduction related: official website description
-
about[How Hystrix works]The introduction of
[Background]
-
As the scale and complexity of distributed systems increase, the requirements for availability of distributed systems become higher and higher. Among the various high availability design patterns, “fuses, isolation, downgrades, limiting” are frequently used. The related technology, Hystrix itself is not a new technology, but it is the most classic technology system! .
-
Hystrix is designed to achieve fusible downgrades, thus improving system availability.
-
Hystrix is a Java service component library that implements circuit breaker mode and hatch mode on the call side to improve system fault tolerance by avoiding cascading failures for highly available designs.
-
Hystrix implements a resource isolation mechanism
The premise is introduced
Hystrix’s timeout detection is essentially done by starting a separate thread that executes exactly as long as the task has timed out, which is essentially a simple logic.
Hystrix times out and throws a HystrixTimeoutException.
Timeout detection logic
Hystrix timeouts include the registration process and the execution process. The registration process is as follows:
-
Perform lift (new HystrixObservableTimeoutOperator (_cmd) connection timeout detection task.
-
HystrixObservableTimeoutOperator class, the new TimerListener () is responsible for creating test task, Hystrixtimer.getinstance ().addtimerListener (listener) Associates scheduled tasks.
- In HystrixObservableTimeoutOperator class, addTimerListener through Java timing task services scheduleAtFixedRate execution after the timeout time delay.
Hystrix’s timeout execution process is as follows:
-
The tick method of class TimerListener is executed after the listener.tick() method is executed after the timeout
-
Execute the HystrixContextRunnable run method after executing timeoutrunable.run () in the tick method of the TimerListener class
-
Execute child.onError(new HystrixTimeoutException()) in the HystrixContextRunnable class run method to implement the timeout.
-
executeCommandWithSpecifiedIsolation(_cmd).lift(new HystrixObservableTimeoutOperator(_cmd));
private static class HystrixObservableTimeoutOperator<R> implements Operator<R.R> {
final AbstractCommand<R> originalCommand;
public HystrixObservableTimeoutOperator(final AbstractCommand<R> originalCommand) {
this.originalCommand = originalCommand;
}
@Override
public Subscriber<? super R> call(final Subscriber<? super R> child) {
final CompositeSubscription s = new CompositeSubscription();
// if the child unsubscribes we unsubscribe our parent as well
child.add(s);
//capture the HystrixRequestContext upfront so that we can use it in the timeout thread later
final HystrixRequestContext hystrixRequestContext =
HystrixRequestContext.getContextForCurrentThread();
TimerListener listener = new TimerListener() {
@Override
public void tick(a) {
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(a) {
child.onError(newHystrixTimeoutException()); }}); timeoutRunnable.run(); }}@Override
public int getIntervalTimeInMilliseconds(a) {
returnoriginalCommand.properties.executionTimeoutInMilliseconds().get(); }};final Reference<TimerListener> tl = HystrixTimer.getInstance().addTimerListener(listener);
// set externally so execute/queue can see this
originalCommand.timeoutTimer.set(tl);
/** * If this subscriber receives values it means the parent succeeded/completed */
Subscriber<R> parent = new Subscriber<R>() {
@Override
public void onCompleted(a) {
if (isNotTimedOut()) {
// stop timer and pass notification throughtl.clear(); child.onCompleted(); }}@Override
public void onError(Throwable e) {
if (isNotTimedOut()) {
// stop timer and pass notification throughtl.clear(); child.onError(e); }}@Override
public void onNext(R v) {
if(isNotTimedOut()) { child.onNext(v); }}private boolean isNotTimedOut(a) {
// if already marked COMPLETED (by onNext) or succeeds in setting to COMPLETED
returnoriginalCommand.isCommandTimedOut.get() == TimedOutStatus.COMPLETED || originalCommand.isCommandTimedOut.compareAndSet(TimedOutStatus.NOT_EXECUTED, TimedOutStatus.COMPLETED); }};// if s is unsubscribed we want to unsubscribe the parent
s.add(parent);
returnparent; }}public Reference<TimerListener> addTimerListener(final TimerListener listener) {
startThreadIfNeeded();
// add the listener
Runnable r = new Runnable() {
@Override
public void run(a) {
try {
listener.tick();
} catch (Exception e) {
logger.error("Failed while ticking TimerListener", e); }}};// scheduleAtFixedRate takes the timeout period as a cycle to determine whether the execution is completeScheduledFuture<? > f = executor.get().getThreadPool().scheduleAtFixedRate(r, listener.getIntervalTimeInMilliseconds(), listener.getIntervalTimeInMilliseconds(), TimeUnit.MILLISECONDS);return new TimerReference(listener, f);
}
public class HystrixContextRunnable implements Runnable {
private final Callable<Void> actual;
private final HystrixRequestContext parentThreadState;
public HystrixContextRunnable(Runnable actual) {
this(HystrixPlugins.getInstance().getConcurrencyStrategy(), actual);
}
public HystrixContextRunnable(HystrixConcurrencyStrategy concurrencyStrategy, final Runnable
actual) {
this(concurrencyStrategy, HystrixRequestContext.getContextForCurrentThread(), actual);
}
public HystrixContextRunnable(final HystrixConcurrencyStrategy concurrencyStrategy,
final HystrixRequestContext hystrixRequestContext, final Runnable actual) {
this.actual = concurrencyStrategy.wrapCallable(new Callable<Void>() {
@Override
public Void call(a) throws Exception {
actual.run();
return null; }});this.parentThreadState = hystrixRequestContext;
}
@Override
public void run(a) {
HystrixRequestContext existingState = HystrixRequestContext.getContextForCurrentThread();
try {
// set the state of this thread to that of its parent
HystrixRequestContext.setContextOnCurrentThread(parentThreadState);
// execute actual Callable with the state of the parent
try {
actual.call();
} catch (Exception e) {
throw newRuntimeException(e); }}finally {
// restore this thread back to its original stateHystrixRequestContext.setContextOnCurrentThread(existingState); }}}Copy the code