use of rx.functions.Action0 in project Hystrix by Netflix.
the class AbstractCommand method executeCommandAndObserve.
/**
* This decorates "Hystrix" functionality around the run() Observable.
*
* @return R
*/
private Observable<R> executeCommandAndObserve(final AbstractCommand<R> _cmd) {
final HystrixRequestContext currentRequestContext = HystrixRequestContext.getContextForCurrentThread();
final Action1<R> markEmits = new Action1<R>() {
@Override
public void call(R r) {
if (shouldOutputOnNextEvents()) {
executionResult = executionResult.addEvent(HystrixEventType.EMIT);
eventNotifier.markEvent(HystrixEventType.EMIT, commandKey);
}
if (commandIsScalar()) {
long latency = System.currentTimeMillis() - executionResult.getStartTimestamp();
eventNotifier.markEvent(HystrixEventType.SUCCESS, commandKey);
executionResult = executionResult.addEvent((int) latency, HystrixEventType.SUCCESS);
eventNotifier.markCommandExecution(getCommandKey(), properties.executionIsolationStrategy().get(), (int) latency, executionResult.getOrderedList());
circuitBreaker.markSuccess();
}
}
};
final Action0 markOnCompleted = new Action0() {
@Override
public void call() {
if (!commandIsScalar()) {
long latency = System.currentTimeMillis() - executionResult.getStartTimestamp();
eventNotifier.markEvent(HystrixEventType.SUCCESS, commandKey);
executionResult = executionResult.addEvent((int) latency, HystrixEventType.SUCCESS);
eventNotifier.markCommandExecution(getCommandKey(), properties.executionIsolationStrategy().get(), (int) latency, executionResult.getOrderedList());
circuitBreaker.markSuccess();
}
}
};
final Func1<Throwable, Observable<R>> handleFallback = new Func1<Throwable, Observable<R>>() {
@Override
public Observable<R> call(Throwable t) {
circuitBreaker.markNonSuccess();
Exception e = getExceptionFromThrowable(t);
executionResult = executionResult.setExecutionException(e);
if (e instanceof RejectedExecutionException) {
return handleThreadPoolRejectionViaFallback(e);
} else if (t instanceof HystrixTimeoutException) {
return handleTimeoutViaFallback();
} else if (t instanceof HystrixBadRequestException) {
return handleBadRequestByEmittingError(e);
} else {
/*
* Treat HystrixBadRequestException from ExecutionHook like a plain HystrixBadRequestException.
*/
if (e instanceof HystrixBadRequestException) {
eventNotifier.markEvent(HystrixEventType.BAD_REQUEST, commandKey);
return Observable.error(e);
}
return handleFailureViaFallback(e);
}
}
};
final Action1<Notification<? super R>> setRequestContext = new Action1<Notification<? super R>>() {
@Override
public void call(Notification<? super R> rNotification) {
setRequestContextIfNeeded(currentRequestContext);
}
};
Observable<R> execution;
if (properties.executionTimeoutEnabled().get()) {
execution = executeCommandWithSpecifiedIsolation(_cmd).lift(new HystrixObservableTimeoutOperator<R>(_cmd));
} else {
execution = executeCommandWithSpecifiedIsolation(_cmd);
}
return execution.doOnNext(markEmits).doOnCompleted(markOnCompleted).onErrorResumeNext(handleFallback).doOnEach(setRequestContext);
}
use of rx.functions.Action0 in project Hystrix by Netflix.
the class HystrixCollapser method observe.
/**
* Used for asynchronous execution with a callback by subscribing to the {@link Observable}.
* <p>
* This eagerly starts execution the same as {@link #queue()} and {@link #execute()}.
* A lazy {@link Observable} can be obtained from {@link #toObservable()}.
* <p>
* <b>Callback Scheduling</b>
* <p>
* <ul>
* <li>When using {@link ExecutionIsolationStrategy#THREAD} this defaults to using {@link Schedulers#computation()} for callbacks.</li>
* <li>When using {@link ExecutionIsolationStrategy#SEMAPHORE} this defaults to using {@link Schedulers#immediate()} for callbacks.</li>
* </ul>
* Use {@link #toObservable(rx.Scheduler)} to schedule the callback differently.
* <p>
* See https://github.com/Netflix/RxJava/wiki for more information.
*
* @return {@code Observable<R>} that executes and calls back with the result of of {@link HystrixCommand}{@code <BatchReturnType>} execution after passing through {@link #mapResponseToRequests}
* to transform the {@code <BatchReturnType>} into {@code <ResponseType>}
*/
public Observable<ResponseType> observe() {
// use a ReplaySubject to buffer the eagerly subscribed-to Observable
ReplaySubject<ResponseType> subject = ReplaySubject.create();
// eagerly kick off subscription
final Subscription underlyingSubscription = toObservable().subscribe(subject);
// return the subject that can be subscribed to later while the execution has already started
return subject.doOnUnsubscribe(new Action0() {
@Override
public void call() {
underlyingSubscription.unsubscribe();
}
});
}
use of rx.functions.Action0 in project Hystrix by Netflix.
the class HystrixCommandTest method testUnsubscribingDownstreamOperatorStillResultsInSuccessEventType.
/**
* Some RxJava operators like take(n), zip receive data in an onNext from upstream and immediately unsubscribe.
* When upstream is a HystrixCommand, Hystrix may get that unsubscribe before it gets to its onCompleted.
* This should still be marked as a HystrixEventType.SUCCESS.
*/
@Test
public void testUnsubscribingDownstreamOperatorStillResultsInSuccessEventType() throws InterruptedException {
HystrixCommand<Integer> cmd = getCommand(ExecutionIsolationStrategy.THREAD, AbstractTestHystrixCommand.ExecutionResult.SUCCESS, 100, AbstractTestHystrixCommand.FallbackResult.UNIMPLEMENTED);
Observable<Integer> o = cmd.toObservable().doOnNext(new Action1<Integer>() {
@Override
public void call(Integer i) {
System.out.println(Thread.currentThread().getName() + " : " + System.currentTimeMillis() + " CMD OnNext : " + i);
}
}).doOnError(new Action1<Throwable>() {
@Override
public void call(Throwable throwable) {
System.out.println(Thread.currentThread().getName() + " : " + System.currentTimeMillis() + " CMD OnError : " + throwable);
}
}).doOnCompleted(new Action0() {
@Override
public void call() {
System.out.println(Thread.currentThread().getName() + " : " + System.currentTimeMillis() + " CMD OnCompleted");
}
}).doOnSubscribe(new Action0() {
@Override
public void call() {
System.out.println(Thread.currentThread().getName() + " : " + System.currentTimeMillis() + " CMD OnSubscribe");
}
}).doOnUnsubscribe(new Action0() {
@Override
public void call() {
System.out.println(Thread.currentThread().getName() + " : " + System.currentTimeMillis() + " CMD OnUnsubscribe");
}
}).take(1).observeOn(Schedulers.io()).map(new Func1<Integer, Integer>() {
@Override
public Integer call(Integer i) {
System.out.println(Thread.currentThread().getName() + " : " + System.currentTimeMillis() + " : Doing some more computation in the onNext!!");
try {
Thread.sleep(100);
} catch (InterruptedException ex) {
ex.printStackTrace();
}
return i;
}
});
final CountDownLatch latch = new CountDownLatch(1);
o.doOnSubscribe(new Action0() {
@Override
public void call() {
System.out.println(Thread.currentThread().getName() + " : " + System.currentTimeMillis() + " : OnSubscribe");
}
}).doOnUnsubscribe(new Action0() {
@Override
public void call() {
System.out.println(Thread.currentThread().getName() + " : " + System.currentTimeMillis() + " : OnUnsubscribe");
}
}).subscribe(new Subscriber<Integer>() {
@Override
public void onCompleted() {
System.out.println(Thread.currentThread().getName() + " : " + System.currentTimeMillis() + " : OnCompleted");
latch.countDown();
}
@Override
public void onError(Throwable e) {
System.out.println(Thread.currentThread().getName() + " : " + System.currentTimeMillis() + " : OnError : " + e);
latch.countDown();
}
@Override
public void onNext(Integer i) {
System.out.println(Thread.currentThread().getName() + " : " + System.currentTimeMillis() + " : OnNext : " + i);
}
});
latch.await(1000, TimeUnit.MILLISECONDS);
System.out.println("ReqLog : " + HystrixRequestLog.getCurrentRequest().getExecutedCommandsAsString());
assertTrue(cmd.isExecutedInThread());
assertCommandExecutionEvents(cmd, HystrixEventType.SUCCESS);
}
use of rx.functions.Action0 in project Hystrix by Netflix.
the class HystrixCommandTest method testRequestThenTwoCacheHitsAllUnsubscribed.
@Test
public void testRequestThenTwoCacheHitsAllUnsubscribed() {
AsyncCacheableCommand original = new AsyncCacheableCommand("foo");
AsyncCacheableCommand fromCache1 = new AsyncCacheableCommand("foo");
AsyncCacheableCommand fromCache2 = new AsyncCacheableCommand("foo");
final CountDownLatch originalLatch = new CountDownLatch(1);
final CountDownLatch fromCache1Latch = new CountDownLatch(1);
final CountDownLatch fromCache2Latch = new CountDownLatch(1);
Observable<Boolean> originalObservable = original.toObservable();
Observable<Boolean> fromCache1Observable = fromCache1.toObservable();
Observable<Boolean> fromCache2Observable = fromCache2.toObservable();
Subscription originalSubscription = originalObservable.doOnUnsubscribe(new Action0() {
@Override
public void call() {
System.out.println(System.currentTimeMillis() + " : " + Thread.currentThread().getName() + " Test.Original Unsubscribe");
originalLatch.countDown();
}
}).subscribe(new Subscriber<Boolean>() {
@Override
public void onCompleted() {
System.out.println(System.currentTimeMillis() + " : " + Thread.currentThread().getName() + " Test.Original OnCompleted");
originalLatch.countDown();
}
@Override
public void onError(Throwable e) {
System.out.println(System.currentTimeMillis() + " : " + Thread.currentThread().getName() + " Test.Original OnError : " + e);
originalLatch.countDown();
}
@Override
public void onNext(Boolean b) {
System.out.println(System.currentTimeMillis() + " : " + Thread.currentThread().getName() + " Test.Original OnNext : " + b);
}
});
Subscription fromCache1Subscription = fromCache1Observable.doOnUnsubscribe(new Action0() {
@Override
public void call() {
System.out.println(System.currentTimeMillis() + " : " + Thread.currentThread().getName() + " Test.FromCache1 Unsubscribe");
fromCache1Latch.countDown();
}
}).subscribe(new Subscriber<Boolean>() {
@Override
public void onCompleted() {
System.out.println(System.currentTimeMillis() + " : " + Thread.currentThread().getName() + " Test.FromCache1 OnCompleted");
fromCache1Latch.countDown();
}
@Override
public void onError(Throwable e) {
System.out.println(System.currentTimeMillis() + " : " + Thread.currentThread().getName() + " Test.FromCache1 OnError : " + e);
fromCache1Latch.countDown();
}
@Override
public void onNext(Boolean b) {
System.out.println(System.currentTimeMillis() + " : " + Thread.currentThread().getName() + " Test.FromCache1 OnNext : " + b);
}
});
Subscription fromCache2Subscription = fromCache2Observable.doOnUnsubscribe(new Action0() {
@Override
public void call() {
System.out.println(System.currentTimeMillis() + " : " + Thread.currentThread().getName() + " Test.FromCache2 Unsubscribe");
fromCache2Latch.countDown();
}
}).subscribe(new Subscriber<Boolean>() {
@Override
public void onCompleted() {
System.out.println(System.currentTimeMillis() + " : " + Thread.currentThread().getName() + " Test.FromCache2 OnCompleted");
fromCache2Latch.countDown();
}
@Override
public void onError(Throwable e) {
System.out.println(System.currentTimeMillis() + " : " + Thread.currentThread().getName() + " Test.FromCache2 OnError : " + e);
fromCache2Latch.countDown();
}
@Override
public void onNext(Boolean b) {
System.out.println(System.currentTimeMillis() + " : " + Thread.currentThread().getName() + " Test.FromCache2 OnNext : " + b);
}
});
try {
Thread.sleep(10);
originalSubscription.unsubscribe();
fromCache1Subscription.unsubscribe();
fromCache2Subscription.unsubscribe();
assertTrue(originalLatch.await(200, TimeUnit.MILLISECONDS));
assertTrue(fromCache1Latch.await(200, TimeUnit.MILLISECONDS));
assertTrue(fromCache2Latch.await(200, TimeUnit.MILLISECONDS));
System.out.println("ReqLog : " + HystrixRequestLog.getCurrentRequest().getExecutedCommandsAsString());
assertEquals("Number of execution semaphores in use (original)", 0, original.getExecutionSemaphore().getNumberOfPermitsUsed());
assertEquals("Number of fallback semaphores in use (original)", 0, original.getFallbackSemaphore().getNumberOfPermitsUsed());
assertFalse(original.isExecutionComplete());
assertTrue(original.isExecutedInThread());
System.out.println("FEE : " + original.getFailedExecutionException());
if (original.getFailedExecutionException() != null) {
original.getFailedExecutionException().printStackTrace();
}
assertNull(original.getFailedExecutionException());
assertNull(original.getExecutionException());
assertTrue(original.getExecutionTimeInMilliseconds() > -1);
assertFalse(original.isSuccessfulExecution());
assertCommandExecutionEvents(original, HystrixEventType.CANCELLED);
// assertTrue(original.isCancelled()); //underlying work This doesn't work yet
assertEquals(0, original.metrics.getCurrentConcurrentExecutionCount());
assertEquals("Number of execution semaphores in use (fromCache1)", 0, fromCache1.getExecutionSemaphore().getNumberOfPermitsUsed());
assertEquals("Number of fallback semaphores in use (fromCache1)", 0, fromCache1.getFallbackSemaphore().getNumberOfPermitsUsed());
assertFalse(fromCache1.isExecutionComplete());
assertFalse(fromCache1.isExecutedInThread());
assertEquals(null, fromCache1.getFailedExecutionException());
assertNull(fromCache1.getExecutionException());
assertCommandExecutionEvents(fromCache1, HystrixEventType.RESPONSE_FROM_CACHE, HystrixEventType.CANCELLED);
assertTrue(fromCache1.getExecutionTimeInMilliseconds() == -1);
assertFalse(fromCache1.isSuccessfulExecution());
assertEquals(0, fromCache1.metrics.getCurrentConcurrentExecutionCount());
assertEquals("Number of execution semaphores in use (fromCache2)", 0, fromCache2.getExecutionSemaphore().getNumberOfPermitsUsed());
assertEquals("Number of fallback semaphores in use (fromCache2)", 0, fromCache2.getFallbackSemaphore().getNumberOfPermitsUsed());
assertFalse(fromCache2.isExecutionComplete());
assertFalse(fromCache2.isExecutedInThread());
assertEquals(null, fromCache2.getFailedExecutionException());
assertNull(fromCache2.getExecutionException());
assertCommandExecutionEvents(fromCache2, HystrixEventType.RESPONSE_FROM_CACHE, HystrixEventType.CANCELLED);
assertTrue(fromCache2.getExecutionTimeInMilliseconds() == -1);
assertFalse(fromCache2.isSuccessfulExecution());
assertEquals(0, fromCache2.metrics.getCurrentConcurrentExecutionCount());
assertSaneHystrixRequestLog(3);
} catch (InterruptedException ex) {
ex.printStackTrace();
}
}
use of rx.functions.Action0 in project Hystrix by Netflix.
the class HystrixCommandTest method testEarlyUnsubscribeDuringFallback.
@Test
public void testEarlyUnsubscribeDuringFallback() {
class AsyncCommand extends HystrixCommand<Boolean> {
public AsyncCommand() {
super(Setter.withGroupKey(HystrixCommandGroupKey.Factory.asKey("ASYNC")));
}
@Override
protected Boolean run() {
throw new RuntimeException("run failure");
}
@Override
protected Boolean getFallback() {
try {
Thread.sleep(500);
return false;
} catch (InterruptedException ex) {
throw new RuntimeException(ex);
}
}
}
HystrixCommand<Boolean> cmd = new AsyncCommand();
final CountDownLatch latch = new CountDownLatch(1);
Observable<Boolean> o = cmd.toObservable();
Subscription s = o.doOnUnsubscribe(new Action0() {
@Override
public void call() {
System.out.println("OnUnsubscribe");
latch.countDown();
}
}).subscribe(new Subscriber<Boolean>() {
@Override
public void onCompleted() {
System.out.println("OnCompleted");
latch.countDown();
}
@Override
public void onError(Throwable e) {
System.out.println("OnError : " + e);
}
@Override
public void onNext(Boolean b) {
System.out.println("OnNext : " + b);
}
});
try {
// give fallback a chance to fire
Thread.sleep(10);
s.unsubscribe();
assertTrue(latch.await(200, TimeUnit.MILLISECONDS));
assertEquals("Number of execution semaphores in use", 0, cmd.getExecutionSemaphore().getNumberOfPermitsUsed());
assertEquals("Number of fallback semaphores in use", 0, cmd.getFallbackSemaphore().getNumberOfPermitsUsed());
assertEquals(0, cmd.metrics.getCurrentConcurrentExecutionCount());
assertFalse(cmd.isExecutionComplete());
} catch (InterruptedException ex) {
ex.printStackTrace();
}
}
Aggregations