SlideShare a Scribd company logo
RXJAVA
AS A KEY COMPONENT
IN A MATURE
BIG DATA PRODUCT
by Igor Lozynskyi
HELLO!I am Igor Lozynskyi
I have 8 years of Java experience, currently work at
You can find me at @siromaha
2
Agenda
■ RxJava basics
■ Zoomdata (goals & architecture)
■ “Good” & “bad” RxJava experience
■ Some thoughts about Rx future
3
Disclaimer
■ This isn’t a sponsored talk!
■ This talk isn’t Zoomdata advertisement!
■ It’s just our experience.
4
WHAT IS
ZOOMDATA?
The Fastest Visual Analytics for Big Data
www.zoomdata.com
5
■ Data visualization software
■ Big Data
■ 30+ DB types
■ SQL, NoSQL, raw data (CSV)
■ Pretty charts
■ Platform!
Zoomdata (ZD):
6
cross-database JOIN
7
8
■ Static is boring
■ Dynamic is interesting
Instant feedback
■ We do not like to wait
9
ZOOMDATA
ARCHITECTURE
very simplified view
10
very
11
12
Let’s code it!
13
15
class QueryProcessor implements Observable.Transformer<QueryRequest, QueryResult> {
Observable<QueryResult> call(Observable<QueryRequest> requests) {
...
}
}
17
class QueryProcessor implements Observable.Transformer<QueryRequest, QueryResult> {
Observable<QueryResult> call(Observable<QueryRequest> requests) {
return requests
.takeWhile(req -> !isCancellation(req))
.map(this::validateRequest)
.compose(r -> requestProcessor(r))
.onErrorReturn(this::handleProcessingErrors)
}
Observable<QueryResult> requestProcessor(Observable<QueryRequestParsed> requests) {
return mainQuery(requests);
}
}
19
class QueryProcessor implements Observable.Transformer<QueryRequest, QueryResult> {
Observable<QueryResult> call(Observable<QueryRequest> requests) {
return requests
.takeWhile(req -> !isCancellation(req))
.map(this::validateRequest)
.compose(r -> requestProcessor(r))
.onErrorReturn(this::handleProcessingErrors)
}
Observable<QueryResult> requestProcessor(Observable<QueryRequestParsed> requests) {
return merge(
mainQuery(requests),
intermediateResults(requests) // approximate result
);
}
}
21
class QueryProcessor implements Observable.Transformer<QueryRequest, QueryResult> {
Observable<QueryResult> call(Observable<QueryRequest> requests) {
return requests
.takeWhile(req -> !isCancellation(req))
.map(this::validateRequest)
.compose(r -> requestProcessor(r))
.onErrorReturn(this::handleProcessingErrors)
}
Observable<QueryResult> requestProcessor(Observable<QueryRequestParsed> request) {
return merge(
mainQuery(requests),
intermediateResults(requests),
mainQueryProgress(requests) // based on main query
);
}
}
It was easy!
23
OUR RXJAVA
EXPERIENCE
Disclaimer:
■ Your mileage may vary!
24
GOODRxJava
25
Effortless mapping of
WebSocket to
Observable Stream
26
27
class RxWebSocketSession<T extends WebSocketMessage<?>> {
spring.WebSocketSession nativeSession;
Subject<T, T> inputSubject;
Subscriber<T> socketSubscriber;
public RxWebSocketSession(spring.WebSocketSession nativeSession) {
...
}
public Observable<T> getInput() {
return inputSubject;
}
public Subscriber<T> getOutput() {
return socketSubscriber;
}
...
}
28
class NativeWebSocketHandler extends TextWebSocketHandler {
IRxWebSocketHandler<TextMessage> sessionHandler;
Map<WebSocketSession, RxWebSocketSession<TextMessage>> sessions;
void afterConnectionEstablished(WebSocketSession session) {
RxWebSocketSession<TextMessage> rxSession
= new RxWebSocketSession<>(synchronizedSession(session));
sessions.put(session, rxSession);
sessionHandler.afterConnectionEstablished(rxSession);
}
void handleTextMessage(WebSocketSession session, TextMessage message) {
sessions.get(session).handleMessage(message);
}
void afterConnectionClosed(WebSocketSession session, CloseStatus status) {
RxWebSocketSession<TextMessage> rxSession = sessions.remove(session);
rxSession.close();
sessionHandler.afterConnectionClosed(rxSession, status);
}
}
29
class RxWebSocketHandler implements IRxWebSocketHandler<TextMessage> {
rx.Observable.Transformer<String, String> messageTransformer;
rx.Scheduler sendingIoScheduler;
public void afterConnectionEstablished(RxWebSocketSession<TextMessage> session) {
session
.getInput()
.map(TextMessage::getPayload)
.compose(messageTransformer)
.onBackpressureBuffer(OUTGOING_WS_BUFFER_CAPACITY,
() -> reportMessageDropped(session.getId()),
ON_OVERFLOW_DROP_OLDEST)
.observeOn(sendingIoScheduler)
.map(TextMessage::new)
.subscribe(session.getOutput());
}
}
It is easy to stream
intermediate results
to a client
30
It is easy to coordinate complex
& long running workflows
31
RxJava
allows to compose
dozens of
reactive streams
32
Query Cancellation
out-of-the-box
33
RxJava is
very powerful
Any stream
transformation
that you can imagine!
Image credits: Denys Nevozhai
“BAD”RxJava
35
Use TDD for Rx code!
Lack of unit tests
for Rx code
Many integration tests
instead
36Image credits: Matthew Henry
Stream code should not be too
complicated!
Rule: “10 lines max” for method
37
38
protected Observable<Map<QueryStream, ComputedTasks>> play(Map<QueryStream, ComputedTasks> initial) {
return concat(just(primaryTimeWindow), timeWindowStream)
.map(tw ->
playingReadRequests.columnKeySet().stream()
.collect(toMap(
calc -> calc,
calc -> calc.calculateTimewindow(tw)))
)
.buffer(2, 1)
.filter(contextsMaps -> contextsMaps.size() == 2)
.zipWith(checkPointsStream::iterator, Pair::of)
.scan(initialTasksByTimewindow, (tasksMap, actions) -> {
Map<TimewindowCalculator, List<ReadAction>> actionsByWindow = actions.getLeft();
Boolean doCheckpoint = actions.getRight();
Map<TimewindowCalculator, Map<QueryStream, ComputedTasks>> tasksByTimewindow = MapStream.of(actionsByWindow)
.map(e -> {
TimewindowCalculator timewindow = e.getKey();
List<ReadAction> timewindowActions = e.getValue();
Map<QueryStream, ComputedTasks> tasksOfTimewindow = tasksMap.get(timewindow);
Map<QueryStream, ComputedTasks> tasksByStream = calculateStreamTasksWithActions(timewindow,
tasksOfTimewindow, timewindowActions, doCheckpoint);
return Pair.of(timewindow, tasksByStream);
}).collect(toMap(Pair::getKey, Pair::getValue));
return tasksByTimewindow;
})
.map(tasksByTimewindow -> {
Collection<Map<QueryStream, ComputedTasks>> tasksByStreamMaps = tasksByTimewindow.values();
return mergeTasksMapsByStream(tasksByStreamMaps);
})
.doOnNext(this::rememberLastTasksReference)
.skip(1);
}
39
protected Observable<Map<QueryStream, ComputedTasks>> play(Map<QueryStream, ComputedTasks> initial) {
return concat(just(primaryTimeWindow), timeWindowStream)
.map(tw ->
playingReadRequests.columnKeySet().stream()
.collect(toMap(
calc -> calc,
calc -> calc.calculateTimewindow(tw)))
)
.buffer(2, 1)
.filter(contextsMaps -> contextsMaps.size() == 2)
.zipWith(checkPointsStream::iterator, Pair::of)
.scan(initialTasksByTimewindow, (tasksMap, actions) -> {
Map<TimewindowCalculator, List<ReadAction>> actionsByWindow = actions.getLeft();
Boolean doCheckpoint = actions.getRight();
Map<TimewindowCalculator, Map<QueryStream, ComputedTasks>> tasksByTimewindow = MapStream.of(actionsByWindow)
.map(e -> {
TimewindowCalculator timewindow = e.getKey();
List<ReadAction> timewindowActions = e.getValue();
Map<QueryStream, ComputedTasks> tasksOfTimewindow = tasksMap.get(timewindow);
Map<QueryStream, ComputedTasks> tasksByStream = calculateStreamTasksWithActions(timewindow,
tasksOfTimewindow, timewindowActions, doCheckpoint);
return Pair.of(timewindow, tasksByStream);
}).collect(toMap(Pair::getKey, Pair::getValue));
return tasksByTimewindow;
})
.map(tasksByTimewindow -> {
Collection<Map<QueryStream, ComputedTasks>> tasksByStreamMaps = tasksByTimewindow.values();
return mergeTasksMapsByStream(tasksByStreamMaps);
})
.doOnNext(this::rememberLastTasksReference)
.skip(1);
}
40
protected Observable<Map<QueryStream, ComputedTasks>> play(Map<QueryStream, ComputedTasks> initial) {
return concat(just(primaryTimeWindow), timeWindowStream)
.map(this::calculateTimeWindows)
.buffer(2, 1)
.filter(this::contextMapsOfSizeTwo)
.zipWith(checkPointsStream::iterator, Pair::of)
.scan(initialTasksByTimewindow, this::updateJobResultsForNewTimeWindow)
.map(tasksByTimewindow -> mergeTaskMapsByStream(tasksByTimewindow.values()))
.doOnNext(this::rememberLastTasksReference)
.skip(1);
}
41
protected Observable<Map<QueryStream, ComputedTasks>> play(Map<QueryStream, ComputedTasks> initial) {
return concat(just(primaryTimeWindow), timeWindowStream)
.map(this::calculateTimeWindows)
.buffer(2, 1)
.filter(this::contextMapsOfSizeTwo)
.map(this::transitionWindow)
.zipWith(checkPointsStream::iterator, Pair::of)
.scan(initialTasksByTimewindow, this::updateJobResultsForNewTimeWindow)
.map(tasksByTimewindow -> mergeTaskMapsByStream(tasksByTimewindow.values()))
.doOnNext(this::rememberLastTasksReference)
.skip(1);
}
It is easy to forget
about one very
important thing
42
Remember next slide
Image credits: Oscar Sutton
43
BACKPRESSURE
44
BACKPRESSURE
BACK
PRES
Image credits: Google search
Remember not to overflow
your client!
Your client will not be happy
47
Remember not to overflow
yourself!
48
Slow subscriber may cause data
buffering
Buffering may be costly
49
Rx
silently introduces
a notion of time
into your API
50
51
Track your stream lifetime!
GroupBy operator
52
53
Track your stream lifetime!
54
Child streams live along with
parent!
55
Track your stream lifetime!
Unpleasant when child streams hold
resources
56
Subscription takes some time
Be careful not to miss messages
57
58
Reactive transformations are
time dependent
59
Zoomdata had an issue due to this
60
https://github.com/ReactiveX/RxJava/issues/3522 (fixed in 1.0.15)
61
Hard to code complicated
context-dependent workflow
■ Loop vs flatMap
■ State should be incorporated into the stream!
62
Try not to mutate objects
inside Rx streams
■ Rx stream is a concurrent system
■ In concurrent systems mutation is evil
■ Zoomdata had such issues
63
Think twice before providing
pull API over Rx stream
64
■ Pull push hard & risky
■ Pull push mutability disaster
Think twice before providing
pull API over Rx stream
■ Push pull ok
65
It is better to control
execution threads
on your own
■ Doing CPU in IO thread
■ Doing IO in CPU thread
66Image credits: Haiku Deck
Care about concurrency
■ No ThreadLocal tricks!
■ flatMap/zip/merge may move execution into
unexpected (for you) thread
■ Immutability is the only reasonable way to go
67
and, last but not least...
68
Complexity is
still there!
69Image credits: sciencemag.org
OVERALL
EXPERIENCE
70
■ WebSocket to Rx stream mapping: 3 files
■ ZD query processing is almost entirely RxJava code
■ Most algorithms live in 10 files (~1000 loc)
□ playing, sharpening, progress, timeline, push/pull data
strategies, main query, timeline, and much more
■ RxJava is complicated, but very powerful
■ Zoomdata benefits a lot from RxJava usage!
Is RxJava good enough for ZD?
71
■ Java 9 & Spring 5 will spread reactive programming
■ We expect big shift towards Project Reactor
■ We will have more reactive and proactive software!
□ Zoomdata is already proactive
Some thoughts about Rx future
72
THANKS!
Contact me:
@siromaha
aigooor [at] gmail [dot] com
Presentation template by SlidesCarnival
Image credits: Denys Nevozhai

