SlideShare a Scribd company logo
1 of 73
Download to read offline
Building reac-ve game engine
with Spring 5 & Couchbase
Alex Derkach
Senior So0ware Engineer @ Play7ka
@alexsderkach
‣ Java addict since ’12
‣ SSE @ Slotomania Feature Team
‣ Ac7ve Couchbase & Spring user
‣ All things reac7ve & distributed
2h>p://alexsderkach.io
slides
Plan for today
3
‣ Why Couchbase + Quick Overview
‣ Reac7ve founda7on behind Spring 5
‣ Demonstra7on & Case Study
‣ Summary
Applica-on Layer
Old-School Architecture
4
App App
App App
App App
Read/Write
Requests
RDBMS
Individual Memcached NodesApplica-on Layer
Old-School Architecture
5
App App
App App
App App
Cache Misses &
Write Requests
RDBMS
Read/Write
requests
RDBMS
6
Video game is not ‘yet another web app’
7
‣ Rapid Fall or Growth
‣ Responsiveness will brake you
‣ Always ON
‣ Flexible Data Model
It all comes to this…
8
What is Couchbase?
9
‣ Key-Document storage
‣ Consistent high performance
‣ Scale with single “push” buTon
‣ Zero-down7me opera7ons
Server
10
Couchbase Architecture
Cluster
Manager
Data Service
Index Service
Query Service
Cache
Storage
Server
Cluster
Manager
Data Service
Index Service
Query Service
Cache
Storage
Server
Cluster
Manager
Data Service
Index Service
Query Service
Cache
Storage
Server
Cluster
Manager
Data Service
Index Service
Query Service
Cache
Storage
Server
Cluster
Manager
Data Service
Index Service
Query Service
Cache
Storage
Couchbase Cluster
Server
11
Couchbase Architecture
Cluster
Manager
Data Service
Cache
Storage
Server
Cluster
Manager
Data Service
Cache
Storage
Server
Cluster
Manager
Query Service
Cache
Storage
Server
Cluster
Manager
Index Service
Cache
Storage
Server
Cluster
Manager
Index Service
Cache
Storage
Couchbase Cluster
12
Example Use Case: Leaderboard
SELECT * FROM `scores`
WHERE roundId = 10
ORDER BY score DESC
LIMIT 3
Data
Service
Index Service
Query Service
Couchbase SDK
13
‣ RxJava 1
‣ CRUD
‣ N1QL
‣ Map/Reduce
‣ Administra7on
bucket
.get("whiskey")
.onErrorResumeNext(bucket.getFromReplica("whiskey", ReplicaMode.ALL))
.first()
.map(doc -> doc.content().getString("name"))
.timeout(2, TimeUnit.SECONDS)
.doOnError(System.err::println)
.onErrorReturn(error -> "Not found!")
Couchbase SDK
14
‣ RxJava 1
‣ CRUD
‣ N1QL
‣ Map/Reduce
‣ Administra7on
bucket
.get("whiskey")
.onErrorResumeNext(bucket.getFromReplica("whiskey", ReplicaMode.ALL))
.first()
.map(doc -> doc.content().getString("name"))
.timeout(2, TimeUnit.SECONDS)
.doOnError(System.err::println)
.onErrorReturn(error -> "Not found!")
Couchbase SDK
15
‣ RxJava 1
‣ CRUD
‣ N1QL
‣ Map/Reduce
‣ Administra7on
bucket
.get("whiskey")
.onErrorResumeNext(bucket.getFromReplica("whiskey", ReplicaMode.ALL))
.first()
.map(doc -> doc.content().getString("name"))
.timeout(2, TimeUnit.SECONDS)
.doOnError(System.err::println)
.onErrorReturn(error -> "Not found!")
Couchbase SDK
16
‣ RxJava 1
‣ CRUD
‣ N1QL
‣ Map/Reduce
‣ Administra7on
bucket
.get("whiskey")
.onErrorResumeNext(bucket.getFromReplica("whiskey", ReplicaMode.ALL))
.first()
.map(doc -> doc.content().getString("name"))
.timeout(2, TimeUnit.SECONDS)
.doOnError(System.err::println)
.onErrorReturn(error -> "Not found!")
Couchbase SDK
17
‣ RxJava 1
‣ CRUD
‣ N1QL
‣ Map/Reduce
‣ Administra7on
bucket
.get("whiskey")
.onErrorResumeNext(bucket.getFromReplica("whiskey", ReplicaMode.ALL))
.first()
.map(doc -> doc.content().getString("name"))
.timeout(2, TimeUnit.SECONDS)
.doOnError(System.err::println)
.onErrorReturn(error -> "Not found!")
Couchbase SDK
18
‣ RxJava 1
‣ CRUD
‣ N1QL
‣ Map/Reduce
‣ Administra7on
bucket
.get("whiskey")
.onErrorResumeNext(bucket.getFromReplica("whiskey", ReplicaMode.ALL))
.first()
.map(doc -> doc.content().getString("name"))
.timeout(2, TimeUnit.SECONDS)
.doOnError(System.err::println)
.onErrorReturn(error -> "Not found!")
Couchbase SDK
19
‣ RxJava 1
‣ CRUD
‣ N1QL
‣ Map/Reduce
‣ Administra7on
bucket
.get("whiskey")
.onErrorResumeNext(bucket.getFromReplica("whiskey", ReplicaMode.ALL))
.first()
.map(doc -> doc.content().getString("name"))
.timeout(2, TimeUnit.SECONDS)
.doOnError(System.err::println)
.onErrorReturn(error -> "Not found!")
Couchbase SDK
20
‣ RxJava 1
‣ CRUD
‣ N1QL
‣ Map/Reduce
‣ Administra7on
bucket
.get("whiskey")
.onErrorResumeNext(bucket.getFromReplica("whiskey", ReplicaMode.ALL))
.first()
.map(doc -> doc.content().getString("name"))
.timeout(2, TimeUnit.SECONDS)
.doOnError(System.err::println)
.onErrorReturn(error -> "Not found!")
21
22
Couchbase
Connector
wait for events
handle events
Thread
get(“user::1”)
result
RUNNING
RUNNING
BLOCKED
Couchbase
23
public interface Publisher<T> {
void subscribe(Subscriber<? super T> s);
}
public interface Subscriber<T> {
void onSubscribe(Subscription s);
void onNext(T t);
void onError(Throwable t);
void onComplete();
}
public interface Subscription {
void request(long n);
void cancel();
}
public interface Processor<T, R> extends Subscriber<T>, Publisher<R> {
}
h>ps://github.com/reac-ve-streams/reac-ve-streams-jvm
Let’s build Reac-ve Framework!
DIY - Reac-ve Framework
24
1. Should work with RS Java Specifica7on
2. Address the reentrance
3. Address thread safety
4. Address back-pressure
5. Address state
6. For Many-To-One Flows, implement merging
7. For One-To-Many, implement broadcas7ng
8. …
h>ps://github.com/reac-ve-streams/reac-ve-streams-jvm
DIY - Reac-ve Framework
25
1. Should work with RS Java Specifica7on
2. Address the reentrance
3. Address thread safety
4. Address back-pressure
5. Address state
6. For Many-To-One Flows, implement merging
7. For One-To-Many, implement broadcas7ng
8. …
h>ps://github.com/reac-ve-streams/reac-ve-streams-jvm
26
27
MySQL
Thread
RUNNING
BLOCKED
Couchbase
User Service
Payment Service
Twitter API
BLOCKED
BLOCKED
BLOCKED
BLOCKED
RUNNING
RUNNING
RUNNING
3rd party
Spring 5
28
‣ Based on Reactor Core 3
‣ Reac7ve HTTP Server Abstrac7on
‣ Compa7ble with RxJava 1 & 2
‣ Compa7ble with Java 9
‣ Many more!
29
‣ Func7onal, declara7ve programming model
‣ Combine, transform, reduce sequences (500+ methods)
‣ Reac7ve Streams ready
‣ Focus on what, not how
Reactor 3 Crash Course
Flux / Mono Subscriber
0..N Data
+ 0..1 (Error, Completed)
Backpressure
regulation
30
Learning to Flux
OR Flux.create(sink -> *blocking call*);Mono.create(sink -> *blocking call*);
31
Learning to Flux
Mono.create(sink -> {
val result = repository.findOne(1L);
if (result.isPresent()) {
sink.success(result.get());
} else {
sink.error(new UserNotFoundException(id));
}
})
.subscribe(System.out::println);
Flux.create(sink -> *blocking call*);Mono.create(sink -> *blocking call*); OR
32
Learning to Flux
Mono.create(sink -> {
val result = repository.findOne(1L);
if (result.isPresent()) {
sink.success(result.get());
} else {
sink.error(new UserNotFoundException(id));
}
})
.subscribe(System.out::println);
Flux.create(sink -> *blocking call*);Mono.create(sink -> *blocking call*);
Flux.create(sink -> {
val ids = asList(1L, 2L, 3L);
val result = userRepository.findAll(ids);
for (User user : result) {
sink.next(user);
}
sink.complete();
})
.subscribe(System.out::println);
OR
33
Flux.create(..., );
enum OverflowStrategy {
// Completely ignore downstream backpressure requests.
IGNORE,
// Signal an IllegalStateException when the downstream
can't keep up
ERROR,
// Drop the incoming signal if the downstream is not
ready to receive it.
DROP,
// Downstream will get only the latest signals from
upstream.
LATEST,
// Buffer all signals if the downstream can't keep up.
BUFFER
}
Backpressure
34
Flux.<User>create(sink -> {
userRepository.findAll(ids).forEach(sink::next);
sink.complete();
})
.filter(user -> user.getGender() == MALE)
.map(user -> new User(user.getId(), user.getName().toUpperCase()))
.buffer(20)
.flatMap(users ->
Flux.create(sink -> {
userRepository.save(users).forEach(sink::next);
sink.complete();
})
.subscribeOn(Schedulers.elastic())
)
.subscribeOn(Schedulers.elastic())
.subscribe(System.out::println, System.err::println);
I have a Flux. What’s next?
35
Flux.<User>create(sink -> {
userRepository.findAll(ids).forEach(sink::next);
sink.complete();
})
.filter(user -> user.getGender() == MALE)
.map(user -> new User(user.getId(), user.getName().toUpperCase()))
.buffer(20)
.flatMap(users ->
Flux.create(sink -> {
userRepository.save(users).forEach(sink::next);
sink.complete();
})
.subscribeOn(Schedulers.elastic())
)
.subscribeOn(Schedulers.elastic())
.subscribe(System.out::println, System.err::println);
I have a Flux. What’s next?
36
Be Blocking or Non-Blocking?
37
Be Blocking or Non-Blocking?
@Test
public void testEmojiSource() {
Flux<String> source = emojiSource();
Iterable<String> values = source.toIterable();
assertEquals(asList("🙈", "🙉", "🙊"), values);
}
@Test
public void testWelcomeSource() {
Mono<String> source = welcomeSource();
String value = source.block();
assertEquals("Hello", value);
}
Non-Blocking to Blocking
38
Be Blocking or Non-Blocking?
@Test
public void testEmojiSource() {
Flux<String> source = emojiSource();
Iterable<String> values = source.toIterable();
assertEquals(asList("🙈", "🙉", "🙊"), values);
}
@Test
public void testWelcomeSource() {
Mono<String> source = welcomeSource();
String value = source.block();
assertEquals("Hello", value);
}
Non-Blocking to Blocking Blocking to Non-Blocking
40
spring-web
Jetty
Netty
Tomcat
Undertow
HttpServlet
Request|Response
HttpServer
Request|Response
HttpServlet
Request|Response
HttpServerExchange
🍒
ServerHttp
Request|Response
1
1
1
1
<interface>
WebHandler
41
spring-web
Dispatcher
Handler
Jetty
Netty
Tomcat
Undertow
HttpServlet
Request|Response
HttpServer
Request|Response
HttpServlet
Request|Response
HttpServerExchange
🍒
ServerHttp
Request|Response
1
1
1
1
public interface HandlerMapping {
Mono<Object> getHandler( 🍒);
}
public interface HandlerAdapter {
boolean supports(Object handler);
Mono<HandlerResult> handle( 🍒, handler);
}
2
3
spring-webflux
<interface>
WebHandler
public interface HandlerMethodArgumentResolver {
boolean supportsParameter(MethodParameter);
Mono< 🍷> resolveArgument(MethodParameter, 🍒);
}
4 handler.invoke(Mono< 🍷>...);
5
42
spring-web spring-webflux
@RestController
public class UserController {
@GetMapping("/users/{id}")
public User get(long id) { }
@PostMapping("/users/")
public User create(User user) { }
@PutMapping("/users/{id}")
public User update(long id, User user) { }
@DeleteMapping("/users/{id}")
public User delete(long id) { }
}
@RestController
public class UserController {
@GetMapping("/users/{id}")
public User get(long id) { }
@PostMapping("/users/")
public User create(User user) { }
@PutMapping("/users/{id}")
public User update(long id, User user) { }
@DeleteMapping("/users/{id}")
public User delete(long id) { }
}
43
spring-web spring-webflux
@RestController
public class UserController {
@GetMapping("/users/{id}")
public User get(long id) { }
@PostMapping("/users/")
public User create(User user) { }
@PutMapping("/users/{id}")
public User update(long id, User user) { }
@DeleteMapping("/users/{id}")
public User delete(long id) { }
}
@RestController
public class UserController {
@GetMapping("/users/{id}")
public Mono<User> get(long id) { }
@PostMapping("/users/")
public Mono<User> create(Mono<User> user) { }
@PutMapping("/users/{id}")
public Mono<User> update(long id,
Mono<User> user) { }
@DeleteMapping("/users/{id}")
public Mono<User> delete(long id) { }
}
DEMO
45
Flux against the world
h>p://alexsderkach.io/comparing-java-8-rxjava-reactor/
46
Flux against the world
composable lazy reusable async cached push
back-
pressure
operator
fusion
CompletableFuture ✔ ✘ ✔ ✔ ✔ ✔ ✘ ✘
Stream ✔ ✔ ✘ ✘ ✘ ✘ ✘ ✘
Optional ✔ ✘ ✔ ✘ ✔ ✘ ✘ ✘
Observable (RxJava 1) ✔ ✔ ✔ ✔
✔
*.cache()
✔
✔
*.onBackpressure
*()
✘
Observable (RxJava 2) ✔ ✔ ✔ ✔
✔
*.cache()
✔ ✘ ✔
Flowable (RxJava 2) ✔ ✔ ✔ ✔
✔
*.cache()
✔ ✔ ✔
Flux ✔ ✔ ✔ ✔
✔
*.cache()
✔ ✔ ✔
h>p://alexsderkach.io/comparing-java-8-rxjava-reactor/
47
Flux against the world
composable lazy reusable async cached push
back-
pressure
operator
fusion
CompletableFuture ✔ ✘ ✔ ✔ ✔ ✔ ✘ ✘
Stream ✔ ✔ ✘ ✘ ✘ ✘ ✘ ✘
Optional ✔ ✘ ✔ ✘ ✔ ✘ ✘ ✘
Observable (RxJava 1) ✔ ✔ ✔ ✔
✔
*.cache()
✔
✔
*.onBackpressure
*()
✘
Observable (RxJava 2) ✔ ✔ ✔ ✔
✔
*.cache()
✔ ✘ ✔
Flowable (RxJava 2) ✔ ✔ ✔ ✔
✔
*.cache()
✔ ✔ ✔
Flux ✔ ✔ ✔ ✔
✔
*.cache()
✔ ✔ ✔
h>p://alexsderkach.io/comparing-java-8-rxjava-reactor/
48
Flux against the world
composable lazy reusable async cached push
back-
pressure
operator
fusion
CompletableFuture ✔ ✘ ✔ ✔ ✔ ✔ ✘ ✘
Stream ✔ ✔ ✘ ✘ ✘ ✘ ✘ ✘
Optional ✔ ✘ ✔ ✘ ✔ ✘ ✘ ✘
Observable (RxJava 1) ✔ ✔ ✔ ✔
✔
*.cache()
✔
✔
*.onBackpressure
*()
✘
Observable (RxJava 2) ✔ ✔ ✔ ✔
✔
*.cache()
✔ ✘ ✔
Flowable (RxJava 2) ✔ ✔ ✔ ✔
✔
*.cache()
✔ ✔ ✔
Flux ✔ ✔ ✔ ✔
✔
*.cache()
✔ ✔ ✔
h>p://alexsderkach.io/comparing-java-8-rxjava-reactor/
49
Flux against the world
composable lazy reusable async cached push
back-
pressure
operator
fusion
CompletableFuture ✔ ✘ ✔ ✔ ✔ ✔ ✘ ✘
Stream ✔ ✔ ✘ ✘ ✘ ✘ ✘ ✘
Optional ✔ ✘ ✔ ✘ ✔ ✘ ✘ ✘
Observable (RxJava 1) ✔ ✔ ✔ ✔
✔
*.cache()
✔
✔
*.onBackpressure
*()
✘
Observable (RxJava 2) ✔ ✔ ✔ ✔
✔
*.cache()
✔ ✘ ✔
Flowable (RxJava 2) ✔ ✔ ✔ ✔
✔
*.cache()
✔ ✔ ✔
Flux ✔ ✔ ✔ ✔
✔
*.cache()
✔ ✔ ✔
h>p://alexsderkach.io/comparing-java-8-rxjava-reactor/
50
Flux against the world
composable lazy reusable async cached push
back-
pressure
operator
fusion
CompletableFuture ✔ ✘ ✔ ✔ ✔ ✔ ✘ ✘
Stream ✔ ✔ ✘ ✘ ✘ ✘ ✘ ✘
Optional ✔ ✘ ✔ ✘ ✔ ✘ ✘ ✘
Observable (RxJava 1) ✔ ✔ ✔ ✔
✔
*.cache()
✔
✔
*.onBackpressure
*()
✘
Observable (RxJava 2) ✔ ✔ ✔ ✔
✔
*.cache()
✔ ✘ ✔
Flowable (RxJava 2) ✔ ✔ ✔ ✔
✔
*.cache()
✔ ✔ ✔
Flux ✔ ✔ ✔ ✔
✔
*.cache()
✔ ✔ ✔
h>p://alexsderkach.io/comparing-java-8-rxjava-reactor/
51
Flux against the world
composable lazy reusable async cached push
back-
pressure
operator
fusion
CompletableFuture ✔ ✘ ✔ ✔ ✔ ✔ ✘ ✘
Stream ✔ ✔ ✘ ✘ ✘ ✘ ✘ ✘
Optional ✔ ✘ ✔ ✘ ✔ ✘ ✘ ✘
Observable (RxJava 1) ✔ ✔ ✔ ✔
✔
*.cache()
✔
✔
*.onBackpressure
*()
✘
Observable (RxJava 2) ✔ ✔ ✔ ✔
✔
*.cache()
✔ ✘ ✔
Flowable (RxJava 2) ✔ ✔ ✔ ✔
✔
*.cache()
✔ ✔ ✔
Flux ✔ ✔ ✔ ✔
✔
*.cache()
✔ ✔ ✔
h>p://alexsderkach.io/comparing-java-8-rxjava-reactor/
52
Flux against the world
composable lazy reusable async cached push
back-
pressure
operator
fusion
CompletableFuture ✔ ✘ ✔ ✔ ✔ ✔ ✘ ✘
Stream ✔ ✔ ✘ ✘ ✘ ✘ ✘ ✘
Optional ✔ ✘ ✔ ✘ ✔ ✘ ✘ ✘
Observable (RxJava 1) ✔ ✔ ✔ ✔
✔
*.cache()
✔
✔
*.onBackpressure
*()
✘
Observable (RxJava 2) ✔ ✔ ✔ ✔
✔
*.cache()
✔ ✘ ✔
Flowable (RxJava 2) ✔ ✔ ✔ ✔
✔
*.cache()
✔ ✔ ✔
Flux ✔ ✔ ✔ ✔
✔
*.cache()
✔ ✔ ✔
h>p://alexsderkach.io/comparing-java-8-rxjava-reactor/
53
Flux against the world
composable lazy reusable async cached push
back-
pressure
operator
fusion
CompletableFuture ✔ ✘ ✔ ✔ ✔ ✔ ✘ ✘
Stream ✔ ✔ ✘ ✘ ✘ ✘ ✘ ✘
Optional ✔ ✘ ✔ ✘ ✔ ✘ ✘ ✘
Observable (RxJava 1) ✔ ✔ ✔ ✔
✔
*.cache()
✔
✔
*.onBackpressure
*()
✘
Observable (RxJava 2) ✔ ✔ ✔ ✔
✔
*.cache()
✔ ✘ ✔
Flowable (RxJava 2) ✔ ✔ ✔ ✔
✔
*.cache()
✔ ✔ ✔
Flux ✔ ✔ ✔ ✔
✔
*.cache()
✔ ✔ ✔
h>p://alexsderkach.io/comparing-java-8-rxjava-reactor/
54
Flux against the world
composable lazy reusable async cached push
back-
pressure
operator
fusion
CompletableFuture ✔ ✘ ✔ ✔ ✔ ✔ ✘ ✘
Stream ✔ ✔ ✘ ✘ ✘ ✘ ✘ ✘
Optional ✔ ✘ ✔ ✘ ✔ ✘ ✘ ✘
Observable (RxJava 1) ✔ ✔ ✔ ✔
✔
*.cache()
✔
✔
*.onBackpressure
*()
✘
Observable (RxJava 2) ✔ ✔ ✔ ✔
✔
*.cache()
✔ ✘ ✔
Flowable (RxJava 2) ✔ ✔ ✔ ✔
✔
*.cache()
✔ ✔ ✔
Flux ✔ ✔ ✔ ✔
✔
*.cache()
✔ ✔ ✔
h>p://alexsderkach.io/comparing-java-8-rxjava-reactor/
55
Automa-c Op-miza-ons
‣ Macro-fusion - replacing 2+ subsequent operators with a single operator:



