SlideShare ist ein Scribd-Unternehmen logo
1 von 73
Downloaden Sie, um offline zu lesen
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?

Weitere ähnliche Inhalte

Was ist angesagt?

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
 

Was ist angesagt? (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?
 

Ähnlich wie 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
 

Ähnlich wie 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
 

Kürzlich hochgeladen

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
 
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
 
Advancing Engineering with AI through the Next Generation of Strategic Projec...
Advancing Engineering with AI through the Next Generation of Strategic Projec...Advancing Engineering with AI through the Next Generation of Strategic Projec...
Advancing Engineering with AI through the Next Generation of Strategic Projec...OnePlan Solutions
 
HR Software Buyers Guide in 2024 - HRSoftware.com
HR Software Buyers Guide in 2024 - HRSoftware.comHR Software Buyers Guide in 2024 - HRSoftware.com
HR Software Buyers Guide in 2024 - HRSoftware.comFatema Valibhai
 
Steps To Getting Up And Running Quickly With MyTimeClock Employee Scheduling ...
Steps To Getting Up And Running Quickly With MyTimeClock Employee Scheduling ...Steps To Getting Up And Running Quickly With MyTimeClock Employee Scheduling ...
Steps To Getting Up And Running Quickly With MyTimeClock Employee Scheduling ...MyIntelliSource, Inc.
 
Shapes for Sharing between Graph Data Spaces - and Epistemic Querying of RDF-...
Shapes for Sharing between Graph Data Spaces - and Epistemic Querying of RDF-...Shapes for Sharing between Graph Data Spaces - and Epistemic Querying of RDF-...
Shapes for Sharing between Graph Data Spaces - and Epistemic Querying of RDF-...Steffen Staab
 
Salesforce Certified Field Service Consultant
Salesforce Certified Field Service ConsultantSalesforce Certified Field Service Consultant
Salesforce Certified Field Service ConsultantAxelRicardoTrocheRiq
 
Hand gesture recognition PROJECT PPT.pptx
Hand gesture recognition PROJECT PPT.pptxHand gesture recognition PROJECT PPT.pptx
Hand gesture recognition PROJECT PPT.pptxbodapatigopi8531
 
Software Quality Assurance Interview Questions
Software Quality Assurance Interview QuestionsSoftware Quality Assurance Interview Questions
Software Quality Assurance Interview QuestionsArshad QA
 
(Genuine) Escort Service Lucknow | Starting ₹,5K To @25k with A/C 🧑🏽‍❤️‍🧑🏻 89...
(Genuine) Escort Service Lucknow | Starting ₹,5K To @25k with A/C 🧑🏽‍❤️‍🧑🏻 89...(Genuine) Escort Service Lucknow | Starting ₹,5K To @25k with A/C 🧑🏽‍❤️‍🧑🏻 89...
(Genuine) Escort Service Lucknow | Starting ₹,5K To @25k with A/C 🧑🏽‍❤️‍🧑🏻 89...gurkirankumar98700
 
call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️
call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️
call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️Delhi Call girls
 
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
 
Professional Resume Template for Software Developers
Professional Resume Template for Software DevelopersProfessional Resume Template for Software Developers
Professional Resume Template for Software DevelopersVinodh Ram
 
DNT_Corporate presentation know about us
DNT_Corporate presentation know about usDNT_Corporate presentation know about us
DNT_Corporate presentation know about usDynamic Netsoft
 
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
 
TECUNIQUE: Success Stories: IT Service provider
TECUNIQUE: Success Stories: IT Service providerTECUNIQUE: Success Stories: IT Service provider
TECUNIQUE: Success Stories: IT Service providermohitmore19
 
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
 

Kürzlich hochgeladen (20)

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
 
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
 
Microsoft AI Transformation Partner Playbook.pdf
Microsoft AI Transformation Partner Playbook.pdfMicrosoft AI Transformation Partner Playbook.pdf
Microsoft AI Transformation Partner Playbook.pdf
 
Advancing Engineering with AI through the Next Generation of Strategic Projec...
Advancing Engineering with AI through the Next Generation of Strategic Projec...Advancing Engineering with AI through the Next Generation of Strategic Projec...
Advancing Engineering with AI through the Next Generation of Strategic Projec...
 
HR Software Buyers Guide in 2024 - HRSoftware.com
HR Software Buyers Guide in 2024 - HRSoftware.comHR Software Buyers Guide in 2024 - HRSoftware.com
HR Software Buyers Guide in 2024 - HRSoftware.com
 
Exploring iOS App Development: Simplifying the Process
Exploring iOS App Development: Simplifying the ProcessExploring iOS App Development: Simplifying the Process
Exploring iOS App Development: Simplifying the Process
 
Steps To Getting Up And Running Quickly With MyTimeClock Employee Scheduling ...
Steps To Getting Up And Running Quickly With MyTimeClock Employee Scheduling ...Steps To Getting Up And Running Quickly With MyTimeClock Employee Scheduling ...
Steps To Getting Up And Running Quickly With MyTimeClock Employee Scheduling ...
 
Shapes for Sharing between Graph Data Spaces - and Epistemic Querying of RDF-...
Shapes for Sharing between Graph Data Spaces - and Epistemic Querying of RDF-...Shapes for Sharing between Graph Data Spaces - and Epistemic Querying of RDF-...
Shapes for Sharing between Graph Data Spaces - and Epistemic Querying of RDF-...
 
Salesforce Certified Field Service Consultant
Salesforce Certified Field Service ConsultantSalesforce Certified Field Service Consultant
Salesforce Certified Field Service Consultant
 
Call Girls In Mukherjee Nagar 📱 9999965857 🤩 Delhi 🫦 HOT AND SEXY VVIP 🍎 SE...
Call Girls In Mukherjee Nagar 📱  9999965857  🤩 Delhi 🫦 HOT AND SEXY VVIP 🍎 SE...Call Girls In Mukherjee Nagar 📱  9999965857  🤩 Delhi 🫦 HOT AND SEXY VVIP 🍎 SE...
Call Girls In Mukherjee Nagar 📱 9999965857 🤩 Delhi 🫦 HOT AND SEXY VVIP 🍎 SE...
 
Hand gesture recognition PROJECT PPT.pptx
Hand gesture recognition PROJECT PPT.pptxHand gesture recognition PROJECT PPT.pptx
Hand gesture recognition PROJECT PPT.pptx
 
Software Quality Assurance Interview Questions
Software Quality Assurance Interview QuestionsSoftware Quality Assurance Interview Questions
Software Quality Assurance Interview Questions
 
(Genuine) Escort Service Lucknow | Starting ₹,5K To @25k with A/C 🧑🏽‍❤️‍🧑🏻 89...
(Genuine) Escort Service Lucknow | Starting ₹,5K To @25k with A/C 🧑🏽‍❤️‍🧑🏻 89...(Genuine) Escort Service Lucknow | Starting ₹,5K To @25k with A/C 🧑🏽‍❤️‍🧑🏻 89...
(Genuine) Escort Service Lucknow | Starting ₹,5K To @25k with A/C 🧑🏽‍❤️‍🧑🏻 89...
 
call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️
call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️
call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️
 
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
 
Professional Resume Template for Software Developers
Professional Resume Template for Software DevelopersProfessional Resume Template for Software Developers
Professional Resume Template for Software Developers
 
DNT_Corporate presentation know about us
DNT_Corporate presentation know about usDNT_Corporate presentation know about us
DNT_Corporate presentation know about us
 
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...
 
TECUNIQUE: Success Stories: IT Service provider
TECUNIQUE: Success Stories: IT Service providerTECUNIQUE: Success Stories: IT Service provider
TECUNIQUE: Success Stories: IT Service provider
 
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 ☂️
 

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