More Related Content

What's hot

Cassandra Summit EU 2014 Lightning talk - Paging (no animation)
Cassandra Summit EU 2014 Lightning talk - Paging (no animation)Cassandra Summit EU 2014 Lightning talk - Paging (no animation)
Cassandra Summit EU 2014 Lightning talk - Paging (no animation)
Christopher Batey
 
Qt Rest Server
Qt Rest ServerQt Rest Server
Qt Rest Server
Vasiliy Sorokin
 
JS Fest 2019. Thomas Watson. Post-Mortem Debugging in Node.js
JS Fest 2019. Thomas Watson. Post-Mortem Debugging in Node.jsJS Fest 2019. Thomas Watson. Post-Mortem Debugging in Node.js
JS Fest 2019. Thomas Watson. Post-Mortem Debugging in Node.js
JSFestUA
 
Marble Testing RxJS streams
Marble Testing RxJS streamsMarble Testing RxJS streams
Marble Testing RxJS streams
Ilia Idakiev
 
Instant add column for inno db in mariadb 10.3+ (fosdem 2018, second draft)
Instant add column for inno db in mariadb 10.3+ (fosdem 2018, second draft)Instant add column for inno db in mariadb 10.3+ (fosdem 2018, second draft)
Instant add column for inno db in mariadb 10.3+ (fosdem 2018, second draft)
Valerii Kravchuk
 
