Upload
indicthreads
View
305
Download
2
Embed Size (px)
Citation preview
Reactive Programming
“a programming paradigm oriented around data flows and the propagation of change”
– Wikipedia
• Java VM implementation of ReactiveX
• An API for asynchronous programming with observable streams
What is Rx in RxJava?
RxJs
Rx.NET
RxScala
RxClojure RxSwift
Rx.rbRxPY
& Others
• Client Side
• Server Side
Applications of RxJava
Internal Processing
Service A
Service B
Service C
Request
Total Request Processing Time
Service Boundary
Parallel
SequentialResponse
Combine
RxJava
Observable
Subscriber
observeOn
subscribeOn
fromCallable
timer
interval
map
flatMaptimestampfilter
distinctUntilChanged
justerror
onErroronNextonCompleted
take
buffer
zip
combineLatest
concatmerge
Scheduler
iocomputation
newThread
Observer Pattern
Reactive
Functional
Asynchronous
Resiliency
TestSubscriber
TestScheduler
RxJavafromCallable
timer
interval justerror
ObservableSubscriber onErroronNext
onCompletedObserver Pattern
Reactivemap flatMap
timestampfilterdistinctUntilChanged
takebuffer
zipcombineLatest
concatmerge
Functional
observeOnsubscribeOnScheduler
io computation newThread
AsynchronousTestSubscriber
TestScheduler
Resiliencyretry timeout
onErrorResumeNext
ObservableSubscriber onErroronNext
onCompletedObserver Pattern
Reactive
Concept
fromCallabletimer
interval justerrorCreate map flatMap
timestampfilterdistinctUntilChanged
takebuffer
zipcombineLatest
concatmerge
Functional
Operate
observeOnsubscribeOnScheduler
io computation newThread
Asynchronous
Resiliencyretry timeout
onErrorResumeNextTestSubscriber
TestScheduler Concurrent
Handle
errorsTest
How to think in RxJava
Subscriber(Consumer)
Observable(Source)
2 onNext( )2 21 1onNext( )1
Source Consumersubscribe
Produces data/event asynchronously
Consumes data/event as they arrive
Pushes data/event
Observer & Iterator Pattern
onCompleted()
Observable Subscriber(Source) (Consumer)
unsubscribe
Pushes completion event
Observer & Iterator Pattern
Complete
onError( )XX X
Observable Subscriber(Source) (Consumer)
unsubscribe
Pushes error event
Observer & Iterator Pattern
Error
onNext( )1
Observable Subscriber
onError( )X
onCompleted()
Pushing Streams of Data/Events
Observer & Iterator Pattern
Subscriber<Integer> subscriber = Subscribers.create( n -> System.out.println(n), e -> System.out.print("Error"), () -> System.out.println("Completed") );
Observable<Integer> observable = Observable.just(1, 2, 3);
observable.subscribe(subscriber);
Subscriber<Integer> subscriber = Subscribers.create( n -> System.out.println(n), e -> System.out.print("Error"), () -> System.out.println("Completed") );
Subscriber<Integer> subscriber = Subscribers.create( n -> System.out.println(n), e -> System.out.println("Error"), () -> System.out.println("Completed"));
Subscriber<Integer> subscriber = Subscribers.create( n -> System.out.println(n), e -> System.out.println("Error"), () -> System.out.println("Completed") );
Subscriber<Integer> subscriber = Subscribers.create( n -> System.out.println(n), e -> System.out.println("Error"), () -> System.out.println("Completed") );
Observable<Integer> observable = Observable.just(1, 2, 3);
Subscriber<Integer> subscriber = Subscribers.create( n -> System.out.println(n), e -> System.out.println("Error"), () -> System.out.println("Completed") );
Observable<Integer> observable = Observable.just(1, 2, 3);
RxJava in ActionSource
Consumer
onNext onError
onCompleted
connect
Observable.just(1, 2, 3).subscribe( n -> System.out.println(n), e -> System.out.println("Error"), () -> System.out.println("Completed") );
1Output:
23Completed
RxJava in Action
Observable.fromCallable(new Callable<String>() { @Override public String call() throws Exception { return "result"; }}).subscribe( n -> System.out.println(n), e -> System.out.println(“Error"), () -> System.out.println("Completed") );
fromCallable
Observable.fromCallable(new Callable<String>() { @Override public String call() throws Exception { return "result"; }}).subscribe( n -> System.out.println(n), e -> System.out.println(“Error"), () -> System.out.println("Completed") );
Observable.fromCallable(() -> "result"); .subscribe( s -> System.out.println(s), e -> System.out.println("Error"), () -> System.out.println("Completed") );
fromCallable
Output:
result Completed
Observable.fromCallable(() -> "result"); .subscribe( s -> System.out.println(s), e -> System.out.println("Error"), () -> System.out.println("Completed") );
Observable.interval(1, TimeUnit.SECONDS) .take(2) .subscribe( n -> System.out.println(n), e -> System.out.println("Error"), () -> System.out.println("Completed") );
Output:
0 1 Completed
FilteringObservable.interval(1, TimeUnit.SECONDS) .take(2) .subscribe( n -> System.out.println(n), e -> System.out.println("Error"), () -> System.out.println("Completed") );
Observable.interval(1, TimeUnit.SECONDS) .take(2) .subscribe( n -> System.out.println(n), e -> System.out.println("Error"), () -> System.out.println("Completed") );
Observable.just("A", "B") .flatMap(e -> Observable.just(1, 2).map(n -> e + n)) .subscribe( n -> System.out.println(n), e -> System.out.println("Error"), () -> System.out.println("Completed") );
Output:
A1 A2 B1 B2 Completed
TransformingObservable.just("A", "B") .flatMap(e -> Observable.just(1, 2).map(n -> e + n)) .subscribe( n -> System.out.println(n), e -> System.out.println("Error"), () -> System.out.println("Completed") );
Observable.just("A", "B") .flatMap(e -> Observable.just(1, 2).map(n -> e + n)) .subscribe( n -> System.out.println(n), e -> System.out.println("Error"), () -> System.out.println("Completed") );
Observable.zip( Observable.just("A", "B", "C"), Observable.interval(1, TimeUnit.SECONDS), (a, n) -> a + n).subscribe( n -> System.out.println(n), e -> System.out.println("Error"), () -> System.out.println("Completed"));Output:
A0 B1 C2 Completed
CombiningObservable.zip( Observable.just("A", "B", "C"), Observable.interval(1, TimeUnit.SECONDS), (a, n) -> a + n).subscribe( n -> System.out.println(n), e -> System.out.println("Error"), () -> System.out.println("Completed") );
MultithreadingObservable .fromCallable(() -> { printThreadNameAnd("Observable"); return 1; }) .filter(n -> { printThreadNameAnd("Operator 1"); return n == 1; }) .map(n -> { printThreadNameAnd("Operator 2"); return "A" + n; }) .subscribe(n -> printThreadNameAnd(“Subscriber"));
printThreadNameAnd("Done subscribing");
Observable
Operator 1
Operator 2
Subscriber
Observable .fromCallable(() -> { printThreadNameAnd("Observable"); return 1; }) .filter(n -> { printThreadNameAnd("Operator 1"); return n == 1; }) .map(n -> { printThreadNameAnd("Operator 2"); return "A" + n; }) .subscribe(n -> printThreadNameAnd(“Subscriber"));
printThreadNameAnd("Done subscribing");
Observable .fromCallable(() -> { printThreadNameAnd("Observable"); return 1; }) .filter(n -> { printThreadNameAnd("Operator 1"); return n == 1; }) .map(n -> { printThreadNameAnd("Operator 2"); return "A" + n; }) .subscribe(n -> printThreadNameAnd(“Subscriber"));
printThreadNameAnd("Done subscribing");
Observable .fromCallable(() -> { printThreadNameAnd("Observable"); return 1; }) .filter(n -> { printThreadNameAnd("Operator 1"); return n == 1; }) .map(n -> { printThreadNameAnd("Operator 2"); return "A" + n; }) .subscribe(n -> printThreadNameAnd(“Subscriber"));
printThreadNameAnd("Done subscribing");
Observable .fromCallable(() -> { printThreadNameAnd("Observable"); return 1; }) .filter(n -> { printThreadNameAnd("Operator 1"); return n == 1; }) .map(n -> { printThreadNameAnd("Operator 2"); return "A" + n; }) .subscribe(n -> printThreadNameAnd(“Subscriber"));
printThreadNameAnd("Done subscribing");
Observable .fromCallable(() -> { printThreadNameAnd("Observable"); return 1; }) .filter(n -> { printThreadNameAnd("Operator 1"); return n == 1; }) .map(n -> { printThreadNameAnd("Operator 2"); return "A" + n; }) .subscribe(n -> printThreadNameAnd(“Subscriber"));
printThreadNameAnd("Done subscribing");
Observable .fromCallable(() -> { printThreadNameAnd("Observable"); return 1; }) .filter(n -> { printThreadNameAnd("Operator 1"); return n == 1; }) .map(n -> { printThreadNameAnd("Operator 2"); return "A" + n; }) .subscribe(n -> printThreadNameAnd(“Subscriber"));
printThreadNameAnd("Done subscribing");
Observable .fromCallable(() -> { printThreadNameAnd("Observable"); return 1; }) .filter(n -> { printThreadNameAnd("Operator 1"); return n == 1; }) .map(n -> { printThreadNameAnd("Operator 2"); return "A" + n; }) .subscribe(n -> printThreadNameAnd(“Subscriber"));
printThreadNameAnd("Done subscribing");
Observable .fromCallable(() -> { printThreadNameAnd("Observable"); return 1; }) .filter(n -> { printThreadNameAnd("Operator 1"); return n == 1; }) .map(n -> { printThreadNameAnd("Operator 2"); return "A" + n; }) .subscribe(n -> printThreadNameAnd(“Subscriber"));
printThreadNameAnd("Done subscribing");
Output:
main: Observable main: Operator 1 main: Operator 2 main: Subscriber main: Done subscribing
RxJava is blocking by
default
Multithreading
Observable .fromCallable(() -> { printThreadNameAnd("Observable"); return 1; }) .subscribeOn(Schedulers.io()) .filter(n -> { printThreadNameAnd("Operator 1"); return n == 1; }) .map(n -> { printThreadNameAnd("Operator 2"); return "A" + n; }) .subscribe(n -> printThreadNameAnd("Subscriber"));
printThreadNameAnd("Done subscribing");
Observable .fromCallable(() -> { printThreadNameAnd("Observable"); return 1; }) .subscribeOn(Schedulers.io()) .filter(n -> { printThreadNameAnd("Operator 1"); return n == 1; }) .map(n -> { printThreadNameAnd("Operator 2"); return "A" + n; }) .subscribe(n -> printThreadNameAnd("Subscriber"));
printThreadNameAnd("Done subscribing");
Output:
main: Done subscribing RxCachedThreadScheduler-1: Observable RxCachedThreadScheduler-1: Operator 1 RxCachedThreadScheduler-1: Operator 2 RxCachedThreadScheduler-1: SubscriberObservable
.fromCallable(() -> { printThreadNameAnd("Observable"); return 1; }) .subscribeOn(Schedulers.io()) .filter(n -> { printThreadNameAnd("Operator 1"); return n == 1; }) .map(n -> { printThreadNameAnd("Operator 2"); return "A" + n; }) .subscribe(n -> printThreadNameAnd("Subscriber"));
printThreadNameAnd("Done subscribing");
Observable .fromCallable(() -> { printThreadNameAnd("Observable"); return 1; }) .subscribeOn(Schedulers.io()) .filter(n -> { printThreadNameAnd("Operator 1"); return n == 1; }) .map(n -> { printThreadNameAnd("Operator 2"); return "A" + n; }) .subscribe(n -> printThreadNameAnd("Subscriber"));
printThreadNameAnd("Done subscribing");
Observable .fromCallable(() -> { printThreadNameAnd("Observable"); return 1; }) .subscribeOn(Schedulers.io()) .filter(n -> { printThreadNameAnd("Operator 1"); return n == 1; }) .map(n -> { printThreadNameAnd("Operator 2"); return "A" + n; }) .subscribe(n -> printThreadNameAnd("Subscriber"));
printThreadNameAnd("Done subscribing");
Observable .fromCallable(() -> { printThreadNameAnd("Observable"); return 1; }) .subscribeOn(Schedulers.io()) .filter(n -> { printThreadNameAnd("Operator 1"); return n == 1; }) .map(n -> { printThreadNameAnd("Operator 2"); return "A" + n; }) .subscribe(n -> printThreadNameAnd("Subscriber"));
printThreadNameAnd("Done subscribing");
Observable .fromCallable(() -> { printThreadNameAnd("Observable"); return 1; }) .subscribeOn(Schedulers.io()) .filter(n -> { printThreadNameAnd("Operator 1"); return n == 1; }) .map(n -> { printThreadNameAnd("Operator 2"); return "A" + n; }) .subscribe(n -> printThreadNameAnd("Subscriber"));
printThreadNameAnd("Done subscribing");
Observable .fromCallable(() -> { printThreadNameAnd("Observable"); return 1; }) .subscribeOn(Schedulers.io()) .filter(n -> { printThreadNameAnd("Operator 1"); return n == 1; }) .map(n -> { printThreadNameAnd("Operator 2"); return "A" + n; }) .subscribe(n -> printThreadNameAnd("Subscriber"));
printThreadNameAnd("Done subscribing");
Multithreading
Observable .fromCallable(() -> { printThreadNameAnd("Observable"); return 1; }) .subscribeOn(Schedulers.io()) .filter(n -> { printThreadNameAnd("Operator 1"); return n == 1; }) .observeOn(Schedulers.newThread()) .map(n -> { printThreadNameAnd("Operator 2"); return "A" + n; }) .subscribe(n -> printThreadNameAnd("Subscriber"));
printThreadNameAnd("Done subscribing");
Output:
main: Done subscribing RxCachedThreadScheduler-1: Observable RxCachedThreadScheduler-1: Operator 1 RxNewThreadScheduler-1: Operator 2 RxNewThreadScheduler-1: SubscriberObservable
.fromCallable(() -> { printThreadNameAnd("Observable"); return 1; }) .subscribeOn(Schedulers.io()) .filter(n -> { printThreadNameAnd("Operator 1"); return n == 1; }) .observeOn(Schedulers.newThread()) .map(n -> { printThreadNameAnd("Operator 2"); return "A" + n; }) .subscribe(n -> printThreadNameAnd("Subscriber"));
printThreadNameAnd("Done subscribing");
Observable .fromCallable(() -> { printThreadNameAnd("Observable"); return 1; }) .subscribeOn(Schedulers.io()) .filter(n -> { printThreadNameAnd("Operator 1"); return n == 1; }) .observeOn(Schedulers.newThread()) .map(n -> { printThreadNameAnd("Operator 2"); return "A" + n; }) .subscribe(n -> printThreadNameAnd("Subscriber"));
printThreadNameAnd("Done subscribing");
Observable .fromCallable(() -> { printThreadNameAnd("Observable"); return 1; }) .subscribeOn(Schedulers.io()) .filter(n -> { printThreadNameAnd("Operator 1"); return n == 1; }) .observeOn(Schedulers.newThread()) .map(n -> { printThreadNameAnd("Operator 2"); return "A" + n; }) .subscribe(n -> printThreadNameAnd("Subscriber"));
printThreadNameAnd("Done subscribing");
Observable .fromCallable(() -> { printThreadNameAnd("Observable"); return 1; }) .subscribeOn(Schedulers.io()) .filter(n -> { printThreadNameAnd("Operator 1"); return n == 1; }) .observeOn(Schedulers.newThread()) .map(n -> { printThreadNameAnd("Operator 2"); return "A" + n; }) .subscribe(n -> printThreadNameAnd("Subscriber"));
printThreadNameAnd("Done subscribing");
Observable .fromCallable(() -> { printThreadNameAnd("Observable"); return 1; }) .subscribeOn(Schedulers.io()) .filter(n -> { printThreadNameAnd("Operator 1"); return n == 1; }) .observeOn(Schedulers.newThread()) .map(n -> { printThreadNameAnd("Operator 2"); return "A" + n; }) .subscribe(n -> printThreadNameAnd("Subscriber"));
printThreadNameAnd("Done subscribing");
Observable .fromCallable(() -> { printThreadNameAnd("Observable"); return 1; }) .subscribeOn(Schedulers.io()) .filter(n -> { printThreadNameAnd("Operator 1"); return n == 1; }) .observeOn(Schedulers.newThread()) .map(n -> { printThreadNameAnd("Operator 2"); return "A" + n; }) .subscribe(n -> printThreadNameAnd("Subscriber"));
printThreadNameAnd("Done subscribing");
Observable .fromCallable(() -> { printThreadNameAnd("Observable"); return 1; }) .subscribeOn(Schedulers.io()) .filter(n -> { printThreadNameAnd("Operator 1"); return n == 1; }) .observeOn(Schedulers.newThread()) .map(n -> { printThreadNameAnd("Operator 2"); return "A" + n; }) .subscribe(n -> printThreadNameAnd("Subscriber"));
printThreadNameAnd("Done subscribing");
Multithreading
Scheduler• Schedulers.newThread()
• Schedulers.io()
• Schedulers.computation()
• Schedulers.from(java.util.concurrent.Executor executor)
Observable.interval(1, TimeUnit.SECONDS) .take(3) .subscribe( n -> printThreadNameAnd("Subscriber"), e -> System.out.println("Error"), () -> System.out.println("Completed") );
Output:
RxComputationThreadPool-1: Subscriber RxComputationThreadPool-1: Subscriber RxComputationThreadPool-1: Subscriber Completed
Scheduler
Scheduler:
interval operates by default on the computation Scheduler.
Default error handlingObservable.fromCallable(() -> { throw new IOException(); }) .subscribe( n -> System.out.println(n), throwable -> printErrorClassName(throwable), () -> System.out.println("Completed") );
Output:
Error: IOException
Observable.fromCallable(() -> { throw new IOException(); }) .subscribe( n -> System.out.println(n), throwable -> printErrorClassName(throwable), () -> System.out.println("Completed") );
Observable.fromCallable(() -> { throw new IOException(); }) .subscribe( n -> System.out.println(n), throwable -> printErrorClassName(throwable), () -> System.out.println("Completed") );
Observable
throws
Exceptionhandled
in onError
Default error handlingObservable.just("A") .map(text -> Integer.parseInt(text)) .subscribe( n -> System.out.println(n), throwable -> printErrorClassName(throwable), () -> System.out.println("Completed") );
Output:
Error: NumberFormatException
Observable.just("A") .map(text -> Integer.parseInt(text)) .subscribe( n -> System.out.println(n), throwable -> printErrorClassName(throwable), () -> System.out.println("Completed") );
Observable.just("A") .map(text -> Integer.parseInt(text)) .subscribe( n -> System.out.println(n), throwable -> printErrorClassName(throwable), () -> System.out.println("Completed") );
Operator
throws
Exception
handled
in onError
Errors not handledObservable.just("A") .map(text -> Integer.parseInt(text)) .subscribe( n -> System.out.println(n), throwable -> { throw new RuntimeException(); }, () -> System.out.println("Completed") );
Output:
Exception in thread "main" rx.exceptions.OnErrorFailedException: Error occurred when trying to propagate error to Observer.onError
Observable.just("A") .map(text -> Integer.parseInt(text)) .subscribe( n -> System.out.println(n), throwable -> { throw new RuntimeException(); }, () -> System.out.println("Completed") );
Observable.just("A") .map(text -> Integer.parseInt(text)) .subscribe( n -> System.out.println(n), throwable -> { throw new RuntimeException(); }, () -> System.out.println("Completed") ); onError
throws
Exception
Errors not handledObservable.just("A") .map(text -> Integer.parseInt(text)) .subscribe( n -> System.out.println(n) );
Output:
Exception in thread "main" rx.exceptions.OnErrorNotImplementedException
Observable.just("A") .map(text -> Integer.parseInt(text)) .subscribe( n -> System.out.println(n) );
onError
function
missing
Closing the stream gracefullyObservable.error(new IOException()) .onErrorReturn(throwable -> -1) .subscribe( n -> System.out.println(n), throwable -> printErrorClassName(throwable), () -> System.out.println("Completed") );
Output:
-1 Completed
Observable.error(new IOException()) .onErrorReturn(throwable -> -1) .subscribe( n -> System.out.println(n), throwable -> printErrorClassName(throwable), () -> System.out.println("Completed") );
Observable.error(new IOException()) .onErrorReturn(throwable -> -1) .subscribe( n -> System.out.println(n), throwable -> printErrorClassName(throwable), () -> System.out.println("Completed") );
handling error
by retuning a value
indicating error
Using a backupObservable<Integer> aService = Observable .error(new IOException());Observable<Integer> backupService = Observable.just(1); aService .onErrorResumeNext(backupService) .subscribe( n -> System.out.println(n), throwable -> printErrorClassName(throwable), () -> System.out.println("Completed") );
Output:
1 Completed
Observable<Integer> aService = Observable .error(new IOException());Observable<Integer> backupService = Observable.just(1); aService .onErrorResumeNext(backupService) .subscribe( n -> System.out.println(n), throwable -> printErrorClassName(throwable), () -> System.out.println("Completed") );
Observable<Integer> aService = Observable .error(new IOException());Observable<Integer> backupService = Observable.just(1); aService .onErrorResumeNext(backupService) .subscribe( n -> System.out.println(n), throwable -> printErrorClassName(throwable), () -> System.out.println("Completed") );
resuming
with
another service
RetryingObservable.error(new IOException()) .retryWhen(errorStream -> Observable.range(1, 3) .zipWith(errorStream, (n, e) -> n) .doOnNext(n -> System.out.println("Retry: " + n)) ).subscribe( n -> System.out.println(n), throwable -> printErrorClassName(throwable), () -> System.out.println("Completed") );
Output:
Retry: 1 Retry: 2 Retry: 3 Completed
Observable.error(new IOException()) .retryWhen(errorStream -> Observable.range(1, 3) .zipWith(errorStream, (n, e) -> n) .doOnNext(n -> System.out.println("Retry: " + n)) ).subscribe( n -> System.out.println(n), throwable -> printErrorClassName(throwable), () -> System.out.println("Completed") );
Observable.error(new IOException()) .retryWhen(errorStream -> Observable.range(1, 3) .zipWith(errorStream, (n, e) -> n) .doOnNext(n -> System.out.println("Retry: " + n)) ).subscribe( n -> System.out.println(n), throwable -> printErrorClassName(throwable), () -> System.out.println("Completed") ); conditional
retry logic
TestSubscriberTestSubscriber<Long> testSubscriber = TestSubscriber.create();
Observable.interval(1, TimeUnit.SECONDS).take(2) .subscribe(testSubscriber); testSubscriber.awaitTerminalEvent();
testSubscriber.assertCompleted(); testSubscriber.assertNoErrors(); testSubscriber.assertUnsubscribed(); testSubscriber.assertValueCount(2); testSubscriber.assertValues(0L, 1L);
TestSchedulerTestScheduler testScheduler = Schedulers.test(); TestSubscriber<Long> testSubscriber = TestSubscriber.create(); Observable.interval(1, TimeUnit.SECONDS, testScheduler) .take(2).subscribe(testSubscriber); testScheduler.advanceTimeTo(1500, TimeUnit.MILLISECONDS); testSubscriber.assertValueCount(1);testSubscriber.assertNotCompleted(); testScheduler.advanceTimeBy(1000, TimeUnit.MILLISECONDS); testSubscriber.assertValueCount(2);testSubscriber.assertCompleted();
How to think in RxJavafromCallable
timer
interval justerror
ObservableSubscriber onErroronNext
onCompletedObserver Pattern
Reactivemap flatMap
timestampfilterdistinctUntilChanged
takebuffer
zipcombineLatest
concatmerge
Functional
observeOnsubscribeOnScheduler
io computation newThread
AsynchronousTestSubscriber
TestScheduler
Resiliencyretry timeout
onErrorResumeNext
ObservableSubscriber onErroronNext
onCompletedObserver Pattern
Reactive
Concept
fromCallabletimer
interval justerrorCreate map flatMap
timestampfilterdistinctUntilChanged
takebuffer
zipcombineLatest
concatmerge
Functional
Operate
observeOnsubscribeOnScheduler
io computation newThread
Asynchronous
Resiliencyretry timeout
onErrorResumeNextTestSubscriber
TestScheduler Concurrent
Handle
errorsTest