use of com.netflix.hystrix.strategy.concurrency.HystrixRequestContext in project Hystrix by Netflix.
the class AbstractCommand method getFallbackOrThrowException.
/**
* Execute <code>getFallback()</code> within protection of a semaphore that limits number of concurrent executions.
* <p>
* Fallback implementations shouldn't perform anything that can be blocking, but we protect against it anyways in case someone doesn't abide by the contract.
* <p>
* If something in the <code>getFallback()</code> implementation is latent (such as a network call) then the semaphore will cause us to start rejecting requests rather than allowing potentially
* all threads to pile up and block.
*
* @return K
* @throws UnsupportedOperationException
* if getFallback() not implemented
* @throws HystrixRuntimeException
* if getFallback() fails (throws an Exception) or is rejected by the semaphore
*/
private Observable<R> getFallbackOrThrowException(final AbstractCommand<R> _cmd, final HystrixEventType eventType, final FailureType failureType, final String message, final Exception originalException) {
final HystrixRequestContext requestContext = HystrixRequestContext.getContextForCurrentThread();
long latency = System.currentTimeMillis() - executionResult.getStartTimestamp();
// record the executionResult
// do this before executing fallback so it can be queried from within getFallback (see See https://github.com/Netflix/Hystrix/pull/144)
executionResult = executionResult.addEvent((int) latency, eventType);
if (isUnrecoverable(originalException)) {
logger.error("Unrecoverable Error for HystrixCommand so will throw HystrixRuntimeException and not apply fallback. ", originalException);
/* executionHook for all errors */
Exception e = wrapWithOnErrorHook(failureType, originalException);
return Observable.error(new HystrixRuntimeException(failureType, this.getClass(), getLogMessagePrefix() + " " + message + " and encountered unrecoverable error.", e, null));
} else {
if (isRecoverableError(originalException)) {
logger.warn("Recovered from java.lang.Error by serving Hystrix fallback", originalException);
}
if (properties.fallbackEnabled().get()) {
/* fallback behavior is permitted so attempt */
final Action1<Notification<? super R>> setRequestContext = new Action1<Notification<? super R>>() {
@Override
public void call(Notification<? super R> rNotification) {
setRequestContextIfNeeded(requestContext);
}
};
final Action1<R> markFallbackEmit = new Action1<R>() {
@Override
public void call(R r) {
if (shouldOutputOnNextEvents()) {
executionResult = executionResult.addEvent(HystrixEventType.FALLBACK_EMIT);
eventNotifier.markEvent(HystrixEventType.FALLBACK_EMIT, commandKey);
}
}
};
final Action0 markFallbackCompleted = new Action0() {
@Override
public void call() {
long latency = System.currentTimeMillis() - executionResult.getStartTimestamp();
eventNotifier.markEvent(HystrixEventType.FALLBACK_SUCCESS, commandKey);
executionResult = executionResult.addEvent((int) latency, HystrixEventType.FALLBACK_SUCCESS);
}
};
final Func1<Throwable, Observable<R>> handleFallbackError = new Func1<Throwable, Observable<R>>() {
@Override
public Observable<R> call(Throwable t) {
/* executionHook for all errors */
Exception e = wrapWithOnErrorHook(failureType, originalException);
Exception fe = getExceptionFromThrowable(t);
long latency = System.currentTimeMillis() - executionResult.getStartTimestamp();
Exception toEmit;
if (fe instanceof UnsupportedOperationException) {
// debug only since we're throwing the exception and someone higher will do something with it
logger.debug("No fallback for HystrixCommand. ", fe);
eventNotifier.markEvent(HystrixEventType.FALLBACK_MISSING, commandKey);
executionResult = executionResult.addEvent((int) latency, HystrixEventType.FALLBACK_MISSING);
toEmit = new HystrixRuntimeException(failureType, _cmd.getClass(), getLogMessagePrefix() + " " + message + " and no fallback available.", e, fe);
} else {
logger.debug("HystrixCommand execution " + failureType.name() + " and fallback failed.", fe);
eventNotifier.markEvent(HystrixEventType.FALLBACK_FAILURE, commandKey);
executionResult = executionResult.addEvent((int) latency, HystrixEventType.FALLBACK_FAILURE);
toEmit = new HystrixRuntimeException(failureType, _cmd.getClass(), getLogMessagePrefix() + " " + message + " and fallback failed.", e, fe);
}
// NOTE: we're suppressing fallback exception here
if (shouldNotBeWrapped(originalException)) {
return Observable.error(e);
}
return Observable.error(toEmit);
}
};
final TryableSemaphore fallbackSemaphore = getFallbackSemaphore();
final AtomicBoolean semaphoreHasBeenReleased = new AtomicBoolean(false);
final Action0 singleSemaphoreRelease = new Action0() {
@Override
public void call() {
if (semaphoreHasBeenReleased.compareAndSet(false, true)) {
fallbackSemaphore.release();
}
}
};
Observable<R> fallbackExecutionChain;
// acquire a permit
if (fallbackSemaphore.tryAcquire()) {
try {
if (isFallbackUserDefined()) {
executionHook.onFallbackStart(this);
fallbackExecutionChain = getFallbackObservable();
} else {
// same logic as above without the hook invocation
fallbackExecutionChain = getFallbackObservable();
}
} catch (Throwable ex) {
// If hook or user-fallback throws, then use that as the result of the fallback lookup
fallbackExecutionChain = Observable.error(ex);
}
return fallbackExecutionChain.doOnEach(setRequestContext).lift(new FallbackHookApplication(_cmd)).lift(new DeprecatedOnFallbackHookApplication(_cmd)).doOnNext(markFallbackEmit).doOnCompleted(markFallbackCompleted).onErrorResumeNext(handleFallbackError).doOnTerminate(singleSemaphoreRelease).doOnUnsubscribe(singleSemaphoreRelease);
} else {
return handleFallbackRejectionByEmittingError();
}
} else {
return handleFallbackDisabledByEmittingError(originalException, failureType, message);
}
}
}
use of com.netflix.hystrix.strategy.concurrency.HystrixRequestContext in project Hystrix by Netflix.
the class UnsubscribedTasksRequestCacheTest method testOneCommandIsUnsubscribed.
@Test
public void testOneCommandIsUnsubscribed() throws ExecutionException, InterruptedException {
HystrixPlugins.getInstance().registerCommandExecutionHook(new CommandExecutionHook());
final HystrixRequestContext context = HystrixRequestContext.initializeContext();
final AtomicInteger numCacheResponses = new AtomicInteger(0);
try {
ExecutorService executorService = Executors.newSingleThreadExecutor();
Future futureCommand2a = executorService.submit(createCommandRunnable(context, numCacheResponses));
Future futureCommand2b = executorService.submit(createCommandRunnable(context, numCacheResponses));
futureCommand2a.get();
futureCommand2b.get();
assertEquals(1, numCacheResponses.get());
assertEquals(1, numOfExecutions.get());
assertFalse(encounteredCommandException.get());
} finally {
context.shutdown();
}
}
use of com.netflix.hystrix.strategy.concurrency.HystrixRequestContext in project Hystrix by Netflix.
the class HystrixCommandTimeoutConcurrencyTesting method testTimeoutRace.
@Test
public void testTimeoutRace() throws InterruptedException {
final int NUM_TRIALS = 10;
for (int i = 0; i < NUM_TRIALS; i++) {
List<Observable<String>> observables = new ArrayList<Observable<String>>();
HystrixRequestContext context = null;
try {
context = HystrixRequestContext.initializeContext();
for (int j = 0; j < NUM_CONCURRENT_COMMANDS; j++) {
observables.add(new TestCommand().observe());
}
Observable<String> overall = Observable.merge(observables);
// wait for all commands to complete
List<String> results = overall.toList().toBlocking().first();
for (String s : results) {
if (s == null) {
System.err.println("Received NULL!");
throw new RuntimeException("Received NULL");
}
}
for (HystrixInvokableInfo<?> hi : HystrixRequestLog.getCurrentRequest().getAllExecutedCommands()) {
if (!hi.isResponseTimedOut()) {
System.err.println("Timeout not found in executed command");
throw new RuntimeException("Timeout not found in executed command");
}
if (hi.isResponseTimedOut() && hi.getExecutionEvents().size() == 1) {
System.err.println("Missing fallback status!");
throw new RuntimeException("Missing fallback status on timeout.");
}
}
} catch (Exception e) {
System.err.println("Error: " + e.getMessage());
e.printStackTrace();
throw new RuntimeException(e);
} finally {
System.out.println(HystrixRequestLog.getCurrentRequest().getExecutedCommandsAsString());
if (context != null) {
context.shutdown();
}
}
System.out.println("*************** TRIAL " + i + " ******************");
System.out.println();
Thread.sleep(50);
}
Hystrix.reset();
}
use of com.netflix.hystrix.strategy.concurrency.HystrixRequestContext in project Hystrix by Netflix.
the class HystrixCommandTestWithCustomConcurrencyStrategy method testCommandRequiresContextConcurrencyStrategyDoesNotProvideItContextSetUpCorrectly.
/**
* HystrixConcurrencyStrategy
** useDefaultRequestContext : false
* HystrixCommand
** useRequestCache : true
** useRequestLog : true
*
* OUTCOME: RequestLog not set up in command, not available statically
*/
@Test
public void testCommandRequiresContextConcurrencyStrategyDoesNotProvideItContextSetUpCorrectly() {
HystrixConcurrencyStrategy strategy = new CustomConcurrencyStrategy(false);
HystrixPlugins.getInstance().registerConcurrencyStrategy(strategy);
// context is set up properly
HystrixRequestContext context = HystrixRequestContext.initializeContext();
HystrixCommand<Boolean> cmd = new TestCommand(true, true);
assertTrue(cmd.execute());
printRequestLog();
assertNull(HystrixRequestLog.getCurrentRequest());
assertNull(HystrixRequestLog.getCurrentRequest(strategy));
assertNull(cmd.currentRequestLog);
context.shutdown();
}
use of com.netflix.hystrix.strategy.concurrency.HystrixRequestContext in project Hystrix by Netflix.
the class HystrixCommandTestWithCustomConcurrencyStrategy method testCommandRequiresContextConcurrencyStrategyProvidesItContextSetUpCorrectly.
/**
* HystrixConcurrencyStrategy
** useDefaultRequestContext : true
* HystrixCommand
** useRequestCache : true
** useRequestLog : true
*
* OUTCOME: RequestLog set up properly in command
*/
@Test
public void testCommandRequiresContextConcurrencyStrategyProvidesItContextSetUpCorrectly() {
HystrixConcurrencyStrategy strategy = new CustomConcurrencyStrategy(true);
HystrixPlugins.getInstance().registerConcurrencyStrategy(strategy);
// context is set up properly
HystrixRequestContext context = HystrixRequestContext.initializeContext();
HystrixCommand<Boolean> cmd = new TestCommand(true, true);
assertTrue(cmd.execute());
printRequestLog();
assertNotNull(HystrixRequestLog.getCurrentRequest().getExecutedCommandsAsString());
assertNotNull(cmd.currentRequestLog);
context.shutdown();
}
Aggregations