FOSDEM 2015: gdb tips and tricks for MySQL DBAs
FOSDEM 2015: gdb tips and tricks for MySQL DBAsFOSDEM 2015: gdb tips and tricks for MySQL DBAs
FOSDEM 2015: gdb tips and tricks for MySQL DBAs
Valerii Kravchuk
 
MongoDB Performance Debugging
MongoDB Performance DebuggingMongoDB Performance Debugging
MongoDB Performance Debugging
MongoDB
 
MySQL Parallel Replication: inventory, use-case and limitations
MySQL Parallel Replication: inventory, use-case and limitationsMySQL Parallel Replication: inventory, use-case and limitations
MySQL Parallel Replication: inventory, use-case and limitations
Jean-François Gagné
 
Circuit breaker
Circuit breakerCircuit breaker
Circuit breaker
bricemciver
 
Tracing and profiling my sql (percona live europe 2019) draft_1
Tracing and profiling my sql (percona live europe 2019) draft_1Tracing and profiling my sql (percona live europe 2019) draft_1
Tracing and profiling my sql (percona live europe 2019) draft_1
Valerii Kravchuk
 
MySQL Parallel Replication (LOGICAL_CLOCK): all the 5.7 (and some of the 8.0)...
MySQL Parallel Replication (LOGICAL_CLOCK): all the 5.7 (and some of the 8.0)...MySQL Parallel Replication (LOGICAL_CLOCK): all the 5.7 (and some of the 8.0)...
MySQL Parallel Replication (LOGICAL_CLOCK): all the 5.7 (and some of the 8.0)...
Jean-François Gagné
 
More on gdb for my sql db as (fosdem 2016)
More on gdb for my sql db as (fosdem 2016)More on gdb for my sql db as (fosdem 2016)
More on gdb for my sql db as (fosdem 2016)
Valeriy Kravchuk
 
Riding the Binlog: an in Deep Dissection of the Replication Stream
Riding the Binlog: an in Deep Dissection of the Replication StreamRiding the Binlog: an in Deep Dissection of the Replication Stream
Riding the Binlog: an in Deep Dissection of the Replication Stream
Jean-François Gagné
 
Gdb basics for my sql db as (openfest 2017) final
Gdb basics for my sql db as (openfest 2017) finalGdb basics for my sql db as (openfest 2017) final
Gdb basics for my sql db as (openfest 2017) final
Valeriy Kravchuk
 
MySQL/MariaDB Parallel Replication: inventory, use-case and limitations
MySQL/MariaDB Parallel Replication: inventory, use-case and limitationsMySQL/MariaDB Parallel Replication: inventory, use-case and limitations
MySQL/MariaDB Parallel Replication: inventory, use-case and limitations
Jean-François Gagné
 
What is row level isolation on cassandra
What is row level isolation on cassandraWhat is row level isolation on cassandra
What is row level isolation on cassandra
Kazutaka Tomita
 
Compact and safely: static DSL on Kotlin
Compact and safely: static DSL on KotlinCompact and safely: static DSL on Kotlin
Compact and safely: static DSL on Kotlin
Dmitry Pranchuk
 
Vertically Scaled Design Patters
Vertically Scaled Design PattersVertically Scaled Design Patters
Vertically Scaled Design Patters
Jeff Malnick
 
Construire une application JavaFX 8 avec gradle
Construire une application JavaFX 8 avec gradleConstruire une application JavaFX 8 avec gradle
Construire une application JavaFX 8 avec gradle
Thierry Wasylczenko
 
Gdb basics for my sql db as (percona live europe 2019)
Gdb basics for my sql db as (percona live europe 2019)Gdb basics for my sql db as (percona live europe 2019)
Gdb basics for my sql db as (percona live europe 2019)
Valerii Kravchuk
 

What's hot (20)

Cassandra Summit EU 2014 Lightning talk - Paging (no animation)
Cassandra Summit EU 2014 Lightning talk - Paging (no animation)Cassandra Summit EU 2014 Lightning talk - Paging (no animation)
Cassandra Summit EU 2014 Lightning talk - Paging (no animation)
 
Qt Rest Server
Qt Rest ServerQt Rest Server
Qt Rest Server
 
JS Fest 2019. Thomas Watson. Post-Mortem Debugging in Node.js
JS Fest 2019. Thomas Watson. Post-Mortem Debugging in Node.jsJS Fest 2019. Thomas Watson. Post-Mortem Debugging in Node.js
JS Fest 2019. Thomas Watson. Post-Mortem Debugging in Node.js
 
Marble Testing RxJS streams
Marble Testing RxJS streamsMarble Testing RxJS streams
Marble Testing RxJS streams
 
Instant add column for inno db in mariadb 10.3+ (fosdem 2018, second draft)
Instant add column for inno db in mariadb 10.3+ (fosdem 2018, second draft)Instant add column for inno db in mariadb 10.3+ (fosdem 2018, second draft)
Instant add column for inno db in mariadb 10.3+ (fosdem 2018, second draft)
 
FOSDEM 2015: gdb tips and tricks for MySQL DBAs
FOSDEM 2015: gdb tips and tricks for MySQL DBAsFOSDEM 2015: gdb tips and tricks for MySQL DBAs
FOSDEM 2015: gdb tips and tricks for MySQL DBAs
 
MongoDB Performance Debugging
MongoDB Performance DebuggingMongoDB Performance Debugging
MongoDB Performance Debugging
 
MySQL Parallel Replication: inventory, use-case and limitations
MySQL Parallel Replication: inventory, use-case and limitationsMySQL Parallel Replication: inventory, use-case and limitations
MySQL Parallel Replication: inventory, use-case and limitations
 
Circuit breaker
Circuit breakerCircuit breaker
Circuit breaker
 
Tracing and profiling my sql (percona live europe 2019) draft_1
Tracing and profiling my sql (percona live europe 2019) draft_1Tracing and profiling my sql (percona live europe 2019) draft_1
Tracing and profiling my sql (percona live europe 2019) draft_1
 