1. map(A) = B

2. map(B) = C ƒ(A) = D

3. filter(C) = D
56
‣ Macro-fusion - replacing 2+ subsequent operators with a single operator:



1. map(A) = B

2. map(B) = C ƒ(A) = D

3. filter(C) = D
‣ Micro-fusion - operators that end in an output queue and operators star7ng with
a front-queue could share the same Queue instance



1. 0..100 = B

2. map(B) = C [0..100] <-> map <-> groupBy <-> 🙄

3. groupBy(C) = D
Automa-c Op-miza-ons
push
queuequeue request(1) request(1)
push
request(1)
push
‣ Macro-fusion - replacing 2+ subsequent operators with a single operator:



1. map(A) = B

2. map(B) = C ƒ(A) = D

3. filter(C) = D
‣ Micro-fusion - operators that end in an output queue and operators star7ng with
a front-queue could share the same Queue instance



1. 0..100 = B

2. map(B) = C [0..100] <- map <-> groupBy <- 🙄

3. groupBy(C) = D
57
Automa-c Op-miza-ons
poll
queuequeue
poll
request(1)
push
58
Flux against the world
‣ Stream, Op-onal, CompletableFuture - solve specific tasks
‣ Reac-ve Libraries are universal
59
Reactor Core
RxJava
org.reac-vestreams
reac-ve-streams
1.0.0
Spring 5
Reactor
Kaoa
Spring
Integra-on
Add-ons
Couchbase
Hystrix
61
‣ Pipeline = steps of transforma-ons
How do I test? #unit
62
How do I test? #unit
🛴 🏍 🚐
transforma-on #1 transforma-on #2
‣ Pipeline = steps of transforma-ons
63
How do I test? #unit
Input ExpectedTransformer
🛴 🏍 🚐
transforma-on #1 transforma-on #2
‣ Pipeline = steps of transforma-ons
64
How do I test? #unit
🛴 🏍 🚐
transforma-on #1 transforma-on #2
‣ Pipeline = steps of transforma-ons
Input ExpectedTransformer
@Test
public void testEmojiSource() {
Flux<String> source = emojiSource();
Iterable<String> values = source.toIterable();
assertEquals(asList("🙈", "🙉", "🙊"), values);
}
@Test
public void testWelcomeSource() {
Mono<String> source = welcomeSource();
String value = source.block();
assertEquals("Hello", value);
}
65
How to verify expecta-ons?
h>ps://projectreactor.io/docs/core/release/reference/docs/index.html#tes-ng
1
@Test
public void testEmojiSource() {
Flux<String> source = emojiSource();
StepVerifier.create(source)
.expectNext("🙈", "🙉", "🙊")
.as("expect 3 more")
.expectNextCount(3)
.thenAwait(Duration.ofSeconds(3))
.expectNextMatches(v -> v.startsWith("O_O"))
.as("expect non empty batch")
.thenConsumeWhile(v -> !v.isEmpty())
.expectNextCount(1)
.verifyComplete();
}
2
3
1
2
3
convert to synchronous use StepVerifier
1
3
2
🏍
66
How to generate input?🛴
@Test
public void testEmojiSource() {
Flux<String> source = Flux.just("🙈", "🙉", "🙊");
Iterable<String> values = source.toIterable();
assertEquals(asList("🙈", "🙉", "🙊"), values);
}
@Test
public void testWelcomeSource() {
Mono<String> source = Mono.just("Hello");
String value = source.block();
assertEquals("Hello", value);
}
67
How to generate input?
Emit specific signals with TestPublisher<T>
‣ next(T…) will trigger 1..N onNext signals
‣ emit(T…) will do the same & complete
‣ complete() will terminate with onComplete signal
‣ error(Throwable) will terminate with an onError signal
🛴
68
How to get pre>y stack-trace?
Ac-vate debug mode
Hooks.onOperator(Hooks.OperatorHook::operatorStacktrace);
Error has been observed by the following operator(s):
|_ Flux.map(FakeRepository.java:27)
|_ Flux.map(FakeRepository.java:28)
|_ Flux.filter(FakeUtils1.java:29)
|_ Flux.transform(GuideDebuggingExtraTests.java:41)
|_ Flux.elapsed(FakeUtils2.java:30)
|_ Flux.transform(GuideDebuggingExtraTests.java:42)
69
How do I test Couchbase? #integra-on
without N1QL with N1QL
OR
70
Future
‣ Flow API - Java 9
‣ Non-blocking JDBC spec (Java 10?)
‣ More non-blocking Spring modules
‣ …
Summary
71
‣ K-V Storage - perfect for video games
‣ Design Non-Blocking by Default
‣ RxJava and Reactor are friends
‣ Spring unites everyone
References
72
‣ Why Couchbase chose RxJava

