Search in sources :

Example 1 with Notification

use of rx.Notification 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 (shouldNotBeWrapped(originalException)) {
        /* executionHook for all errors */
        Exception e = wrapWithOnErrorHook(failureType, originalException);
        return Observable.error(e);
    } else 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) {
                    Exception e = originalException;
                    Exception fe = getExceptionFromThrowable(t);
                    if (fe instanceof UnsupportedOperationException) {
                        long latency = System.currentTimeMillis() - executionResult.getStartTimestamp();
                        // 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);
                        /* executionHook for all errors */
                        e = wrapWithOnErrorHook(failureType, e);
                        return Observable.error(new HystrixRuntimeException(failureType, _cmd.getClass(), getLogMessagePrefix() + " " + message + " and no fallback available.", e, fe));
                    } else {
                        long latency = System.currentTimeMillis() - executionResult.getStartTimestamp();
                        logger.debug("HystrixCommand execution " + failureType.name() + " and fallback failed.", fe);
                        eventNotifier.markEvent(HystrixEventType.FALLBACK_FAILURE, commandKey);
                        executionResult = executionResult.addEvent((int) latency, HystrixEventType.FALLBACK_FAILURE);
                        /* executionHook for all errors */
                        e = wrapWithOnErrorHook(failureType, e);
                        return Observable.error(new HystrixRuntimeException(failureType, _cmd.getClass(), getLogMessagePrefix() + " " + message + " and fallback failed.", e, fe));
                    }
                }
            };
            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 Notification

use of rx.Notification in project Hystrix by Netflix.

the class HystrixObservableCommandTest method testRequestContextOnRejectionWithFallback.

private RequestContextTestResults testRequestContextOnRejectionWithFallback(ExecutionIsolationStrategy isolation, final Scheduler userScheduler) {
    final RequestContextTestResults results = new RequestContextTestResults();
    TestHystrixObservableCommand<Boolean> command = new TestHystrixObservableCommand<Boolean>(TestHystrixObservableCommand.testPropsBuilder(new TestCircuitBreaker()).setCommandPropertiesDefaults(HystrixCommandPropertiesTest.getUnitTestPropertiesSetter().withExecutionIsolationStrategy(isolation).withExecutionIsolationSemaphoreMaxConcurrentRequests(0)).setThreadPool(new HystrixThreadPool() {

        @Override
        public ThreadPoolExecutor getExecutor() {
            return null;
        }

        @Override
        public void markThreadExecution() {
        }

        @Override
        public void markThreadCompletion() {
        }

        @Override
        public void markThreadRejection() {
        }

        @Override
        public boolean isQueueSpaceAvailable() {
            // always return false so we reject everything
            return false;
        }

        @Override
        public Scheduler getScheduler() {
            return new HystrixContextScheduler(HystrixPlugins.getInstance().getConcurrencyStrategy(), this);
        }

        @Override
        public Scheduler getScheduler(Func0<Boolean> shouldInterruptThread) {
            return new HystrixContextScheduler(HystrixPlugins.getInstance().getConcurrencyStrategy(), this, shouldInterruptThread);
        }
    })) {

        @Override
        protected Observable<Boolean> construct() {
            return Observable.create(new OnSubscribe<Boolean>() {

                @Override
                public void call(Subscriber<? super Boolean> s) {
                    s.onError(new RuntimeException("onError"));
                }
            }).subscribeOn(userScheduler);
        }

        @Override
        protected Observable<Boolean> resumeWithFallback() {
            return Observable.create(new OnSubscribe<Boolean>() {

                @Override
                public void call(Subscriber<? super Boolean> s) {
                    results.isContextInitialized.set(HystrixRequestContext.isCurrentThreadInitialized());
                    results.originThread.set(Thread.currentThread());
                    s.onNext(false);
                    s.onCompleted();
                }
            }).subscribeOn(userScheduler);
        }
    };
    results.command = command;
    command.toObservable().doOnEach(new Action1<Notification<? super Boolean>>() {

        @Override
        public void call(Notification<? super Boolean> n) {
            results.isContextInitializedObserveOn.set(HystrixRequestContext.isCurrentThreadInitialized());
            results.observeOnThread.set(Thread.currentThread());
        }
    }).subscribe(results.ts);
    results.ts.awaitTerminalEvent();
    System.out.println("Run => Initialized: " + results.isContextInitialized.get() + "  Thread: " + results.originThread.get());
    System.out.println("Observed => Initialized: " + results.isContextInitializedObserveOn.get() + "  Thread: " + results.observeOnThread.get());
    assertEquals(0, results.ts.getOnErrorEvents().size());
    assertEquals(1, results.ts.getOnNextEvents().size());
    assertEquals(false, results.ts.getOnNextEvents().get(0));
    assertFalse(command.isSuccessfulExecution());
    assertTrue(command.isResponseRejected());
    if (isolation == ExecutionIsolationStrategy.SEMAPHORE) {
        assertCommandExecutionEvents(command, HystrixEventType.SEMAPHORE_REJECTED, HystrixEventType.FALLBACK_EMIT, HystrixEventType.FALLBACK_SUCCESS);
    } else {
        assertCommandExecutionEvents(command, HystrixEventType.THREAD_POOL_REJECTED, HystrixEventType.FALLBACK_EMIT, HystrixEventType.FALLBACK_SUCCESS);
    }
    assertEquals(0, command.metrics.getCurrentConcurrentExecutionCount());
    assertSaneHystrixRequestLog(1);
    return results;
}
Also used : TestCircuitBreaker(com.netflix.hystrix.HystrixCircuitBreakerTest.TestCircuitBreaker) Action1(rx.functions.Action1) HystrixContextScheduler(com.netflix.hystrix.strategy.concurrency.HystrixContextScheduler) OnSubscribe(rx.Observable.OnSubscribe) Notification(rx.Notification) HystrixRuntimeException(com.netflix.hystrix.exception.HystrixRuntimeException) TestSubscriber(rx.observers.TestSubscriber) Subscriber(rx.Subscriber) AtomicBoolean(java.util.concurrent.atomic.AtomicBoolean) Func0(rx.functions.Func0)