MySQL Parallel Replication (LOGICAL_CLOCK): all the 5.7 (and some of the 8.0)...
MySQL Parallel Replication (LOGICAL_CLOCK): all the 5.7 (and some of the 8.0)...MySQL Parallel Replication (LOGICAL_CLOCK): all the 5.7 (and some of the 8.0)...
MySQL Parallel Replication (LOGICAL_CLOCK): all the 5.7 (and some of the 8.0)...
 
More on gdb for my sql db as (fosdem 2016)
More on gdb for my sql db as (fosdem 2016)More on gdb for my sql db as (fosdem 2016)
More on gdb for my sql db as (fosdem 2016)
 
Riding the Binlog: an in Deep Dissection of the Replication Stream
Riding the Binlog: an in Deep Dissection of the Replication StreamRiding the Binlog: an in Deep Dissection of the Replication Stream
Riding the Binlog: an in Deep Dissection of the Replication Stream
 
Gdb basics for my sql db as (openfest 2017) final
Gdb basics for my sql db as (openfest 2017) finalGdb basics for my sql db as (openfest 2017) final
Gdb basics for my sql db as (openfest 2017) final
 
MySQL/MariaDB Parallel Replication: inventory, use-case and limitations
MySQL/MariaDB Parallel Replication: inventory, use-case and limitationsMySQL/MariaDB Parallel Replication: inventory, use-case and limitations
MySQL/MariaDB Parallel Replication: inventory, use-case and limitations
 
What is row level isolation on cassandra
What is row level isolation on cassandraWhat is row level isolation on cassandra
What is row level isolation on cassandra
 
Compact and safely: static DSL on Kotlin
Compact and safely: static DSL on KotlinCompact and safely: static DSL on Kotlin
Compact and safely: static DSL on Kotlin
 
Vertically Scaled Design Patters
Vertically Scaled Design PattersVertically Scaled Design Patters
Vertically Scaled Design Patters
 
Construire une application JavaFX 8 avec gradle
Construire une application JavaFX 8 avec gradleConstruire une application JavaFX 8 avec gradle
Construire une application JavaFX 8 avec gradle
 
Gdb basics for my sql db as (percona live europe 2019)
Gdb basics for my sql db as (percona live europe 2019)Gdb basics for my sql db as (percona live europe 2019)
Gdb basics for my sql db as (percona live europe 2019)
 

Similar to [JEEConf-2017] RxJava as a key component in mature Big Data product

Rx java in action
Rx java in actionRx java in action
Rx java in action
Pratama Nur Wijaya
 
RxJava applied [JavaDay Kyiv 2016]
RxJava applied [JavaDay Kyiv 2016]RxJava applied [JavaDay Kyiv 2016]
RxJava applied [JavaDay Kyiv 2016]
Igor Lozynskyi
 
Practical RxJava for Android
Practical RxJava for AndroidPractical RxJava for Android
Practical RxJava for Android
Tomáš Kypta
 
Using Apache Spark to Solve Sessionization Problem in Batch and Streaming
Using Apache Spark to Solve Sessionization Problem in Batch and StreamingUsing Apache Spark to Solve Sessionization Problem in Batch and Streaming
Using Apache Spark to Solve Sessionization Problem in Batch and Streaming
Databricks
 
Reactive Programming Patterns with RxSwift
Reactive Programming Patterns with RxSwiftReactive Programming Patterns with RxSwift
Reactive Programming Patterns with RxSwift
Florent Pillet
 
Example R usage for oracle DBA UKOUG 2013
Example R usage for oracle DBA UKOUG 2013Example R usage for oracle DBA UKOUG 2013
Example R usage for oracle DBA UKOUG 2013
BertrandDrouvot
 
Kick your database_to_the_curb_reston_08_27_19
Kick your database_to_the_curb_reston_08_27_19Kick your database_to_the_curb_reston_08_27_19
Kick your database_to_the_curb_reston_08_27_19
confluent
 
Qt & Webkit
Qt & WebkitQt & Webkit
Qt & Webkit
QT-day
 
Building Scalable Stateless Applications with RxJava
Building Scalable Stateless Applications with RxJavaBuilding Scalable Stateless Applications with RxJava
Building Scalable Stateless Applications with RxJava
Rick Warren
 
Nextcon samza preso july - final
Nextcon samza preso   july - finalNextcon samza preso   july - final
Nextcon samza preso july - final
Yi Pan
 
GDG DevFest 2015 - Reactive approach for slowpokes
GDG DevFest 2015 - Reactive approach for slowpokesGDG DevFest 2015 - Reactive approach for slowpokes
GDG DevFest 2015 - Reactive approach for slowpokes
Sergey Tarasevich
 
From zero to hero with the reactive extensions for JavaScript
From zero to hero with the reactive extensions for JavaScriptFrom zero to hero with the reactive extensions for JavaScript
From zero to hero with the reactive extensions for JavaScript
Maurice De Beijer [MVP]
 
Side effects-con-redux
Side effects-con-reduxSide effects-con-redux
Side effects-con-redux
Nicolas Quiceno Benavides
 
Scaling with Scala: refactoring a back-end service into the mobile age
Scaling with Scala: refactoring a back-end service into the mobile ageScaling with Scala: refactoring a back-end service into the mobile age
Scaling with Scala: refactoring a back-end service into the mobile age
Dragos Manolescu
 
From zero to hero with the reactive extensions for java script
From zero to hero with the reactive extensions for java scriptFrom zero to hero with the reactive extensions for java script
From zero to hero with the reactive extensions for java script
Maurice De Beijer [MVP]
 
Bulding a reactive game engine with Spring 5 & Couchbase
Bulding a reactive game engine with Spring 5 & CouchbaseBulding a reactive game engine with Spring 5 & Couchbase
Bulding a reactive game engine with Spring 5 & Couchbase
Alex Derkach
 
Compose Async with RxJS
Compose Async with RxJSCompose Async with RxJS
Compose Async with RxJS
Kyung Yeol Kim
 
NoSQL and JavaScript: a Love Story
NoSQL and JavaScript: a Love StoryNoSQL and JavaScript: a Love Story
NoSQL and JavaScript: a Love Story
Alexandre Morgaut
 
Василевский Илья (Fun-box): "автоматизация браузера при помощи PhantomJS"
Василевский Илья (Fun-box): "автоматизация браузера при помощи PhantomJS"Василевский Илья (Fun-box): "автоматизация браузера при помощи PhantomJS"
Василевский Илья (Fun-box): "автоматизация браузера при помощи PhantomJS"
Provectus
 
Functional UIs with Java 8 and Vaadin JavaOne2014
Functional UIs with Java 8 and Vaadin JavaOne2014Functional UIs with Java 8 and Vaadin JavaOne2014
Functional UIs with Java 8 and Vaadin JavaOne2014
hezamu
 

Similar to [JEEConf-2017] RxJava as a key component in mature Big Data product (20)

