Search in sources :

Example 1 with HystrixRequestContext

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);
        }
    }
}
Also used : Action0(rx.functions.Action0) Action1(rx.functions.Action1) HystrixRuntimeException(com.netflix.hystrix.exception.HystrixRuntimeException) TimeoutException(java.util.concurrent.TimeoutException) HystrixRuntimeException(com.netflix.hystrix.exception.HystrixRuntimeException) RejectedExecutionException(java.util.concurrent.RejectedExecutionException) HystrixBadRequestException(com.netflix.hystrix.exception.HystrixBadRequestException) HystrixTimeoutException(com.netflix.hystrix.exception.HystrixTimeoutException) Notification(rx.Notification) Observable(rx.Observable) AtomicBoolean(java.util.concurrent.atomic.AtomicBoolean) HystrixRequestContext(com.netflix.hystrix.strategy.concurrency.HystrixRequestContext) Func1(rx.functions.Func1)

Example 2 with HystrixRequestContext

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();
    }
}
Also used : AtomicInteger(java.util.concurrent.atomic.AtomicInteger) ExecutorService(java.util.concurrent.ExecutorService) Future(java.util.concurrent.Future) HystrixRequestContext(com.netflix.hystrix.strategy.concurrency.HystrixRequestContext) HystrixCommandExecutionHook(com.netflix.hystrix.strategy.executionhook.HystrixCommandExecutionHook) Test(org.junit.Test)

Example 3 with HystrixRequestContext

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();
}
Also used : ArrayList(java.util.ArrayList) HystrixRequestContext(com.netflix.hystrix.strategy.concurrency.HystrixRequestContext) Observable(rx.Observable) Test(org.junit.Test)

Example 4 with HystrixRequestContext

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();
}
Also used : HystrixConcurrencyStrategy(com.netflix.hystrix.strategy.concurrency.HystrixConcurrencyStrategy) HystrixRequestContext(com.netflix.hystrix.strategy.concurrency.HystrixRequestContext) Test(org.junit.Test)

Example 5 with HystrixRequestContext

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();
}
Also used : HystrixConcurrencyStrategy(com.netflix.hystrix.strategy.concurrency.HystrixConcurrencyStrategy) HystrixRequestContext(com.netflix.hystrix.strategy.concurrency.HystrixRequestContext) Test(org.junit.Test)

Aggregations

HystrixRequestContext (com.netflix.hystrix.strategy.concurrency.HystrixRequestContext)15 Test (org.junit.Test)12 HystrixConcurrencyStrategy (com.netflix.hystrix.strategy.concurrency.HystrixConcurrencyStrategy)6 ArrayList (java.util.ArrayList)4 Observable (rx.Observable)4 RequestCollapser (com.netflix.hystrix.collapser.RequestCollapser)2 HystrixBadRequestException (com.netflix.hystrix.exception.HystrixBadRequestException)2 HystrixRuntimeException (com.netflix.hystrix.exception.HystrixRuntimeException)2 HystrixTimeoutException (com.netflix.hystrix.exception.HystrixTimeoutException)2 HystrixContextRunnable (com.netflix.hystrix.strategy.concurrency.HystrixContextRunnable)2 List (java.util.List)2 ConcurrentLinkedQueue (java.util.concurrent.ConcurrentLinkedQueue)2 CountDownLatch (java.util.concurrent.CountDownLatch)2 Future (java.util.concurrent.Future)2 RejectedExecutionException (java.util.concurrent.RejectedExecutionException)2 TimeoutException (java.util.concurrent.TimeoutException)2 AtomicInteger (java.util.concurrent.atomic.AtomicInteger)2 Notification (rx.Notification)2 Action0 (rx.functions.Action0)2 Action1 (rx.functions.Action1)2