Example 3 with Notification

use of rx.Notification in project Hystrix by Netflix.

the class HystrixObservableCommandTest method testRequestContextOnShortCircuitedWithFallback.

private RequestContextTestResults testRequestContextOnShortCircuitedWithFallback(ExecutionIsolationStrategy isolation, final Scheduler userScheduler) {
    final RequestContextTestResults results = new RequestContextTestResults();
    TestHystrixObservableCommand<Boolean> command = new TestHystrixObservableCommand<Boolean>(TestHystrixObservableCommand.testPropsBuilder(new TestCircuitBreaker()).setCommandPropertiesDefaults(HystrixCommandPropertiesTest.getUnitTestPropertiesSetter().withExecutionIsolationStrategy(isolation)).setCircuitBreaker(new TestCircuitBreaker().setForceShortCircuit(true))) {

        @Override
        protected Observable<Boolean> construct() {
            return Observable.create(new OnSubscribe<Boolean>() {

                @Override
                public void call(Subscriber<? super Boolean> s) {
                    s.onError(new RuntimeException("onError"));
                }
            }).subscribeOn(userScheduler);
        }

        @Override
        protected Observable<Boolean> resumeWithFallback() {
            return Observable.create(new OnSubscribe<Boolean>() {

                @Override
                public void call(Subscriber<? super Boolean> s) {
                    results.isContextInitialized.set(HystrixRequestContext.isCurrentThreadInitialized());
                    results.originThread.set(Thread.currentThread());
                    s.onNext(false);
                    s.onCompleted();
                }
            }).subscribeOn(userScheduler);
        }
    };
    results.command = command;
    command.toObservable().doOnEach(new Action1<Notification<? super Boolean>>() {

        @Override
        public void call(Notification<? super Boolean> n) {
            results.isContextInitializedObserveOn.set(HystrixRequestContext.isCurrentThreadInitialized());
            results.observeOnThread.set(Thread.currentThread());
        }
    }).subscribe(results.ts);
    results.ts.awaitTerminalEvent();
    System.out.println("Run => Initialized: " + results.isContextInitialized.get() + "  Thread: " + results.originThread.get());
    System.out.println("Observed => Initialized: " + results.isContextInitializedObserveOn.get() + "  Thread: " + results.observeOnThread.get());
    assertEquals(0, results.ts.getOnErrorEvents().size());
    assertEquals(1, results.ts.getOnNextEvents().size());
    assertEquals(false, results.ts.getOnNextEvents().get(0));
    assertTrue(command.getExecutionTimeInMilliseconds() == -1);
    assertFalse(command.isSuccessfulExecution());
    assertTrue(command.isResponseShortCircuited());
    assertCommandExecutionEvents(command, HystrixEventType.SHORT_CIRCUITED, HystrixEventType.FALLBACK_EMIT, HystrixEventType.FALLBACK_SUCCESS);
    assertEquals(0, command.metrics.getCurrentConcurrentExecutionCount());
    assertSaneHystrixRequestLog(1);
    return results;
}
Also used : TestCircuitBreaker(com.netflix.hystrix.HystrixCircuitBreakerTest.TestCircuitBreaker) HystrixRuntimeException(com.netflix.hystrix.exception.HystrixRuntimeException) Action1(rx.functions.Action1) TestSubscriber(rx.observers.TestSubscriber) Subscriber(rx.Subscriber) OnSubscribe(rx.Observable.OnSubscribe) AtomicBoolean(java.util.concurrent.atomic.AtomicBoolean) Notification(rx.Notification)