Rx java in action
Rx java in actionRx java in action
Rx java in action
 
RxJava applied [JavaDay Kyiv 2016]
RxJava applied [JavaDay Kyiv 2016]RxJava applied [JavaDay Kyiv 2016]
RxJava applied [JavaDay Kyiv 2016]
 
Practical RxJava for Android
Practical RxJava for AndroidPractical RxJava for Android
Practical RxJava for Android
 
Using Apache Spark to Solve Sessionization Problem in Batch and Streaming
Using Apache Spark to Solve Sessionization Problem in Batch and StreamingUsing Apache Spark to Solve Sessionization Problem in Batch and Streaming
Using Apache Spark to Solve Sessionization Problem in Batch and Streaming
 
Reactive Programming Patterns with RxSwift
Reactive Programming Patterns with RxSwiftReactive Programming Patterns with RxSwift
Reactive Programming Patterns with RxSwift
 
Example R usage for oracle DBA UKOUG 2013
Example R usage for oracle DBA UKOUG 2013Example R usage for oracle DBA UKOUG 2013
Example R usage for oracle DBA UKOUG 2013
 
Kick your database_to_the_curb_reston_08_27_19
Kick your database_to_the_curb_reston_08_27_19Kick your database_to_the_curb_reston_08_27_19
Kick your database_to_the_curb_reston_08_27_19
 
Qt & Webkit
Qt & WebkitQt & Webkit
Qt & Webkit
 
Building Scalable Stateless Applications with RxJava
Building Scalable Stateless Applications with RxJavaBuilding Scalable Stateless Applications with RxJava
Building Scalable Stateless Applications with RxJava
 
Nextcon samza preso july - final
Nextcon samza preso   july - finalNextcon samza preso   july - final
Nextcon samza preso july - final
 
GDG DevFest 2015 - Reactive approach for slowpokes
GDG DevFest 2015 - Reactive approach for slowpokesGDG DevFest 2015 - Reactive approach for slowpokes
GDG DevFest 2015 - Reactive approach for slowpokes
 
From zero to hero with the reactive extensions for JavaScript
From zero to hero with the reactive extensions for JavaScriptFrom zero to hero with the reactive extensions for JavaScript
From zero to hero with the reactive extensions for JavaScript
 
Side effects-con-redux
Side effects-con-reduxSide effects-con-redux
Side effects-con-redux
 
Scaling with Scala: refactoring a back-end service into the mobile age
Scaling with Scala: refactoring a back-end service into the mobile ageScaling with Scala: refactoring a back-end service into the mobile age
Scaling with Scala: refactoring a back-end service into the mobile age
 
From zero to hero with the reactive extensions for java script
From zero to hero with the reactive extensions for java scriptFrom zero to hero with the reactive extensions for java script
From zero to hero with the reactive extensions for java script
 
Bulding a reactive game engine with Spring 5 & Couchbase
Bulding a reactive game engine with Spring 5 & CouchbaseBulding a reactive game engine with Spring 5 & Couchbase
Bulding a reactive game engine with Spring 5 & Couchbase
 
Compose Async with RxJS
Compose Async with RxJSCompose Async with RxJS
Compose Async with RxJS
 
NoSQL and JavaScript: a Love Story
NoSQL and JavaScript: a Love StoryNoSQL and JavaScript: a Love Story
NoSQL and JavaScript: a Love Story
 
Василевский Илья (Fun-box): "автоматизация браузера при помощи PhantomJS"
Василевский Илья (Fun-box): "автоматизация браузера при помощи PhantomJS"Василевский Илья (Fun-box): "автоматизация браузера при помощи PhantomJS"
Василевский Илья (Fun-box): "автоматизация браузера при помощи PhantomJS"
 
Functional UIs with Java 8 and Vaadin JavaOne2014
Functional UIs with Java 8 and Vaadin JavaOne2014Functional UIs with Java 8 and Vaadin JavaOne2014
Functional UIs with Java 8 and Vaadin JavaOne2014
 

Recently uploaded

Empowering Growth with Best Software Development Company in Noida - Deuglo
Empowering Growth with Best Software  Development Company in Noida - DeugloEmpowering Growth with Best Software  Development Company in Noida - Deuglo
Empowering Growth with Best Software Development Company in Noida - Deuglo
Deuglo Infosystem Pvt Ltd
 
Neo4j - Product Vision and Knowledge Graphs - GraphSummit Paris
Neo4j - Product Vision and Knowledge Graphs - GraphSummit ParisNeo4j - Product Vision and Knowledge Graphs - GraphSummit Paris
Neo4j - Product Vision and Knowledge Graphs - GraphSummit Paris
Neo4j
 
Atelier - Innover avec l’IA Générative et les graphes de connaissances
Atelier - Innover avec l’IA Générative et les graphes de connaissancesAtelier - Innover avec l’IA Générative et les graphes de connaissances
Atelier - Innover avec l’IA Générative et les graphes de connaissances
Neo4j
 
Top Features to Include in Your Winzo Clone App for Business Growth (4).pptx
Top Features to Include in Your Winzo Clone App for Business Growth (4).pptxTop Features to Include in Your Winzo Clone App for Business Growth (4).pptx
Top Features to Include in Your Winzo Clone App for Business Growth (4).pptx
rickgrimesss22
 
Utilocate provides Smarter, Better, Faster, Safer Locate Ticket Management
Utilocate provides Smarter, Better, Faster, Safer Locate Ticket ManagementUtilocate provides Smarter, Better, Faster, Safer Locate Ticket Management
Utilocate provides Smarter, Better, Faster, Safer Locate Ticket Management
Utilocate
 
Energy consumption of Database Management - Florina Jonuzi
Energy consumption of Database Management - Florina JonuziEnergy consumption of Database Management - Florina Jonuzi
Energy consumption of Database Management - Florina Jonuzi
Green Software Development
 
socradar-q1-2024-aviation-industry-report.pdf
socradar-q1-2024-aviation-industry-report.pdfsocradar-q1-2024-aviation-industry-report.pdf
socradar-q1-2024-aviation-industry-report.pdf
SOCRadar
 
openEuler Case Study - The Journey to Supply Chain Security
openEuler Case Study - The Journey to Supply Chain SecurityopenEuler Case Study - The Journey to Supply Chain Security
openEuler Case Study - The Journey to Supply Chain Security
Shane Coughlan
 
Graspan: A Big Data System for Big Code Analysis
Graspan: A Big Data System for Big Code AnalysisGraspan: A Big Data System for Big Code Analysis
Graspan: A Big Data System for Big Code Analysis
Aftab Hussain
 
