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

Alfresco TTL#157 - Troubleshooting Made Easy: Deciphering Alfresco mTLS Confi...
Alfresco TTL#157 - Troubleshooting Made Easy: Deciphering Alfresco mTLS Confi...Alfresco TTL#157 - Troubleshooting Made Easy: Deciphering Alfresco mTLS Confi...
Alfresco TTL#157 - Troubleshooting Made Easy: Deciphering Alfresco mTLS Confi...Angel Borroy López
 
Ahmed Motair CV April 2024 (Senior SW Developer)
Ahmed Motair CV April 2024 (Senior SW Developer)Ahmed Motair CV April 2024 (Senior SW Developer)
Ahmed Motair CV April 2024 (Senior SW Developer)Ahmed Mater
 
Introduction Computer Science - Software Design.pdf
Introduction Computer Science - Software Design.pdfIntroduction Computer Science - Software Design.pdf
Introduction Computer Science - Software Design.pdfFerryKemperman
 
Taming Distributed Systems: Key Insights from Wix's Large-Scale Experience - ...
Taming Distributed Systems: Key Insights from Wix's Large-Scale Experience - ...Taming Distributed Systems: Key Insights from Wix's Large-Scale Experience - ...
Taming Distributed Systems: Key Insights from Wix's Large-Scale Experience - ...Natan Silnitsky
 
Balasore Best It Company|| Top 10 IT Company || Balasore Software company Odisha
Balasore Best It Company|| Top 10 IT Company || Balasore Software company OdishaBalasore Best It Company|| Top 10 IT Company || Balasore Software company Odisha
Balasore Best It Company|| Top 10 IT Company || Balasore Software company Odishasmiwainfosol
 
Software Project Health Check: Best Practices and Techniques for Your Product...
Software Project Health Check: Best Practices and Techniques for Your Product...Software Project Health Check: Best Practices and Techniques for Your Product...
Software Project Health Check: Best Practices and Techniques for Your Product...Velvetech LLC
 
Folding Cheat Sheet #4 - fourth in a series
Folding Cheat Sheet #4 - fourth in a seriesFolding Cheat Sheet #4 - fourth in a series
Folding Cheat Sheet #4 - fourth in a seriesPhilip Schwarz
 
Implementing Zero Trust strategy with Azure
Implementing Zero Trust strategy with AzureImplementing Zero Trust strategy with Azure
Implementing Zero Trust strategy with AzureDinusha Kumarasiri
 
Tech Tuesday - Mastering Time Management Unlock the Power of OnePlan's Timesh...
Tech Tuesday - Mastering Time Management Unlock the Power of OnePlan's Timesh...Tech Tuesday - Mastering Time Management Unlock the Power of OnePlan's Timesh...
Tech Tuesday - Mastering Time Management Unlock the Power of OnePlan's Timesh...OnePlan Solutions
 
Cyber security and its impact on E commerce
Cyber security and its impact on E commerceCyber security and its impact on E commerce
Cyber security and its impact on E commercemanigoyal112
 
Catch the Wave: SAP Event-Driven and Data Streaming for the Intelligence Ente...
Catch the Wave: SAP Event-Driven and Data Streaming for the Intelligence Ente...Catch the Wave: SAP Event-Driven and Data Streaming for the Intelligence Ente...
Catch the Wave: SAP Event-Driven and Data Streaming for the Intelligence Ente...confluent
 
CRM Contender Series: HubSpot vs. Salesforce
CRM Contender Series: HubSpot vs. SalesforceCRM Contender Series: HubSpot vs. Salesforce
CRM Contender Series: HubSpot vs. SalesforceBrainSell Technologies
 
SpotFlow: Tracking Method Calls and States at Runtime
SpotFlow: Tracking Method Calls and States at RuntimeSpotFlow: Tracking Method Calls and States at Runtime
SpotFlow: Tracking Method Calls and States at Runtimeandrehoraa
 
Maximizing Efficiency and Profitability with OnePlan’s Professional Service A...
Maximizing Efficiency and Profitability with OnePlan’s Professional Service A...Maximizing Efficiency and Profitability with OnePlan’s Professional Service A...
Maximizing Efficiency and Profitability with OnePlan’s Professional Service A...OnePlan Solutions
 
Cloud Data Center Network Construction - IEEE
Cloud Data Center Network Construction - IEEECloud Data Center Network Construction - IEEE
Cloud Data Center Network Construction - IEEEVICTOR MAESTRE RAMIREZ
 
What is Advanced Excel and what are some best practices for designing and cre...
What is Advanced Excel and what are some best practices for designing and cre...What is Advanced Excel and what are some best practices for designing and cre...
What is Advanced Excel and what are some best practices for designing and cre...Technogeeks
 
React Server Component in Next.js by Hanief Utama
React Server Component in Next.js by Hanief UtamaReact Server Component in Next.js by Hanief Utama
React Server Component in Next.js by Hanief UtamaHanief Utama
 
Unveiling Design Patterns: A Visual Guide with UML Diagrams
Unveiling Design Patterns: A Visual Guide with UML DiagramsUnveiling Design Patterns: A Visual Guide with UML Diagrams
Unveiling Design Patterns: A Visual Guide with UML DiagramsAhmed Mohamed
 

Kürzlich hochgeladen (20)