hTps://goo.gl/dWeS35
‣ Reac7ve Spring by Josh Long

hTps://goo.gl/EXtJrB
‣ Developing Reac7ve applica7ons with Reac7ve Streams

hTps://goo.gl/eeNaAh
‣ Spring Boot 2.0 change-log

hTps://goo.gl/j8HFuY
2
THANK YOU
@alexsderkach.io
twi>er
blog
We’re hiring!
Slides
Wanna use
Spring 5 & RxJava?

More Related Content

What's hot

Reactive programming in Angular 2
Reactive programming in Angular 2Reactive programming in Angular 2
Reactive programming in Angular 2Yakov Fain
 
I can't believe it's not a queue: Kafka and Spring
I can't believe it's not a queue: Kafka and SpringI can't believe it's not a queue: Kafka and Spring
I can't believe it's not a queue: Kafka and SpringJoe Kutner
 
Docker 對傳統 DevOps 工具鏈的衝擊 (Docker's Impact on traditional DevOps toolchain)
Docker 對傳統 DevOps 工具鏈的衝擊 (Docker's Impact on traditional DevOps toolchain)Docker 對傳統 DevOps 工具鏈的衝擊 (Docker's Impact on traditional DevOps toolchain)
Docker 對傳統 DevOps 工具鏈的衝擊 (Docker's Impact on traditional DevOps toolchain)William Yeh
 
Introduction to Retrofit and RxJava
Introduction to Retrofit and RxJavaIntroduction to Retrofit and RxJava
Introduction to Retrofit and RxJavaFabio Collini
 
Real world functional reactive programming
Real world functional reactive programmingReal world functional reactive programming
Real world functional reactive programmingEric Polerecky
 
Containerizing a Web Application with Vue.js and Java
Containerizing a Web Application with Vue.js and JavaContainerizing a Web Application with Vue.js and Java
Containerizing a Web Application with Vue.js and JavaJadson Santos
 
Short intro to scala and the play framework
Short intro to scala and the play frameworkShort intro to scala and the play framework
Short intro to scala and the play frameworkFelipe
 
Machine learning with Apache Spark on Kubernetes | DevNation Tech Talk
Machine learning with Apache Spark on Kubernetes | DevNation Tech TalkMachine learning with Apache Spark on Kubernetes | DevNation Tech Talk
Machine learning with Apache Spark on Kubernetes | DevNation Tech TalkRed Hat Developers
 
Tech Talks_25.04.15_Session 3_Tibor Sulyan_Distributed coordination with zook...
Tech Talks_25.04.15_Session 3_Tibor Sulyan_Distributed coordination with zook...Tech Talks_25.04.15_Session 3_Tibor Sulyan_Distributed coordination with zook...
Tech Talks_25.04.15_Session 3_Tibor Sulyan_Distributed coordination with zook...EPAM_Systems_Bulgaria
 
Non Blocking I/O for Everyone with RxJava
Non Blocking I/O for Everyone with RxJavaNon Blocking I/O for Everyone with RxJava
Non Blocking I/O for Everyone with RxJavaFrank Lyaruu
 
Cloning Running Servers with Docker and CRIU by Ross Boucher
Cloning Running Servers with Docker and CRIU by Ross BoucherCloning Running Servers with Docker and CRIU by Ross Boucher
Cloning Running Servers with Docker and CRIU by Ross BoucherDocker, Inc.
 
Akka Actor presentation
Akka Actor presentationAkka Actor presentation
Akka Actor presentationGene Chang
 
KubeCon EU 2016: Kubernetes and the Potential for Higher Level Interfaces
KubeCon EU 2016: Kubernetes and the Potential for Higher Level InterfacesKubeCon EU 2016: Kubernetes and the Potential for Higher Level Interfaces
KubeCon EU 2016: Kubernetes and the Potential for Higher Level InterfacesKubeAcademy
 
Seven perilous pitfalls to avoid with Java | DevNation Tech Talk
Seven perilous pitfalls to avoid with Java | DevNation Tech TalkSeven perilous pitfalls to avoid with Java | DevNation Tech Talk
Seven perilous pitfalls to avoid with Java | DevNation Tech TalkRed Hat Developers
 
Modern Java Workshop
Modern Java WorkshopModern Java Workshop
Modern Java WorkshopSimon Ritter
 
Docker and Go: why did we decide to write Docker in Go?
Docker and Go: why did we decide to write Docker in Go?Docker and Go: why did we decide to write Docker in Go?
Docker and Go: why did we decide to write Docker in Go?Jérôme Petazzoni
 

What's hot (20)

Reactive programming in Angular 2
Reactive programming in Angular 2Reactive programming in Angular 2
Reactive programming in Angular 2
 
I can't believe it's not a queue: Kafka and Spring
I can't believe it's not a queue: Kafka and SpringI can't believe it's not a queue: Kafka and Spring
I can't believe it's not a queue: Kafka and Spring
 
rx-java-presentation
rx-java-presentationrx-java-presentation
rx-java-presentation
 
Docker 對傳統 DevOps 工具鏈的衝擊 (Docker's Impact on traditional DevOps toolchain)
Docker 對傳統 DevOps 工具鏈的衝擊 (Docker's Impact on traditional DevOps toolchain)Docker 對傳統 DevOps 工具鏈的衝擊 (Docker's Impact on traditional DevOps toolchain)
Docker 對傳統 DevOps 工具鏈的衝擊 (Docker's Impact on traditional DevOps toolchain)
 
Introduction to Retrofit and RxJava
Introduction to Retrofit and RxJavaIntroduction to Retrofit and RxJava
Introduction to Retrofit and RxJava
 
Real world functional reactive programming
Real world functional reactive programmingReal world functional reactive programming
Real world functional reactive programming
 
Containerizing a Web Application with Vue.js and Java
Containerizing a Web Application with Vue.js and JavaContainerizing a Web Application with Vue.js and Java
Containerizing a Web Application with Vue.js and Java
 
Short intro to scala and the play framework
Short intro to scala and the play frameworkShort intro to scala and the play framework
Short intro to scala and the play framework
 
Javantura v3 - ES6 – Future Is Now – Nenad Pečanac
Javantura v3 - ES6 – Future Is Now – Nenad PečanacJavantura v3 - ES6 – Future Is Now – Nenad Pečanac
Javantura v3 - ES6 – Future Is Now – Nenad Pečanac
 
Machine learning with Apache Spark on Kubernetes | DevNation Tech Talk
Machine learning with Apache Spark on Kubernetes | DevNation Tech TalkMachine learning with Apache Spark on Kubernetes | DevNation Tech Talk
Machine learning with Apache Spark on Kubernetes | DevNation Tech Talk
 
Tech Talks_25.04.15_Session 3_Tibor Sulyan_Distributed coordination with zook...
Tech Talks_25.04.15_Session 3_Tibor Sulyan_Distributed coordination with zook...Tech Talks_25.04.15_Session 3_Tibor Sulyan_Distributed coordination with zook...
Tech Talks_25.04.15_Session 3_Tibor Sulyan_Distributed coordination with zook...
 
Non Blocking I/O for Everyone with RxJava
Non Blocking I/O for Everyone with RxJavaNon Blocking I/O for Everyone with RxJava
Non Blocking I/O for Everyone with RxJava
 
Cloning Running Servers with Docker and CRIU by Ross Boucher
Cloning Running Servers with Docker and CRIU by Ross BoucherCloning Running Servers with Docker and CRIU by Ross Boucher
Cloning Running Servers with Docker and CRIU by Ross Boucher
 
Reactive Java (33rd Degree)
Reactive Java (33rd Degree)Reactive Java (33rd Degree)
Reactive Java (33rd Degree)
 
RxJava Applied
RxJava AppliedRxJava Applied
RxJava Applied
 
Akka Actor presentation
Akka Actor presentationAkka Actor presentation
Akka Actor presentation
 
KubeCon EU 2016: Kubernetes and the Potential for Higher Level Interfaces
KubeCon EU 2016: Kubernetes and the Potential for Higher Level InterfacesKubeCon EU 2016: Kubernetes and the Potential for Higher Level Interfaces
KubeCon EU 2016: Kubernetes and the Potential for Higher Level Interfaces
 
Seven perilous pitfalls to avoid with Java | DevNation Tech Talk
Seven perilous pitfalls to avoid with Java | DevNation Tech TalkSeven perilous pitfalls to avoid with Java | DevNation Tech Talk
Seven perilous pitfalls to avoid with Java | DevNation Tech Talk
 
Modern Java Workshop
Modern Java WorkshopModern Java Workshop
Modern Java Workshop
 
Docker and Go: why did we decide to write Docker in Go?
Docker and Go: why did we decide to write Docker in Go?Docker and Go: why did we decide to write Docker in Go?
Docker and Go: why did we decide to write Docker in Go?
 

Similar to Bulding a reactive game engine with Spring 5 & Couchbase

Original slides from Ryan Dahl's NodeJs intro talk
Original slides from Ryan Dahl's NodeJs intro talkOriginal slides from Ryan Dahl's NodeJs intro talk
Original slides from Ryan Dahl's NodeJs intro talkAarti Parikh
 
FrenchKit 2017: Server(less) Swift
FrenchKit 2017: Server(less) SwiftFrenchKit 2017: Server(less) Swift
FrenchKit 2017: Server(less) SwiftChris Bailey
 
Playing With Fire - An Introduction to Node.js
Playing With Fire - An Introduction to Node.jsPlaying With Fire - An Introduction to Node.js
Playing With Fire - An Introduction to Node.jsMike Hagedorn
 
An intro to Docker, Terraform, and Amazon ECS
An intro to Docker, Terraform, and Amazon ECSAn intro to Docker, Terraform, and Amazon ECS
An intro to Docker, Terraform, and Amazon ECSYevgeniy Brikman
 
AFUP Lorraine - Symfony Webpack Encore
AFUP Lorraine - Symfony Webpack EncoreAFUP Lorraine - Symfony Webpack Encore
AFUP Lorraine - Symfony Webpack EncoreEngineor
 
Hopping in clouds - phpuk 17
Hopping in clouds - phpuk 17Hopping in clouds - phpuk 17
Hopping in clouds - phpuk 17Michele Orselli
 
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_19confluent
 
Node.js - async for the rest of us.
Node.js - async for the rest of us.Node.js - async for the rest of us.
Node.js - async for the rest of us.Mike Brevoort
 
MySQL Audit using Percona audit plugin and ELK
MySQL Audit using Percona audit plugin and ELKMySQL Audit using Percona audit plugin and ELK
MySQL Audit using Percona audit plugin and ELKYoungHeon (Roy) Kim
 
Automated Spark Deployment With Declarative Infrastructure
Automated Spark Deployment With Declarative InfrastructureAutomated Spark Deployment With Declarative Infrastructure
Automated Spark Deployment With Declarative InfrastructureSpark Summit
 
Burn down the silos! Helping dev and ops gel on high availability websites
Burn down the silos! Helping dev and ops gel on high availability websitesBurn down the silos! Helping dev and ops gel on high availability websites
Burn down the silos! Helping dev and ops gel on high availability websitesLindsay Holmwood
 
A Deep Dive into Query Execution Engine of Spark SQL
A Deep Dive into Query Execution Engine of Spark SQLA Deep Dive into Query Execution Engine of Spark SQL
A Deep Dive into Query Execution Engine of Spark SQLDatabricks
 
Into The Box 2018 Going live with commandbox and docker
Into The Box 2018 Going live with commandbox and dockerInto The Box 2018 Going live with commandbox and docker
Into The Box 2018 Going live with commandbox and dockerOrtus Solutions, Corp
 
Going live with BommandBox and docker Into The Box 2018
Going live with BommandBox and docker Into The Box 2018Going live with BommandBox and docker Into The Box 2018
Going live with BommandBox and docker Into The Box 2018Ortus Solutions, Corp
 
Cristiano Betta (Betta Works) - Lightweight Libraries with Rollup, Riot and R...
Cristiano Betta (Betta Works) - Lightweight Libraries with Rollup, Riot and R...Cristiano Betta (Betta Works) - Lightweight Libraries with Rollup, Riot and R...
Cristiano Betta (Betta Works) - Lightweight Libraries with Rollup, Riot and R...Techsylvania
 
Live deployment, ci, drupal
Live deployment, ci, drupalLive deployment, ci, drupal
Live deployment, ci, drupalAndrii Podanenko
 

Similar to Bulding a reactive game engine with Spring 5 & Couchbase (20)

Original slides from Ryan Dahl's NodeJs intro talk
Original slides from Ryan Dahl's NodeJs intro talkOriginal slides from Ryan Dahl's NodeJs intro talk
Original slides from Ryan Dahl's NodeJs intro talk
 
Serverless and React
Serverless and ReactServerless and React
Serverless and React
 
FrenchKit 2017: Server(less) Swift
FrenchKit 2017: Server(less) SwiftFrenchKit 2017: Server(less) Swift
FrenchKit 2017: Server(less) Swift
 
Playing With Fire - An Introduction to Node.js
Playing With Fire - An Introduction to Node.jsPlaying With Fire - An Introduction to Node.js
Playing With Fire - An Introduction to Node.js
 
Fun with Ruby and Cocoa
Fun with Ruby and CocoaFun with Ruby and Cocoa
Fun with Ruby and Cocoa
 
An intro to Docker, Terraform, and Amazon ECS
An intro to Docker, Terraform, and Amazon ECSAn intro to Docker, Terraform, and Amazon ECS
An intro to Docker, Terraform, and Amazon ECS
 
AFUP Lorraine - Symfony Webpack Encore
AFUP Lorraine - Symfony Webpack EncoreAFUP Lorraine - Symfony Webpack Encore
AFUP Lorraine - Symfony Webpack Encore
 
Hopping in clouds - phpuk 17
Hopping in clouds - phpuk 17Hopping in clouds - phpuk 17
Hopping in clouds - phpuk 17
 
Play framework
Play frameworkPlay framework
Play framework
 
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
 
Node.js - async for the rest of us.
Node.js - async for the rest of us.Node.js - async for the rest of us.
Node.js - async for the rest of us.
 
MySQL Audit using Percona audit plugin and ELK
MySQL Audit using Percona audit plugin and ELKMySQL Audit using Percona audit plugin and ELK
MySQL Audit using Percona audit plugin and ELK
 
Automated Spark Deployment With Declarative Infrastructure
Automated Spark Deployment With Declarative InfrastructureAutomated Spark Deployment With Declarative Infrastructure
Automated Spark Deployment With Declarative Infrastructure
 
Play vs Rails
Play vs RailsPlay vs Rails
Play vs Rails
 
Burn down the silos! Helping dev and ops gel on high availability websites
Burn down the silos! Helping dev and ops gel on high availability websitesBurn down the silos! Helping dev and ops gel on high availability websites
Burn down the silos! Helping dev and ops gel on high availability websites
 
A Deep Dive into Query Execution Engine of Spark SQL
A Deep Dive into Query Execution Engine of Spark SQLA Deep Dive into Query Execution Engine of Spark SQL
A Deep Dive into Query Execution Engine of Spark SQL
 
Into The Box 2018 Going live with commandbox and docker
Into The Box 2018 Going live with commandbox and dockerInto The Box 2018 Going live with commandbox and docker
Into The Box 2018 Going live with commandbox and docker
 
Going live with BommandBox and docker Into The Box 2018
Going live with BommandBox and docker Into The Box 2018Going live with BommandBox and docker Into The Box 2018
Going live with BommandBox and docker Into The Box 2018
 
Cristiano Betta (Betta Works) - Lightweight Libraries with Rollup, Riot and R...
Cristiano Betta (Betta Works) - Lightweight Libraries with Rollup, Riot and R...Cristiano Betta (Betta Works) - Lightweight Libraries with Rollup, Riot and R...
Cristiano Betta (Betta Works) - Lightweight Libraries with Rollup, Riot and R...
 
Live deployment, ci, drupal
Live deployment, ci, drupalLive deployment, ci, drupal
Live deployment, ci, drupal
 

Recently uploaded

+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...
+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...
+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...Health
 
A Secure and Reliable Document Management System is Essential.docx
A Secure and Reliable Document Management System is Essential.docxA Secure and Reliable Document Management System is Essential.docx
A Secure and Reliable Document Management System is Essential.docxComplianceQuest1
 
Unveiling the Tech Salsa of LAMs with Janus in Real-Time Applications
Unveiling the Tech Salsa of LAMs with Janus in Real-Time ApplicationsUnveiling the Tech Salsa of LAMs with Janus in Real-Time Applications
Unveiling the Tech Salsa of LAMs with Janus in Real-Time ApplicationsAlberto González Trastoy
 
Reassessing the Bedrock of Clinical Function Models: An Examination of Large ...
Reassessing the Bedrock of Clinical Function Models: An Examination of Large ...Reassessing the Bedrock of Clinical Function Models: An Examination of Large ...
Reassessing the Bedrock of Clinical Function Models: An Examination of Large ...harshavardhanraghave
 
The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...
The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...
The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...ICS
 
CALL ON ➥8923113531 🔝Call Girls Kakori Lucknow best sexual service Online ☂️
CALL ON ➥8923113531 🔝Call Girls Kakori Lucknow best sexual service Online  ☂️CALL ON ➥8923113531 🔝Call Girls Kakori Lucknow best sexual service Online  ☂️
CALL ON ➥8923113531 🔝Call Girls Kakori Lucknow best sexual service Online ☂️anilsa9823
 
CALL ON ➥8923113531 🔝Call Girls Badshah Nagar Lucknow best Female service
CALL ON ➥8923113531 🔝Call Girls Badshah Nagar Lucknow best Female serviceCALL ON ➥8923113531 🔝Call Girls Badshah Nagar Lucknow best Female service
CALL ON ➥8923113531 🔝Call Girls Badshah Nagar Lucknow best Female serviceanilsa9823
 
W01_panagenda_Navigating-the-Future-with-The-Hitchhikers-Guide-to-Notes-and-D...
W01_panagenda_Navigating-the-Future-with-The-Hitchhikers-Guide-to-Notes-and-D...W01_panagenda_Navigating-the-Future-with-The-Hitchhikers-Guide-to-Notes-and-D...
W01_panagenda_Navigating-the-Future-with-The-Hitchhikers-Guide-to-Notes-and-D...panagenda
 
5 Signs You Need a Fashion PLM Software.pdf
5 Signs You Need a Fashion PLM Software.pdf5 Signs You Need a Fashion PLM Software.pdf
5 Signs You Need a Fashion PLM Software.pdfWave PLM
 
Short Story: Unveiling the Reasoning Abilities of Large Language Models by Ke...
Short Story: Unveiling the Reasoning Abilities of Large Language Models by Ke...Short Story: Unveiling the Reasoning Abilities of Large Language Models by Ke...
Short Story: Unveiling the Reasoning Abilities of Large Language Models by Ke...kellynguyen01
 
Try MyIntelliAccount Cloud Accounting Software As A Service Solution Risk Fre...
Try MyIntelliAccount Cloud Accounting Software As A Service Solution Risk Fre...Try MyIntelliAccount Cloud Accounting Software As A Service Solution Risk Fre...
Try MyIntelliAccount Cloud Accounting Software As A Service Solution Risk Fre...MyIntelliSource, Inc.
 
Right Money Management App For Your Financial Goals
Right Money Management App For Your Financial GoalsRight Money Management App For Your Financial Goals
Right Money Management App For Your Financial GoalsJhone kinadey
 
Learn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdf
Learn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdfLearn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdf
Learn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdfkalichargn70th171
 
TECUNIQUE: Success Stories: IT Service provider
TECUNIQUE: Success Stories: IT Service providerTECUNIQUE: Success Stories: IT Service provider
TECUNIQUE: Success Stories: IT Service providermohitmore19
 
Diamond Application Development Crafting Solutions with Precision
Diamond Application Development Crafting Solutions with PrecisionDiamond Application Development Crafting Solutions with Precision
Diamond Application Development Crafting Solutions with PrecisionSolGuruz
 
Unlocking the Future of AI Agents with Large Language Models
Unlocking the Future of AI Agents with Large Language ModelsUnlocking the Future of AI Agents with Large Language Models
Unlocking the Future of AI Agents with Large Language Modelsaagamshah0812
 
Tech Tuesday-Harness the Power of Effective Resource Planning with OnePlan’s ...
Tech Tuesday-Harness the Power of Effective Resource Planning with OnePlan’s ...Tech Tuesday-Harness the Power of Effective Resource Planning with OnePlan’s ...
Tech Tuesday-Harness the Power of Effective Resource Planning with OnePlan’s ...OnePlan Solutions
 
Hand gesture recognition PROJECT PPT.pptx
Hand gesture recognition PROJECT PPT.pptxHand gesture recognition PROJECT PPT.pptx
Hand gesture recognition PROJECT PPT.pptxbodapatigopi8531
 
How To Use Server-Side Rendering with Nuxt.js
How To Use Server-Side Rendering with Nuxt.jsHow To Use Server-Side Rendering with Nuxt.js
How To Use Server-Side Rendering with Nuxt.jsAndolasoft Inc
 

Recently uploaded (20)

+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...
+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...
+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...
 
A Secure and Reliable Document Management System is Essential.docx
A Secure and Reliable Document Management System is Essential.docxA Secure and Reliable Document Management System is Essential.docx
A Secure and Reliable Document Management System is Essential.docx
 
Unveiling the Tech Salsa of LAMs with Janus in Real-Time Applications
Unveiling the Tech Salsa of LAMs with Janus in Real-Time ApplicationsUnveiling the Tech Salsa of LAMs with Janus in Real-Time Applications
Unveiling the Tech Salsa of LAMs with Janus in Real-Time Applications
 
Vip Call Girls Noida ➡️ Delhi ➡️ 9999965857 No Advance 24HRS Live
Vip Call Girls Noida ➡️ Delhi ➡️ 9999965857 No Advance 24HRS LiveVip Call Girls Noida ➡️ Delhi ➡️ 9999965857 No Advance 24HRS Live
Vip Call Girls Noida ➡️ Delhi ➡️ 9999965857 No Advance 24HRS Live
 
Reassessing the Bedrock of Clinical Function Models: An Examination of Large ...
Reassessing the Bedrock of Clinical Function Models: An Examination of Large ...Reassessing the Bedrock of Clinical Function Models: An Examination of Large ...
Reassessing the Bedrock of Clinical Function Models: An Examination of Large ...
 
The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...
The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...
The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...
 
CALL ON ➥8923113531 🔝Call Girls Kakori Lucknow best sexual service Online ☂️
CALL ON ➥8923113531 🔝Call Girls Kakori Lucknow best sexual service Online  ☂️CALL ON ➥8923113531 🔝Call Girls Kakori Lucknow best sexual service Online  ☂️
CALL ON ➥8923113531 🔝Call Girls Kakori Lucknow best sexual service Online ☂️
 
CALL ON ➥8923113531 🔝Call Girls Badshah Nagar Lucknow best Female service
CALL ON ➥8923113531 🔝Call Girls Badshah Nagar Lucknow best Female serviceCALL ON ➥8923113531 🔝Call Girls Badshah Nagar Lucknow best Female service
CALL ON ➥8923113531 🔝Call Girls Badshah Nagar Lucknow best Female service
 
W01_panagenda_Navigating-the-Future-with-The-Hitchhikers-Guide-to-Notes-and-D...
W01_panagenda_Navigating-the-Future-with-The-Hitchhikers-Guide-to-Notes-and-D...W01_panagenda_Navigating-the-Future-with-The-Hitchhikers-Guide-to-Notes-and-D...
W01_panagenda_Navigating-the-Future-with-The-Hitchhikers-Guide-to-Notes-and-D...
 
5 Signs You Need a Fashion PLM Software.pdf
5 Signs You Need a Fashion PLM Software.pdf5 Signs You Need a Fashion PLM Software.pdf
5 Signs You Need a Fashion PLM Software.pdf
 
Short Story: Unveiling the Reasoning Abilities of Large Language Models by Ke...
Short Story: Unveiling the Reasoning Abilities of Large Language Models by Ke...Short Story: Unveiling the Reasoning Abilities of Large Language Models by Ke...
Short Story: Unveiling the Reasoning Abilities of Large Language Models by Ke...
 
Try MyIntelliAccount Cloud Accounting Software As A Service Solution Risk Fre...
Try MyIntelliAccount Cloud Accounting Software As A Service Solution Risk Fre...Try MyIntelliAccount Cloud Accounting Software As A Service Solution Risk Fre...
Try MyIntelliAccount Cloud Accounting Software As A Service Solution Risk Fre...
 
Right Money Management App For Your Financial Goals
Right Money Management App For Your Financial GoalsRight Money Management App For Your Financial Goals
Right Money Management App For Your Financial Goals
 
Learn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdf
Learn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdfLearn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdf
Learn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdf
 
TECUNIQUE: Success Stories: IT Service provider
TECUNIQUE: Success Stories: IT Service providerTECUNIQUE: Success Stories: IT Service provider
TECUNIQUE: Success Stories: IT Service provider
 
Diamond Application Development Crafting Solutions with Precision
Diamond Application Development Crafting Solutions with PrecisionDiamond Application Development Crafting Solutions with Precision
Diamond Application Development Crafting Solutions with Precision
 
Unlocking the Future of AI Agents with Large Language Models
Unlocking the Future of AI Agents with Large Language ModelsUnlocking the Future of AI Agents with Large Language Models
Unlocking the Future of AI Agents with Large Language Models
 
Tech Tuesday-Harness the Power of Effective Resource Planning with OnePlan’s ...
Tech Tuesday-Harness the Power of Effective Resource Planning with OnePlan’s ...Tech Tuesday-Harness the Power of Effective Resource Planning with OnePlan’s ...
Tech Tuesday-Harness the Power of Effective Resource Planning with OnePlan’s ...
 
Hand gesture recognition PROJECT PPT.pptx
Hand gesture recognition PROJECT PPT.pptxHand gesture recognition PROJECT PPT.pptx
Hand gesture recognition PROJECT PPT.pptx
 
How To Use Server-Side Rendering with Nuxt.js
How To Use Server-Side Rendering with Nuxt.jsHow To Use Server-Side Rendering with Nuxt.js
How To Use Server-Side Rendering with Nuxt.js
 

Bulding a reactive game engine with Spring 5 & Couchbase

  • 1. Building reac-ve game engine with Spring 5 & Couchbase Alex Derkach Senior So0ware Engineer @ Play7ka
  • 2. @alexsderkach ‣ Java addict since ’12 ‣ SSE @ Slotomania Feature Team ‣ Ac7ve Couchbase & Spring user ‣ All things reac7ve & distributed 2h>p://alexsderkach.io slides
  • 3. Plan for today 3 ‣ Why Couchbase + Quick Overview ‣ Reac7ve founda7on behind Spring 5 ‣ Demonstra7on & Case Study ‣ Summary
  • 4. Applica-on Layer Old-School Architecture 4 App App App App App App Read/Write Requests RDBMS
  • 5. Individual Memcached NodesApplica-on Layer Old-School Architecture 5 App App App App App App Cache Misses & Write Requests RDBMS Read/Write requests RDBMS
  • 6. 6
  • 7. Video game is not ‘yet another web app’ 7 ‣ Rapid Fall or Growth ‣ Responsiveness will brake you ‣ Always ON ‣ Flexible Data Model
  • 8. It all comes to this… 8
  • 9. What is Couchbase? 9 ‣ Key-Document storage ‣ Consistent high performance ‣ Scale with single “push” buTon ‣ Zero-down7me opera7ons
  • 10. Server 10 Couchbase Architecture Cluster Manager Data Service Index Service Query Service Cache Storage Server Cluster Manager Data Service Index Service Query Service Cache Storage Server Cluster Manager Data Service Index Service Query Service Cache Storage Server Cluster Manager Data Service Index Service Query Service Cache Storage Server Cluster Manager Data Service Index Service Query Service Cache Storage Couchbase Cluster
  • 11. Server 11 Couchbase Architecture Cluster Manager Data Service Cache Storage Server Cluster Manager Data Service Cache Storage Server Cluster Manager Query Service Cache Storage Server Cluster Manager Index Service Cache Storage Server Cluster Manager Index Service Cache Storage Couchbase Cluster
  • 12. 12 Example Use Case: Leaderboard SELECT * FROM `scores` WHERE roundId = 10 ORDER BY score DESC LIMIT 3 Data Service Index Service Query Service
  • 13. Couchbase SDK 13 ‣ RxJava 1 ‣ CRUD ‣ N1QL ‣ Map/Reduce ‣ Administra7on bucket .get("whiskey") .onErrorResumeNext(bucket.getFromReplica("whiskey", ReplicaMode.ALL)) .first() .map(doc -> doc.content().getString("name")) .timeout(2, TimeUnit.SECONDS) .doOnError(System.err::println) .onErrorReturn(error -> "Not found!")
  • 14. Couchbase SDK 14 ‣ RxJava 1 ‣ CRUD ‣ N1QL ‣ Map/Reduce ‣ Administra7on bucket .get("whiskey") .onErrorResumeNext(bucket.getFromReplica("whiskey", ReplicaMode.ALL)) .first() .map(doc -> doc.content().getString("name")) .timeout(2, TimeUnit.SECONDS) .doOnError(System.err::println) .onErrorReturn(error -> "Not found!")
  • 15. Couchbase SDK 15 ‣ RxJava 1 ‣ CRUD ‣ N1QL ‣ Map/Reduce ‣ Administra7on bucket .get("whiskey") .onErrorResumeNext(bucket.getFromReplica("whiskey", ReplicaMode.ALL)) .first() .map(doc -> doc.content().getString("name")) .timeout(2, TimeUnit.SECONDS) .doOnError(System.err::println) .onErrorReturn(error -> "Not found!")
  • 16. Couchbase SDK 16 ‣ RxJava 1 ‣ CRUD ‣ N1QL ‣ Map/Reduce ‣ Administra7on bucket .get("whiskey") .onErrorResumeNext(bucket.getFromReplica("whiskey", ReplicaMode.ALL)) .first() .map(doc -> doc.content().getString("name")) .timeout(2, TimeUnit.SECONDS) .doOnError(System.err::println) .onErrorReturn(error -> "Not found!")
  • 17. Couchbase SDK 17 ‣ RxJava 1 ‣ CRUD ‣ N1QL ‣ Map/Reduce ‣ Administra7on bucket .get("whiskey") .onErrorResumeNext(bucket.getFromReplica("whiskey", ReplicaMode.ALL)) .first() .map(doc -> doc.content().getString("name")) .timeout(2, TimeUnit.SECONDS) .doOnError(System.err::println) .onErrorReturn(error -> "Not found!")
  • 18. Couchbase SDK 18 ‣ RxJava 1 ‣ CRUD ‣ N1QL ‣ Map/Reduce ‣ Administra7on bucket .get("whiskey") .onErrorResumeNext(bucket.getFromReplica("whiskey", ReplicaMode.ALL)) .first() .map(doc -> doc.content().getString("name")) .timeout(2, TimeUnit.SECONDS) .doOnError(System.err::println) .onErrorReturn(error -> "Not found!")
  • 19. Couchbase SDK 19 ‣ RxJava 1 ‣ CRUD ‣ N1QL ‣ Map/Reduce ‣ Administra7on bucket .get("whiskey") .onErrorResumeNext(bucket.getFromReplica("whiskey", ReplicaMode.ALL)) .first() .map(doc -> doc.content().getString("name")) .timeout(2, TimeUnit.SECONDS) .doOnError(System.err::println) .onErrorReturn(error -> "Not found!")
  • 20. Couchbase SDK 20 ‣ RxJava 1 ‣ CRUD ‣ N1QL ‣ Map/Reduce ‣ Administra7on bucket .get("whiskey") .onErrorResumeNext(bucket.getFromReplica("whiskey", ReplicaMode.ALL)) .first() .map(doc -> doc.content().getString("name")) .timeout(2, TimeUnit.SECONDS) .doOnError(System.err::println) .onErrorReturn(error -> "Not found!")
  • 21. 21
  • 22. 22 Couchbase Connector wait for events handle events Thread get(“user::1”) result RUNNING RUNNING BLOCKED Couchbase
  • 23. 23 public interface Publisher<T> { void subscribe(Subscriber<? super T> s); } public interface Subscriber<T> { void onSubscribe(Subscription s); void onNext(T t); void onError(Throwable t); void onComplete(); } public interface Subscription { void request(long n); void cancel(); } public interface Processor<T, R> extends Subscriber<T>, Publisher<R> { } h>ps://github.com/reac-ve-streams/reac-ve-streams-jvm Let’s build Reac-ve Framework!
  • 24. DIY - Reac-ve Framework 24 1. Should work with RS Java Specifica7on 2. Address the reentrance 3. Address thread safety 4. Address back-pressure 5. Address state 6. For Many-To-One Flows, implement merging 7. For One-To-Many, implement broadcas7ng 8. … h>ps://github.com/reac-ve-streams/reac-ve-streams-jvm
  • 25. DIY - Reac-ve Framework 25 1. Should work with RS Java Specifica7on 2. Address the reentrance 3. Address thread safety 4. Address back-pressure 5. Address state 6. For Many-To-One Flows, implement merging 7. For One-To-Many, implement broadcas7ng 8. … h>ps://github.com/reac-ve-streams/reac-ve-streams-jvm
  • 26. 26
  • 27. 27 MySQL Thread RUNNING BLOCKED Couchbase User Service Payment Service Twitter API BLOCKED BLOCKED BLOCKED BLOCKED RUNNING RUNNING RUNNING 3rd party
  • 28. Spring 5 28 ‣ Based on Reactor Core 3 ‣ Reac7ve HTTP Server Abstrac7on ‣ Compa7ble with RxJava 1 & 2 ‣ Compa7ble with Java 9 ‣ Many more!
  • 29. 29 ‣ Func7onal, declara7ve programming model ‣ Combine, transform, reduce sequences (500+ methods) ‣ Reac7ve Streams ready ‣ Focus on what, not how Reactor 3 Crash Course Flux / Mono Subscriber 0..N Data + 0..1 (Error, Completed) Backpressure regulation
  • 30. 30 Learning to Flux OR Flux.create(sink -> *blocking call*);Mono.create(sink -> *blocking call*);
  • 31. 31 Learning to Flux Mono.create(sink -> { val result = repository.findOne(1L); if (result.isPresent()) { sink.success(result.get()); } else { sink.error(new UserNotFoundException(id)); } }) .subscribe(System.out::println); Flux.create(sink -> *blocking call*);Mono.create(sink -> *blocking call*); OR
  • 32. 32 Learning to Flux Mono.create(sink -> { val result = repository.findOne(1L); if (result.isPresent()) { sink.success(result.get()); } else { sink.error(new UserNotFoundException(id)); } }) .subscribe(System.out::println); Flux.create(sink -> *blocking call*);Mono.create(sink -> *blocking call*); Flux.create(sink -> { val ids = asList(1L, 2L, 3L); val result = userRepository.findAll(ids); for (User user : result) { sink.next(user); } sink.complete(); }) .subscribe(System.out::println); OR
  • 33. 33 Flux.create(..., ); enum OverflowStrategy { // Completely ignore downstream backpressure requests. IGNORE, // Signal an IllegalStateException when the downstream can't keep up ERROR, // Drop the incoming signal if the downstream is not ready to receive it. DROP, // Downstream will get only the latest signals from upstream. LATEST, // Buffer all signals if the downstream can't keep up. BUFFER } Backpressure
  • 34. 34 Flux.<User>create(sink -> { userRepository.findAll(ids).forEach(sink::next); sink.complete(); }) .filter(user -> user.getGender() == MALE) .map(user -> new User(user.getId(), user.getName().toUpperCase())) .buffer(20) .flatMap(users -> Flux.create(sink -> { userRepository.save(users).forEach(sink::next); sink.complete(); }) .subscribeOn(Schedulers.elastic()) ) .subscribeOn(Schedulers.elastic()) .subscribe(System.out::println, System.err::println); I have a Flux. What’s next?
  • 35. 35 Flux.<User>create(sink -> { userRepository.findAll(ids).forEach(sink::next); sink.complete(); }) .filter(user -> user.getGender() == MALE) .map(user -> new User(user.getId(), user.getName().toUpperCase())) .buffer(20) .flatMap(users -> Flux.create(sink -> { userRepository.save(users).forEach(sink::next); sink.complete(); }) .subscribeOn(Schedulers.elastic()) ) .subscribeOn(Schedulers.elastic()) .subscribe(System.out::println, System.err::println); I have a Flux. What’s next?
  • 36. 36 Be Blocking or Non-Blocking?
  • 37. 37 Be Blocking or Non-Blocking? @Test public void testEmojiSource() { Flux<String> source = emojiSource(); Iterable<String> values = source.toIterable(); assertEquals(asList("🙈", "🙉", "🙊"), values); } @Test public void testWelcomeSource() { Mono<String> source = welcomeSource(); String value = source.block(); assertEquals("Hello", value); } Non-Blocking to Blocking
  • 38. 38 Be Blocking or Non-Blocking? @Test public void testEmojiSource() { Flux<String> source = emojiSource(); Iterable<String> values = source.toIterable(); assertEquals(asList("🙈", "🙉", "🙊"), values); } @Test public void testWelcomeSource() { Mono<String> source = welcomeSource(); String value = source.block(); assertEquals("Hello", value); } Non-Blocking to Blocking Blocking to Non-Blocking
  • 39.
  • 41. 41 spring-web Dispatcher Handler Jetty Netty Tomcat Undertow HttpServlet Request|Response HttpServer Request|Response HttpServlet Request|Response HttpServerExchange 🍒 ServerHttp Request|Response 1 1 1 1 public interface HandlerMapping { Mono<Object> getHandler( 🍒); } public interface HandlerAdapter { boolean supports(Object handler); Mono<HandlerResult> handle( 🍒, handler); } 2 3 spring-webflux <interface> WebHandler public interface HandlerMethodArgumentResolver { boolean supportsParameter(MethodParameter); Mono< 🍷> resolveArgument(MethodParameter, 🍒); } 4 handler.invoke(Mono< 🍷>...); 5
  • 42. 42 spring-web spring-webflux @RestController public class UserController { @GetMapping("/users/{id}") public User get(long id) { } @PostMapping("/users/") public User create(User user) { } @PutMapping("/users/{id}") public User update(long id, User user) { } @DeleteMapping("/users/{id}") public User delete(long id) { } } @RestController public class UserController { @GetMapping("/users/{id}") public User get(long id) { } @PostMapping("/users/") public User create(User user) { } @PutMapping("/users/{id}") public User update(long id, User user) { } @DeleteMapping("/users/{id}") public User delete(long id) { } }
  • 43. 43 spring-web spring-webflux @RestController public class UserController { @GetMapping("/users/{id}") public User get(long id) { } @PostMapping("/users/") public User create(User user) { } @PutMapping("/users/{id}") public User update(long id, User user) { } @DeleteMapping("/users/{id}") public User delete(long id) { } } @RestController public class UserController { @GetMapping("/users/{id}") public Mono<User> get(long id) { } @PostMapping("/users/") public Mono<User> create(Mono<User> user) { } @PutMapping("/users/{id}") public Mono<User> update(long id, Mono<User> user) { } @DeleteMapping("/users/{id}") public Mono<User> delete(long id) { } }
  • 44. DEMO
  • 45. 45 Flux against the world h>p://alexsderkach.io/comparing-java-8-rxjava-reactor/
  • 46. 46 Flux against the world composable lazy reusable async cached push back- pressure operator fusion CompletableFuture ✔ ✘ ✔ ✔ ✔ ✔ ✘ ✘ Stream ✔ ✔ ✘ ✘ ✘ ✘ ✘ ✘ Optional ✔ ✘ ✔ ✘ ✔ ✘ ✘ ✘ Observable (RxJava 1) ✔ ✔ ✔ ✔ ✔ *.cache() ✔ ✔ *.onBackpressure *() ✘ Observable (RxJava 2) ✔ ✔ ✔ ✔ ✔ *.cache() ✔ ✘ ✔ Flowable (RxJava 2) ✔ ✔ ✔ ✔ ✔ *.cache() ✔ ✔ ✔ Flux ✔ ✔ ✔ ✔ ✔ *.cache() ✔ ✔ ✔ h>p://alexsderkach.io/comparing-java-8-rxjava-reactor/
  • 47. 47 Flux against the world composable lazy reusable async cached push back- pressure operator fusion CompletableFuture ✔ ✘ ✔ ✔ ✔ ✔ ✘ ✘ Stream ✔ ✔ ✘ ✘ ✘ ✘ ✘ ✘ Optional ✔ ✘ ✔ ✘ ✔ ✘ ✘ ✘ Observable (RxJava 1) ✔ ✔ ✔ ✔ ✔ *.cache() ✔ ✔ *.onBackpressure *() ✘ Observable (RxJava 2) ✔ ✔ ✔ ✔ ✔ *.cache() ✔ ✘ ✔ Flowable (RxJava 2) ✔ ✔ ✔ ✔ ✔ *.cache() ✔ ✔ ✔ Flux ✔ ✔ ✔ ✔ ✔ *.cache() ✔ ✔ ✔ h>p://alexsderkach.io/comparing-java-8-rxjava-reactor/
  • 48. 48 Flux against the world composable lazy reusable async cached push back- pressure operator fusion CompletableFuture ✔ ✘ ✔ ✔ ✔ ✔ ✘ ✘ Stream ✔ ✔ ✘ ✘ ✘ ✘ ✘ ✘ Optional ✔ ✘ ✔ ✘ ✔ ✘ ✘ ✘ Observable (RxJava 1) ✔ ✔ ✔ ✔ ✔ *.cache() ✔ ✔ *.onBackpressure *() ✘ Observable (RxJava 2) ✔ ✔ ✔ ✔ ✔ *.cache() ✔ ✘ ✔ Flowable (RxJava 2) ✔ ✔ ✔ ✔ ✔ *.cache() ✔ ✔ ✔ Flux ✔ ✔ ✔ ✔ ✔ *.cache() ✔ ✔ ✔ h>p://alexsderkach.io/comparing-java-8-rxjava-reactor/
  • 49. 49 Flux against the world composable lazy reusable async cached push back- pressure operator fusion CompletableFuture ✔ ✘ ✔ ✔ ✔ ✔ ✘ ✘ Stream ✔ ✔ ✘ ✘ ✘ ✘ ✘ ✘ Optional ✔ ✘ ✔ ✘ ✔ ✘ ✘ ✘ Observable (RxJava 1) ✔ ✔ ✔ ✔ ✔ *.cache() ✔ ✔ *.onBackpressure *() ✘ Observable (RxJava 2) ✔ ✔ ✔ ✔ ✔ *.cache() ✔ ✘ ✔ Flowable (RxJava 2) ✔ ✔ ✔ ✔ ✔ *.cache() ✔ ✔ ✔ Flux ✔ ✔ ✔ ✔ ✔ *.cache() ✔ ✔ ✔ h>p://alexsderkach.io/comparing-java-8-rxjava-reactor/
  • 50. 50 Flux against the world composable lazy reusable async cached push back- pressure operator fusion CompletableFuture ✔ ✘ ✔ ✔ ✔ ✔ ✘ ✘ Stream ✔ ✔ ✘ ✘ ✘ ✘ ✘ ✘ Optional ✔ ✘ ✔ ✘ ✔ ✘ ✘ ✘ Observable (RxJava 1) ✔ ✔ ✔ ✔ ✔ *.cache() ✔ ✔ *.onBackpressure *() ✘ Observable (RxJava 2) ✔ ✔ ✔ ✔ ✔ *.cache() ✔ ✘ ✔ Flowable (RxJava 2) ✔ ✔ ✔ ✔ ✔ *.cache() ✔ ✔ ✔ Flux ✔ ✔ ✔ ✔ ✔ *.cache() ✔ ✔ ✔ h>p://alexsderkach.io/comparing-java-8-rxjava-reactor/
  • 51. 51 Flux against the world composable lazy reusable async cached push back- pressure operator fusion CompletableFuture ✔ ✘ ✔ ✔ ✔ ✔ ✘ ✘ Stream ✔ ✔ ✘ ✘ ✘ ✘ ✘ ✘ Optional ✔ ✘ ✔ ✘ ✔ ✘ ✘ ✘ Observable (RxJava 1) ✔ ✔ ✔ ✔ ✔ *.cache() ✔ ✔ *.onBackpressure *() ✘ Observable (RxJava 2) ✔ ✔ ✔ ✔ ✔ *.cache() ✔ ✘ ✔ Flowable (RxJava 2) ✔ ✔ ✔ ✔ ✔ *.cache() ✔ ✔ ✔ Flux ✔ ✔ ✔ ✔ ✔ *.cache() ✔ ✔ ✔ h>p://alexsderkach.io/comparing-java-8-rxjava-reactor/
  • 52. 52 Flux against the world composable lazy reusable async cached push back- pressure operator fusion CompletableFuture ✔ ✘ ✔ ✔ ✔ ✔ ✘ ✘ Stream ✔ ✔ ✘ ✘ ✘ ✘ ✘ ✘ Optional ✔ ✘ ✔ ✘ ✔ ✘ ✘ ✘ Observable (RxJava 1) ✔ ✔ ✔ ✔ ✔ *.cache() ✔ ✔ *.onBackpressure *() ✘ Observable (RxJava 2) ✔ ✔ ✔ ✔ ✔ *.cache() ✔ ✘ ✔ Flowable (RxJava 2) ✔ ✔ ✔ ✔ ✔ *.cache() ✔ ✔ ✔ Flux ✔ ✔ ✔ ✔ ✔ *.cache() ✔ ✔ ✔ h>p://alexsderkach.io/comparing-java-8-rxjava-reactor/
  • 53. 53 Flux against the world composable lazy reusable async cached push back- pressure operator fusion CompletableFuture ✔ ✘ ✔ ✔ ✔ ✔ ✘ ✘ Stream ✔ ✔ ✘ ✘ ✘ ✘ ✘ ✘ Optional ✔ ✘ ✔ ✘ ✔ ✘ ✘ ✘ Observable (RxJava 1) ✔ ✔ ✔ ✔ ✔ *.cache() ✔ ✔ *.onBackpressure *() ✘ Observable (RxJava 2) ✔ ✔ ✔ ✔ ✔ *.cache() ✔ ✘ ✔ Flowable (RxJava 2) ✔ ✔ ✔ ✔ ✔ *.cache() ✔ ✔ ✔ Flux ✔ ✔ ✔ ✔ ✔ *.cache() ✔ ✔ ✔ h>p://alexsderkach.io/comparing-java-8-rxjava-reactor/
  • 54. 54 Flux against the world composable lazy reusable async cached push back- pressure operator fusion CompletableFuture ✔ ✘ ✔ ✔ ✔ ✔ ✘ ✘ Stream ✔ ✔ ✘ ✘ ✘ ✘ ✘ ✘ Optional ✔ ✘ ✔ ✘ ✔ ✘ ✘ ✘ Observable (RxJava 1) ✔ ✔ ✔ ✔ ✔ *.cache() ✔ ✔ *.onBackpressure *() ✘ Observable (RxJava 2) ✔ ✔ ✔ ✔ ✔ *.cache() ✔ ✘ ✔ Flowable (RxJava 2) ✔ ✔ ✔ ✔ ✔ *.cache() ✔ ✔ ✔ Flux ✔ ✔ ✔ ✔ ✔ *.cache() ✔ ✔ ✔ h>p://alexsderkach.io/comparing-java-8-rxjava-reactor/
  • 55. 55 Automa-c Op-miza-ons ‣ Macro-fusion - replacing 2+ subsequent operators with a single operator:
 
 1. map(A) = B
 2. map(B) = C ƒ(A) = D
 3. filter(C) = D
  • 56. 56 ‣ Macro-fusion - replacing 2+ subsequent operators with a single operator:
 
 1. map(A) = B
 2. map(B) = C ƒ(A) = D
 3. filter(C) = D ‣ Micro-fusion - operators that end in an output queue and operators star7ng with a front-queue could share the same Queue instance
 
 1. 0..100 = B
 2. map(B) = C [0..100] <-> map <-> groupBy <-> 🙄
 3. groupBy(C) = D Automa-c Op-miza-ons push queuequeue request(1) request(1) push request(1) push
  • 57. ‣ Macro-fusion - replacing 2+ subsequent operators with a single operator:
 
 1. map(A) = B
 2. map(B) = C ƒ(A) = D
 3. filter(C) = D ‣ Micro-fusion - operators that end in an output queue and operators star7ng with a front-queue could share the same Queue instance
 
 1. 0..100 = B
 2. map(B) = C [0..100] <- map <-> groupBy <- 🙄
 3. groupBy(C) = D 57 Automa-c Op-miza-ons poll queuequeue poll request(1) push
  • 58. 58 Flux against the world ‣ Stream, Op-onal, CompletableFuture - solve specific tasks ‣ Reac-ve Libraries are universal
  • 60.
  • 61. 61 ‣ Pipeline = steps of transforma-ons How do I test? #unit
  • 62. 62 How do I test? #unit 🛴 🏍 🚐 transforma-on #1 transforma-on #2 ‣ Pipeline = steps of transforma-ons
  • 63. 63 How do I test? #unit Input ExpectedTransformer 🛴 🏍 🚐 transforma-on #1 transforma-on #2 ‣ Pipeline = steps of transforma-ons
  • 64. 64 How do I test? #unit 🛴 🏍 🚐 transforma-on #1 transforma-on #2 ‣ Pipeline = steps of transforma-ons Input ExpectedTransformer
  • 65. @Test public void testEmojiSource() { Flux<String> source = emojiSource(); Iterable<String> values = source.toIterable(); assertEquals(asList("🙈", "🙉", "🙊"), values); } @Test public void testWelcomeSource() { Mono<String> source = welcomeSource(); String value = source.block(); assertEquals("Hello", value); } 65 How to verify expecta-ons? h>ps://projectreactor.io/docs/core/release/reference/docs/index.html#tes-ng 1 @Test public void testEmojiSource() { Flux<String> source = emojiSource(); StepVerifier.create(source) .expectNext("🙈", "🙉", "🙊") .as("expect 3 more") .expectNextCount(3) .thenAwait(Duration.ofSeconds(3)) .expectNextMatches(v -> v.startsWith("O_O")) .as("expect non empty batch") .thenConsumeWhile(v -> !v.isEmpty()) .expectNextCount(1) .verifyComplete(); } 2 3 1 2 3 convert to synchronous use StepVerifier 1 3 2 🏍
  • 66. 66 How to generate input?🛴 @Test public void testEmojiSource() { Flux<String> source = Flux.just("🙈", "🙉", "🙊"); Iterable<String> values = source.toIterable(); assertEquals(asList("🙈", "🙉", "🙊"), values); } @Test public void testWelcomeSource() { Mono<String> source = Mono.just("Hello"); String value = source.block(); assertEquals("Hello", value); }
  • 67. 67 How to generate input? Emit specific signals with TestPublisher<T> ‣ next(T…) will trigger 1..N onNext signals ‣ emit(T…) will do the same & complete ‣ complete() will terminate with onComplete signal ‣ error(Throwable) will terminate with an onError signal 🛴
  • 68. 68 How to get pre>y stack-trace? Ac-vate debug mode Hooks.onOperator(Hooks.OperatorHook::operatorStacktrace); Error has been observed by the following operator(s): |_ Flux.map(FakeRepository.java:27) |_ Flux.map(FakeRepository.java:28) |_ Flux.filter(FakeUtils1.java:29) |_ Flux.transform(GuideDebuggingExtraTests.java:41) |_ Flux.elapsed(FakeUtils2.java:30) |_ Flux.transform(GuideDebuggingExtraTests.java:42)
  • 69. 69 How do I test Couchbase? #integra-on without N1QL with N1QL OR
  • 70. 70 Future ‣ Flow API - Java 9 ‣ Non-blocking JDBC spec (Java 10?) ‣ More non-blocking Spring modules ‣ …
  • 71. Summary 71 ‣ K-V Storage - perfect for video games ‣ Design Non-Blocking by Default ‣ RxJava and Reactor are friends ‣ Spring unites everyone
  • 72. References 72 ‣ Why Couchbase chose RxJava
 hTps://goo.gl/dWeS35 ‣ Reac7ve Spring by Josh Long
 hTps://goo.gl/EXtJrB ‣ Developing Reac7ve applica7ons with Reac7ve Streams
 hTps://goo.gl/eeNaAh ‣ Spring Boot 2.0 change-log
 hTps://goo.gl/j8HFuY