Neo4j - Product Vision and Knowledge Graphs - GraphSummit Paris
Neo4j - Product Vision and Knowledge Graphs - GraphSummit ParisNeo4j - Product Vision and Knowledge Graphs - GraphSummit Paris
Neo4j - Product Vision and Knowledge Graphs - GraphSummit Paris
Neo4j
 
GreenCode-A-VSCode-Plugin--Dario-Jurisic
GreenCode-A-VSCode-Plugin--Dario-JurisicGreenCode-A-VSCode-Plugin--Dario-Jurisic
GreenCode-A-VSCode-Plugin--Dario-Jurisic
Green Software Development
 
ALGIT - Assembly Line for Green IT - Numbers, Data, Facts
ALGIT - Assembly Line for Green IT - Numbers, Data, FactsALGIT - Assembly Line for Green IT - Numbers, Data, Facts
ALGIT - Assembly Line for Green IT - Numbers, Data, Facts
Green Software Development
 
2024 eCommerceDays Toulouse - Sylius 2.0.pdf
2024 eCommerceDays Toulouse - Sylius 2.0.pdf2024 eCommerceDays Toulouse - Sylius 2.0.pdf
2024 eCommerceDays Toulouse - Sylius 2.0.pdf
Łukasz Chruściel
 
Artificia Intellicence and XPath Extension Functions
Artificia Intellicence and XPath Extension FunctionsArtificia Intellicence and XPath Extension Functions
Artificia Intellicence and XPath Extension Functions
Octavian Nadolu
 
Orion Context Broker introduction 20240604
Orion Context Broker introduction 20240604Orion Context Broker introduction 20240604
Orion Context Broker introduction 20240604
Fermin Galan
 
OpenMetadata Community Meeting - 5th June 2024
OpenMetadata Community Meeting - 5th June 2024OpenMetadata Community Meeting - 5th June 2024
OpenMetadata Community Meeting - 5th June 2024
OpenMetadata
 
Transform Your Communication with Cloud-Based IVR Solutions
Transform Your Communication with Cloud-Based IVR SolutionsTransform Your Communication with Cloud-Based IVR Solutions
Transform Your Communication with Cloud-Based IVR Solutions
TheSMSPoint
 
Microservice Teams - How the cloud changes the way we work
Microservice Teams - How the cloud changes the way we workMicroservice Teams - How the cloud changes the way we work
Microservice Teams - How the cloud changes the way we work
Sven Peters
 
Using Xen Hypervisor for Functional Safety
Using Xen Hypervisor for Functional SafetyUsing Xen Hypervisor for Functional Safety
Using Xen Hypervisor for Functional Safety
Ayan Halder
 
E-commerce Application Development Company.pdf
E-commerce Application Development Company.pdfE-commerce Application Development Company.pdf
E-commerce Application Development Company.pdf
Hornet Dynamics
 

Recently uploaded (20)

Empowering Growth with Best Software Development Company in Noida - Deuglo
Empowering Growth with Best Software  Development Company in Noida - DeugloEmpowering Growth with Best Software  Development Company in Noida - Deuglo
Empowering Growth with Best Software Development Company in Noida - Deuglo
 
Neo4j - Product Vision and Knowledge Graphs - GraphSummit Paris
Neo4j - Product Vision and Knowledge Graphs - GraphSummit ParisNeo4j - Product Vision and Knowledge Graphs - GraphSummit Paris
Neo4j - Product Vision and Knowledge Graphs - GraphSummit Paris
 
Atelier - Innover avec l’IA Générative et les graphes de connaissances
Atelier - Innover avec l’IA Générative et les graphes de connaissancesAtelier - Innover avec l’IA Générative et les graphes de connaissances
Atelier - Innover avec l’IA Générative et les graphes de connaissances
 
Top Features to Include in Your Winzo Clone App for Business Growth (4).pptx
Top Features to Include in Your Winzo Clone App for Business Growth (4).pptxTop Features to Include in Your Winzo Clone App for Business Growth (4).pptx
Top Features to Include in Your Winzo Clone App for Business Growth (4).pptx
 
Utilocate provides Smarter, Better, Faster, Safer Locate Ticket Management
Utilocate provides Smarter, Better, Faster, Safer Locate Ticket ManagementUtilocate provides Smarter, Better, Faster, Safer Locate Ticket Management
Utilocate provides Smarter, Better, Faster, Safer Locate Ticket Management
 
Energy consumption of Database Management - Florina Jonuzi
Energy consumption of Database Management - Florina JonuziEnergy consumption of Database Management - Florina Jonuzi
Energy consumption of Database Management - Florina Jonuzi
 
socradar-q1-2024-aviation-industry-report.pdf
socradar-q1-2024-aviation-industry-report.pdfsocradar-q1-2024-aviation-industry-report.pdf
socradar-q1-2024-aviation-industry-report.pdf
 
openEuler Case Study - The Journey to Supply Chain Security
openEuler Case Study - The Journey to Supply Chain SecurityopenEuler Case Study - The Journey to Supply Chain Security
openEuler Case Study - The Journey to Supply Chain Security
 
Graspan: A Big Data System for Big Code Analysis
Graspan: A Big Data System for Big Code AnalysisGraspan: A Big Data System for Big Code Analysis
Graspan: A Big Data System for Big Code Analysis
 
Neo4j - Product Vision and Knowledge Graphs - GraphSummit Paris
Neo4j - Product Vision and Knowledge Graphs - GraphSummit ParisNeo4j - Product Vision and Knowledge Graphs - GraphSummit Paris
Neo4j - Product Vision and Knowledge Graphs - GraphSummit Paris
 
GreenCode-A-VSCode-Plugin--Dario-Jurisic
GreenCode-A-VSCode-Plugin--Dario-JurisicGreenCode-A-VSCode-Plugin--Dario-Jurisic
GreenCode-A-VSCode-Plugin--Dario-Jurisic
 
ALGIT - Assembly Line for Green IT - Numbers, Data, Facts
ALGIT - Assembly Line for Green IT - Numbers, Data, FactsALGIT - Assembly Line for Green IT - Numbers, Data, Facts
ALGIT - Assembly Line for Green IT - Numbers, Data, Facts
 
2024 eCommerceDays Toulouse - Sylius 2.0.pdf
2024 eCommerceDays Toulouse - Sylius 2.0.pdf2024 eCommerceDays Toulouse - Sylius 2.0.pdf
2024 eCommerceDays Toulouse - Sylius 2.0.pdf
 
Artificia Intellicence and XPath Extension Functions
Artificia Intellicence and XPath Extension FunctionsArtificia Intellicence and XPath Extension Functions
Artificia Intellicence and XPath Extension Functions
 
Orion Context Broker introduction 20240604
Orion Context Broker introduction 20240604Orion Context Broker introduction 20240604
Orion Context Broker introduction 20240604
 