Alfresco TTL#157 - Troubleshooting Made Easy: Deciphering Alfresco mTLS Confi...
Alfresco TTL#157 - Troubleshooting Made Easy: Deciphering Alfresco mTLS Confi...Alfresco TTL#157 - Troubleshooting Made Easy: Deciphering Alfresco mTLS Confi...
Alfresco TTL#157 - Troubleshooting Made Easy: Deciphering Alfresco mTLS Confi...
 
Ahmed Motair CV April 2024 (Senior SW Developer)
Ahmed Motair CV April 2024 (Senior SW Developer)Ahmed Motair CV April 2024 (Senior SW Developer)
Ahmed Motair CV April 2024 (Senior SW Developer)
 
Introduction Computer Science - Software Design.pdf
Introduction Computer Science - Software Design.pdfIntroduction Computer Science - Software Design.pdf
Introduction Computer Science - Software Design.pdf
 
Taming Distributed Systems: Key Insights from Wix's Large-Scale Experience - ...
Taming Distributed Systems: Key Insights from Wix's Large-Scale Experience - ...Taming Distributed Systems: Key Insights from Wix's Large-Scale Experience - ...
Taming Distributed Systems: Key Insights from Wix's Large-Scale Experience - ...
 
Balasore Best It Company|| Top 10 IT Company || Balasore Software company Odisha
Balasore Best It Company|| Top 10 IT Company || Balasore Software company OdishaBalasore Best It Company|| Top 10 IT Company || Balasore Software company Odisha
Balasore Best It Company|| Top 10 IT Company || Balasore Software company Odisha
 
Software Project Health Check: Best Practices and Techniques for Your Product...
Software Project Health Check: Best Practices and Techniques for Your Product...Software Project Health Check: Best Practices and Techniques for Your Product...
Software Project Health Check: Best Practices and Techniques for Your Product...
 
Folding Cheat Sheet #4 - fourth in a series
Folding Cheat Sheet #4 - fourth in a seriesFolding Cheat Sheet #4 - fourth in a series
Folding Cheat Sheet #4 - fourth in a series
 
Hot Sexy call girls in Patel Nagar🔝 9953056974 🔝 escort Service
Hot Sexy call girls in Patel Nagar🔝 9953056974 🔝 escort ServiceHot Sexy call girls in Patel Nagar🔝 9953056974 🔝 escort Service
Hot Sexy call girls in Patel Nagar🔝 9953056974 🔝 escort Service
 
Implementing Zero Trust strategy with Azure
Implementing Zero Trust strategy with AzureImplementing Zero Trust strategy with Azure
Implementing Zero Trust strategy with Azure
 
Advantages of Odoo ERP 17 for Your Business
Advantages of Odoo ERP 17 for Your BusinessAdvantages of Odoo ERP 17 for Your Business
Advantages of Odoo ERP 17 for Your Business
 
Tech Tuesday - Mastering Time Management Unlock the Power of OnePlan's Timesh...
Tech Tuesday - Mastering Time Management Unlock the Power of OnePlan's Timesh...Tech Tuesday - Mastering Time Management Unlock the Power of OnePlan's Timesh...
Tech Tuesday - Mastering Time Management Unlock the Power of OnePlan's Timesh...
 
Cyber security and its impact on E commerce
Cyber security and its impact on E commerceCyber security and its impact on E commerce
Cyber security and its impact on E commerce
 
Catch the Wave: SAP Event-Driven and Data Streaming for the Intelligence Ente...
Catch the Wave: SAP Event-Driven and Data Streaming for the Intelligence Ente...Catch the Wave: SAP Event-Driven and Data Streaming for the Intelligence Ente...
Catch the Wave: SAP Event-Driven and Data Streaming for the Intelligence Ente...
 
CRM Contender Series: HubSpot vs. Salesforce
CRM Contender Series: HubSpot vs. SalesforceCRM Contender Series: HubSpot vs. Salesforce
CRM Contender Series: HubSpot vs. Salesforce
 
SpotFlow: Tracking Method Calls and States at Runtime
SpotFlow: Tracking Method Calls and States at RuntimeSpotFlow: Tracking Method Calls and States at Runtime
SpotFlow: Tracking Method Calls and States at Runtime
 
Maximizing Efficiency and Profitability with OnePlan’s Professional Service A...
Maximizing Efficiency and Profitability with OnePlan’s Professional Service A...Maximizing Efficiency and Profitability with OnePlan’s Professional Service A...
Maximizing Efficiency and Profitability with OnePlan’s Professional Service A...
 
Cloud Data Center Network Construction - IEEE
Cloud Data Center Network Construction - IEEECloud Data Center Network Construction - IEEE
Cloud Data Center Network Construction - IEEE
 
What is Advanced Excel and what are some best practices for designing and cre...
What is Advanced Excel and what are some best practices for designing and cre...What is Advanced Excel and what are some best practices for designing and cre...
What is Advanced Excel and what are some best practices for designing and cre...
 
React Server Component in Next.js by Hanief Utama
React Server Component in Next.js by Hanief UtamaReact Server Component in Next.js by Hanief Utama
React Server Component in Next.js by Hanief Utama
 
Unveiling Design Patterns: A Visual Guide with UML Diagrams
Unveiling Design Patterns: A Visual Guide with UML DiagramsUnveiling Design Patterns: A Visual Guide with UML Diagrams
Unveiling Design Patterns: A Visual Guide with UML Diagrams
 

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