Example 4 with Notification

use of rx.Notification in project Hystrix by Netflix.

the class HystrixObservableCommandTest method testRequestContextOnGracefulFailure.

private RequestContextTestResults testRequestContextOnGracefulFailure(ExecutionIsolationStrategy isolation, final Scheduler userScheduler) {
    final RequestContextTestResults results = new RequestContextTestResults();
    final TestCircuitBreaker circuitBreaker = new TestCircuitBreaker();
    TestHystrixObservableCommand<Boolean> command = new TestHystrixObservableCommand<Boolean>(TestHystrixObservableCommand.testPropsBuilder(circuitBreaker).setCommandPropertiesDefaults(HystrixCommandPropertiesTest.getUnitTestPropertiesSetter().withExecutionIsolationStrategy(isolation))) {

        @Override
        protected Observable<Boolean> construct() {
            return Observable.create(new OnSubscribe<Boolean>() {

                @Override
                public void call(Subscriber<? super Boolean> s) {
                    results.isContextInitialized.set(HystrixRequestContext.isCurrentThreadInitialized());
                    results.originThread.set(Thread.currentThread());
                    s.onError(new RuntimeException("graceful onError"));
                }
            }).subscribeOn(userScheduler);
        }
    };
    results.command = command;
    command.toObservable().doOnEach(new Action1<Notification<? super Boolean>>() {

        @Override
        public void call(Notification<? super Boolean> n) {
            results.isContextInitializedObserveOn.set(HystrixRequestContext.isCurrentThreadInitialized());
            results.observeOnThread.set(Thread.currentThread());
        }
    }).subscribe(results.ts);
    results.ts.awaitTerminalEvent();
    System.out.println("Run => Initialized: " + results.isContextInitialized.get() + "  Thread: " + results.originThread.get());
    System.out.println("Observed => Initialized: " + results.isContextInitializedObserveOn.get() + "  Thread: " + results.observeOnThread.get());
    assertEquals(1, results.ts.getOnErrorEvents().size());
    assertTrue(command.getExecutionTimeInMilliseconds() > -1);
    assertFalse(command.isSuccessfulExecution());
    assertTrue(command.isFailedExecution());
    assertCommandExecutionEvents(command, HystrixEventType.FAILURE, HystrixEventType.FALLBACK_MISSING);
    assertEquals(0, command.metrics.getCurrentConcurrentExecutionCount());
    assertSaneHystrixRequestLog(1);
    return results;
}
Also used : TestCircuitBreaker(com.netflix.hystrix.HystrixCircuitBreakerTest.TestCircuitBreaker) HystrixRuntimeException(com.netflix.hystrix.exception.HystrixRuntimeException) Action1(rx.functions.Action1) TestSubscriber(rx.observers.TestSubscriber) Subscriber(rx.Subscriber) OnSubscribe(rx.Observable.OnSubscribe) AtomicBoolean(java.util.concurrent.atomic.AtomicBoolean) Notification(rx.Notification)

Example 5 with Notification

use of rx.Notification in project Hystrix by Netflix.

the class HystrixObservableCommandTest method testRequestContextOnTimeoutWithFallback.