OpenMetadata Community Meeting - 5th June 2024
OpenMetadata Community Meeting - 5th June 2024OpenMetadata Community Meeting - 5th June 2024
OpenMetadata Community Meeting - 5th June 2024
 
Transform Your Communication with Cloud-Based IVR Solutions
Transform Your Communication with Cloud-Based IVR SolutionsTransform Your Communication with Cloud-Based IVR Solutions
Transform Your Communication with Cloud-Based IVR Solutions
 
Microservice Teams - How the cloud changes the way we work
Microservice Teams - How the cloud changes the way we workMicroservice Teams - How the cloud changes the way we work
Microservice Teams - How the cloud changes the way we work
 
Using Xen Hypervisor for Functional Safety
Using Xen Hypervisor for Functional SafetyUsing Xen Hypervisor for Functional Safety
Using Xen Hypervisor for Functional Safety
 
E-commerce Application Development Company.pdf
E-commerce Application Development Company.pdfE-commerce Application Development Company.pdf
E-commerce Application Development Company.pdf
 

[JEEConf-2017] RxJava as a key component in mature Big Data product

  • 1. RXJAVA AS A KEY COMPONENT IN A MATURE BIG DATA PRODUCT by Igor Lozynskyi
  • 2. HELLO!I am Igor Lozynskyi I have 8 years of Java experience, currently work at You can find me at @siromaha 2
  • 3. Agenda ■ RxJava basics ■ Zoomdata (goals & architecture) ■ “Good” & “bad” RxJava experience ■ Some thoughts about Rx future 3
  • 4. Disclaimer ■ This isn’t a sponsored talk! ■ This talk isn’t Zoomdata advertisement! ■ It’s just our experience. 4
  • 5. WHAT IS ZOOMDATA? The Fastest Visual Analytics for Big Data www.zoomdata.com 5
  • 6. ■ Data visualization software ■ Big Data ■ 30+ DB types ■ SQL, NoSQL, raw data (CSV) ■ Pretty charts ■ Platform! Zoomdata (ZD): 6
  • 8. 8
  • 9. ■ Static is boring ■ Dynamic is interesting Instant feedback ■ We do not like to wait 9
  • 11. 11
  • 12. 12
  • 14.
  • 15. 15 class QueryProcessor implements Observable.Transformer<QueryRequest, QueryResult> { Observable<QueryResult> call(Observable<QueryRequest> requests) { ... } }
  • 16.
  • 17. 17 class QueryProcessor implements Observable.Transformer<QueryRequest, QueryResult> { Observable<QueryResult> call(Observable<QueryRequest> requests) { return requests .takeWhile(req -> !isCancellation(req)) .map(this::validateRequest) .compose(r -> requestProcessor(r)) .onErrorReturn(this::handleProcessingErrors) } Observable<QueryResult> requestProcessor(Observable<QueryRequestParsed> requests) { return mainQuery(requests); } }
  • 18.
  • 19. 19 class QueryProcessor implements Observable.Transformer<QueryRequest, QueryResult> { Observable<QueryResult> call(Observable<QueryRequest> requests) { return requests .takeWhile(req -> !isCancellation(req)) .map(this::validateRequest) .compose(r -> requestProcessor(r)) .onErrorReturn(this::handleProcessingErrors) } Observable<QueryResult> requestProcessor(Observable<QueryRequestParsed> requests) { return merge( mainQuery(requests), intermediateResults(requests) // approximate result ); } }
  • 20.
  • 21. 21 class QueryProcessor implements Observable.Transformer<QueryRequest, QueryResult> { Observable<QueryResult> call(Observable<QueryRequest> requests) { return requests .takeWhile(req -> !isCancellation(req)) .map(this::validateRequest) .compose(r -> requestProcessor(r)) .onErrorReturn(this::handleProcessingErrors) } Observable<QueryResult> requestProcessor(Observable<QueryRequestParsed> request) { return merge( mainQuery(requests), intermediateResults(requests), mainQueryProgress(requests) // based on main query ); } }
  • 22.
  • 26. Effortless mapping of WebSocket to Observable Stream 26
  • 27. 27 class RxWebSocketSession<T extends WebSocketMessage<?>> { spring.WebSocketSession nativeSession; Subject<T, T> inputSubject; Subscriber<T> socketSubscriber; public RxWebSocketSession(spring.WebSocketSession nativeSession) { ... } public Observable<T> getInput() { return inputSubject; } public Subscriber<T> getOutput() { return socketSubscriber; } ... }
  • 28. 28 class NativeWebSocketHandler extends TextWebSocketHandler { IRxWebSocketHandler<TextMessage> sessionHandler; Map<WebSocketSession, RxWebSocketSession<TextMessage>> sessions; void afterConnectionEstablished(WebSocketSession session) { RxWebSocketSession<TextMessage> rxSession = new RxWebSocketSession<>(synchronizedSession(session)); sessions.put(session, rxSession); sessionHandler.afterConnectionEstablished(rxSession); } void handleTextMessage(WebSocketSession session, TextMessage message) { sessions.get(session).handleMessage(message); } void afterConnectionClosed(WebSocketSession session, CloseStatus status) { RxWebSocketSession<TextMessage> rxSession = sessions.remove(session); rxSession.close(); sessionHandler.afterConnectionClosed(rxSession, status); } }
  • 29. 29 class RxWebSocketHandler implements IRxWebSocketHandler<TextMessage> { rx.Observable.Transformer<String, String> messageTransformer; rx.Scheduler sendingIoScheduler; public void afterConnectionEstablished(RxWebSocketSession<TextMessage> session) { session .getInput() .map(TextMessage::getPayload) .compose(messageTransformer) .onBackpressureBuffer(OUTGOING_WS_BUFFER_CAPACITY, () -> reportMessageDropped(session.getId()), ON_OVERFLOW_DROP_OLDEST) .observeOn(sendingIoScheduler) .map(TextMessage::new) .subscribe(session.getOutput()); } }
  • 30. It is easy to stream intermediate results to a client 30
  • 31. It is easy to coordinate complex & long running workflows 31
  • 32. RxJava allows to compose dozens of reactive streams 32
  • 34. RxJava is very powerful Any stream transformation that you can imagine! Image credits: Denys Nevozhai
  • 36. Use TDD for Rx code! Lack of unit tests for Rx code Many integration tests instead 36Image credits: Matthew Henry
  • 37. Stream code should not be too complicated! Rule: “10 lines max” for method 37
  • 38. 38 protected Observable<Map<QueryStream, ComputedTasks>> play(Map<QueryStream, ComputedTasks> initial) { return concat(just(primaryTimeWindow), timeWindowStream) .map(tw -> playingReadRequests.columnKeySet().stream() .collect(toMap( calc -> calc, calc -> calc.calculateTimewindow(tw))) ) .buffer(2, 1) .filter(contextsMaps -> contextsMaps.size() == 2) .zipWith(checkPointsStream::iterator, Pair::of) .scan(initialTasksByTimewindow, (tasksMap, actions) -> { Map<TimewindowCalculator, List<ReadAction>> actionsByWindow = actions.getLeft(); Boolean doCheckpoint = actions.getRight(); Map<TimewindowCalculator, Map<QueryStream, ComputedTasks>> tasksByTimewindow = MapStream.of(actionsByWindow) .map(e -> { TimewindowCalculator timewindow = e.getKey(); List<ReadAction> timewindowActions = e.getValue(); Map<QueryStream, ComputedTasks> tasksOfTimewindow = tasksMap.get(timewindow); Map<QueryStream, ComputedTasks> tasksByStream = calculateStreamTasksWithActions(timewindow, tasksOfTimewindow, timewindowActions, doCheckpoint); return Pair.of(timewindow, tasksByStream); }).collect(toMap(Pair::getKey, Pair::getValue)); return tasksByTimewindow; }) .map(tasksByTimewindow -> { Collection<Map<QueryStream, ComputedTasks>> tasksByStreamMaps = tasksByTimewindow.values(); return mergeTasksMapsByStream(tasksByStreamMaps); }) .doOnNext(this::rememberLastTasksReference) .skip(1); }
  • 39. 39 protected Observable<Map<QueryStream, ComputedTasks>> play(Map<QueryStream, ComputedTasks> initial) { return concat(just(primaryTimeWindow), timeWindowStream) .map(tw -> playingReadRequests.columnKeySet().stream() .collect(toMap( calc -> calc, calc -> calc.calculateTimewindow(tw))) ) .buffer(2, 1) .filter(contextsMaps -> contextsMaps.size() == 2) .zipWith(checkPointsStream::iterator, Pair::of) .scan(initialTasksByTimewindow, (tasksMap, actions) -> { Map<TimewindowCalculator, List<ReadAction>> actionsByWindow = actions.getLeft(); Boolean doCheckpoint = actions.getRight(); Map<TimewindowCalculator, Map<QueryStream, ComputedTasks>> tasksByTimewindow = MapStream.of(actionsByWindow) .map(e -> { TimewindowCalculator timewindow = e.getKey(); List<ReadAction> timewindowActions = e.getValue(); Map<QueryStream, ComputedTasks> tasksOfTimewindow = tasksMap.get(timewindow); Map<QueryStream, ComputedTasks> tasksByStream = calculateStreamTasksWithActions(timewindow, tasksOfTimewindow, timewindowActions, doCheckpoint); return Pair.of(timewindow, tasksByStream); }).collect(toMap(Pair::getKey, Pair::getValue)); return tasksByTimewindow; }) .map(tasksByTimewindow -> { Collection<Map<QueryStream, ComputedTasks>> tasksByStreamMaps = tasksByTimewindow.values(); return mergeTasksMapsByStream(tasksByStreamMaps); }) .doOnNext(this::rememberLastTasksReference) .skip(1); }
  • 40. 40 protected Observable<Map<QueryStream, ComputedTasks>> play(Map<QueryStream, ComputedTasks> initial) { return concat(just(primaryTimeWindow), timeWindowStream) .map(this::calculateTimeWindows) .buffer(2, 1) .filter(this::contextMapsOfSizeTwo) .zipWith(checkPointsStream::iterator, Pair::of) .scan(initialTasksByTimewindow, this::updateJobResultsForNewTimeWindow) .map(tasksByTimewindow -> mergeTaskMapsByStream(tasksByTimewindow.values())) .doOnNext(this::rememberLastTasksReference) .skip(1); }
  • 41. 41 protected Observable<Map<QueryStream, ComputedTasks>> play(Map<QueryStream, ComputedTasks> initial) { return concat(just(primaryTimeWindow), timeWindowStream) .map(this::calculateTimeWindows) .buffer(2, 1) .filter(this::contextMapsOfSizeTwo) .map(this::transitionWindow) .zipWith(checkPointsStream::iterator, Pair::of) .scan(initialTasksByTimewindow, this::updateJobResultsForNewTimeWindow) .map(tasksByTimewindow -> mergeTaskMapsByStream(tasksByTimewindow.values())) .doOnNext(this::rememberLastTasksReference) .skip(1); }
  • 42. It is easy to forget about one very important thing 42 Remember next slide Image credits: Oscar Sutton
  • 47. Remember not to overflow your client! Your client will not be happy 47
  • 48. Remember not to overflow yourself! 48 Slow subscriber may cause data buffering Buffering may be costly
  • 49. 49
  • 50. Rx silently introduces a notion of time into your API 50
  • 51. 51
  • 52. Track your stream lifetime! GroupBy operator 52
  • 53. 53
  • 54. Track your stream lifetime! 54 Child streams live along with parent!
  • 55. 55
  • 56. Track your stream lifetime! Unpleasant when child streams hold resources 56
  • 57. Subscription takes some time Be careful not to miss messages 57
  • 58. 58
  • 59. Reactive transformations are time dependent 59 Zoomdata had an issue due to this
  • 60. 60
  • 62. Hard to code complicated context-dependent workflow ■ Loop vs flatMap ■ State should be incorporated into the stream! 62
  • 63. Try not to mutate objects inside Rx streams ■ Rx stream is a concurrent system ■ In concurrent systems mutation is evil ■ Zoomdata had such issues 63
  • 64. Think twice before providing pull API over Rx stream 64
  • 65. ■ Pull push hard & risky ■ Pull push mutability disaster Think twice before providing pull API over Rx stream ■ Push pull ok 65
  • 66. It is better to control execution threads on your own ■ Doing CPU in IO thread ■ Doing IO in CPU thread 66Image credits: Haiku Deck
  • 67. Care about concurrency ■ No ThreadLocal tricks! ■ flatMap/zip/merge may move execution into unexpected (for you) thread ■ Immutability is the only reasonable way to go 67
  • 68. and, last but not least... 68
  • 69. Complexity is still there! 69Image credits: sciencemag.org
  • 71. ■ WebSocket to Rx stream mapping: 3 files ■ ZD query processing is almost entirely RxJava code ■ Most algorithms live in 10 files (~1000 loc) □ playing, sharpening, progress, timeline, push/pull data strategies, main query, timeline, and much more ■ RxJava is complicated, but very powerful ■ Zoomdata benefits a lot from RxJava usage! Is RxJava good enough for ZD? 71
  • 72. ■ Java 9 & Spring 5 will spread reactive programming ■ We expect big shift towards Project Reactor ■ We will have more reactive and proactive software! □ Zoomdata is already proactive Some thoughts about Rx future 72
  • 73. THANKS! Contact me: @siromaha aigooor [at] gmail [dot] com Presentation template by SlidesCarnival Image credits: Denys Nevozhai