private RequestContextTestResults testRequestContextOnTimeoutWithFallback(ExecutionIsolationStrategy isolation, final Scheduler userScheduler) {
    final RequestContextTestResults results = new RequestContextTestResults();
    TestHystrixObservableCommand<Boolean> command = new TestHystrixObservableCommand<Boolean>(TestHystrixObservableCommand.testPropsBuilder(new TestCircuitBreaker()).setCommandPropertiesDefaults(HystrixCommandPropertiesTest.getUnitTestPropertiesSetter().withExecutionIsolationStrategy(isolation).withExecutionTimeoutInMilliseconds(50))) {

        @Override
        protected Observable<Boolean> construct() {
            return Observable.create(new OnSubscribe<Boolean>() {

                @Override
                public void call(Subscriber<? super Boolean> s) {
                    try {
                        Thread.sleep(500);
                    } catch (InterruptedException e) {
                    // ignore the interrupted exception
                    }
                }
            }).subscribeOn(userScheduler);
        }

        @Override
        protected Observable<Boolean> resumeWithFallback() {
            return Observable.create(new OnSubscribe<Boolean>() {

                @Override
                public void call(Subscriber<? super Boolean> s) {
                    results.isContextInitialized.set(HystrixRequestContext.isCurrentThreadInitialized());
                    results.originThread.set(Thread.currentThread());
                    s.onNext(false);
                    s.onCompleted();
                }
            }).subscribeOn(userScheduler);
        }
    };
    results.command = command;
    command.toObservable().doOnEach(new Action1<Notification<? super Boolean>>() {

        @Override
        public void call(Notification<? super Boolean> n) {
            System.out.println("timeoutWithFallback notification: " + n + "   " + Thread.currentThread());
            results.isContextInitializedObserveOn.set(HystrixRequestContext.isCurrentThreadInitialized());
            results.observeOnThread.set(Thread.currentThread());
        }
    }).subscribe(results.ts);
    results.ts.awaitTerminalEvent();
    System.out.println("Fallback => Initialized: " + results.isContextInitialized.get() + "  Thread: " + results.originThread.get());
    System.out.println("Observed => Initialized: " + results.isContextInitializedObserveOn.get() + "  Thread: " + results.observeOnThread.get());
    assertEquals(1, results.ts.getOnNextEvents().size());
    assertEquals(false, results.ts.getOnNextEvents().get(0));
    assertTrue(command.getExecutionTimeInMilliseconds() > -1);
    assertFalse(command.isSuccessfulExecution());
    assertTrue(command.isResponseTimedOut());
    assertCommandExecutionEvents(command, HystrixEventType.TIMEOUT, HystrixEventType.FALLBACK_EMIT, HystrixEventType.FALLBACK_SUCCESS);
    assertEquals(0, command.metrics.getCurrentConcurrentExecutionCount());
    assertSaneHystrixRequestLog(1);
    return results;
}
Also used : TestCircuitBreaker(com.netflix.hystrix.HystrixCircuitBreakerTest.TestCircuitBreaker) Action1(rx.functions.Action1) TestSubscriber(rx.observers.TestSubscriber) Subscriber(rx.Subscriber) OnSubscribe(rx.Observable.OnSubscribe) AtomicBoolean(java.util.concurrent.atomic.AtomicBoolean) Notification(rx.Notification)

Aggregations

Notification (rx.Notification)12 Action1 (rx.functions.Action1)11 AtomicBoolean (java.util.concurrent.atomic.AtomicBoolean)9 TestCircuitBreaker (com.netflix.hystrix.HystrixCircuitBreakerTest.TestCircuitBreaker)7 HystrixRuntimeException (com.netflix.hystrix.exception.HystrixRuntimeException)7 OnSubscribe (rx.Observable.OnSubscribe)7 Subscriber (rx.Subscriber)7 TestSubscriber (rx.observers.TestSubscriber)7 Observable (rx.Observable)4 Action0 (rx.functions.Action0)4 Func1 (rx.functions.Func1)3 HystrixBadRequestException (com.netflix.hystrix.exception.HystrixBadRequestException)2 HystrixTimeoutException (com.netflix.hystrix.exception.HystrixTimeoutException)2 HystrixRequestContext (com.netflix.hystrix.strategy.concurrency.HystrixRequestContext)2 RejectedExecutionException (java.util.concurrent.RejectedExecutionException)2 TimeoutException (java.util.concurrent.TimeoutException)2 Counter (com.fernandocejas.frodo.internal.Counter)1 StopWatch (com.fernandocejas.frodo.internal.StopWatch)1 HystrixContextScheduler (com.netflix.hystrix.strategy.concurrency.HystrixContextScheduler)1 RibbonResponse (com.netflix.ribbon.RibbonResponse)1