SlideShare a Scribd company logo
The Value Of Reactive
Stephane Maldini - Reactive Engineering @ Pivotal
@smaldini
The Value Of Reactive
What is it ? Where is the value ?
3
No, I do not have a medium blog
=+
@smaldini
Reactive
Programming
● The next frontier for high-efficiency applications
● Non-blocking and allows for concurrent executions
● Often associated with functional programming
● Have no opinion on async and many flows are totally
synchronous
● Resilient with graceful error handling and interruptions
(producer or consumer related)
😴
5
You
A reactive API primer
6
@GetMapping("/health")
public Mono<Health> compositeHealth() {
return Mono.zip(
webClient.get()
.uri(“https://alpha-service/health")
.retrieve()
.bodyToMono(Health.class),
webClient.get()
.uri("https://bravo-service/health")
.retrieve()
.bodyToMono(Health.class),
(alpha, bravo) -> composite(alpha, bravo))
.switchIfEmpty(emptyComposite());
}
Is declarative style too disruptive
to scale across dev teams ?
7
Debugging Reactive flows
8
java.lang.RuntimeException: Am I looking like a nice stacktrace friends ?
at io.spring.workshop.tradingservice.TradingCompanyClient.lambda$getTradingCompany$0(TradingCompanyClient.java:38) ~[classes/:na]
at reactor.core.publisher.FluxPeekFuseable$PeekFuseableSubscriber.onNext(FluxPeekFuseable.java:190) ~[reactor-core-3.3.0]
at reactor.core.publisher.Operators$MonoSubscriber.complete(Operators.java:1575) ~[reactor-core-3.3.0]
at reactor.core.publisher.MonoFlatMap$FlatMapInner.onNext(MonoFlatMap.java:241) ~[reactor-core-3.3.0]
at reactor.core.publisher.FluxOnAssembly$OnAssemblySubscriber.onNext(FluxOnAssembly.java:349) ~[reactor-core-3.3.0]
at reactor.core.publisher.FluxMapFuseable$MapFuseableSubscriber.onNext(FluxMapFuseable.java:121) ~[reactor-core-3.3.0]
at reactor.core.publisher.FluxContextStart$ContextStartSubscriber.onNext(FluxContextStart.java:103) ~[reactor-core-3.3.0]
at reactor.core.publisher.FluxMapFuseable$MapFuseableConditionalSubscriber.onNext(FluxMapFuseable.java:287) ~[reactor-core-3.3.0]
at reactor.core.publisher.FluxFilterFuseable$FilterFuseableConditionalSubscriber.onNext(FluxFilterFuseable.java:331) ~[reactor-core-3.3.0]
at reactor.core.publisher.Operators$MonoSubscriber.complete(Operators.java:1575) ~[reactor-core-3.3.0]
at reactor.core.publisher.MonoCollectList$MonoCollectListSubscriber.onComplete(MonoCollectList.java:121) ~[reactor-core-3.3.0]
at reactor.core.publisher.FluxMap$MapSubscriber.onComplete(FluxMap.java:136) ~[reactor-core-3.3.0]
at reactor.core.publisher.FluxPeek$PeekSubscriber.onComplete(FluxPeek.java:252) ~[reactor-core-3.3.0]
at reactor.core.publisher.FluxPeek$PeekSubscriber.onComplete(FluxPeek.java:252) ~[reactor-core-3.3.0]
at reactor.core.publisher.FluxMap$MapSubscriber.onComplete(FluxMap.java:136) ~[reactor-core-3.3.0]
at reactor.netty.channel.FluxReceive.terminateReceiver(FluxReceive.java:391) ~[reactor-netty-0.9.0]
at reactor.netty.channel.FluxReceive.drainReceiver(FluxReceive.java:197) ~[reactor-netty-0.9.0]
at reactor.netty.channel.FluxReceive.onInboundComplete(FluxReceive.java:338) ~[reactor-netty-0.9.0]
at reactor.netty.channel.ChannelOperations.onInboundComplete(ChannelOperations.java:350) ~[reactor-netty-0.9.0]
at reactor.netty.channel.ChannelOperations.terminate(ChannelOperations.java:399) ~[reactor-netty-0.9.0]
at reactor.netty.http.client.HttpClientOperations.onInboundNext(HttpClientOperations.java:555) ~[reactor-netty-0.9.0]
…
Debugging Reactive flows
9
java.lang.RuntimeException: Am I looking like a nice stacktrace friends ?
at io.spring.workshop.tradingservice.TradingCompanyClient.lambda$getTradingCompany$0(TradingCompanyClient.java:38) ~[classes/:na]
at reactor.core.publisher.FluxPeekFuseable$PeekFuseableSubscriber.onNext(FluxPeekFuseable.java:190) ~[reactor-core-3.3.0]
at reactor.core.publisher.Operators$MonoSubscriber.complete(Operators.java:1575) ~[reactor-core-3.3.0]
at reactor.core.publisher.MonoFlatMap$FlatMapInner.onNext(MonoFlatMap.java:241) ~[reactor-core-3.3.0]
at reactor.core.publisher.FluxOnAssembly$OnAssemblySubscriber.onNext(FluxOnAssembly.java:349) ~[reactor-core-3.3.0]
at reactor.core.publisher.FluxMapFuseable$MapFuseableSubscriber.onNext(FluxMapFuseable.java:121) ~[reactor-core-3.3.0]
at reactor.core.publisher.FluxContextStart$ContextStartSubscriber.onNext(FluxContextStart.java:103) ~[reactor-core-3.3.0]
at reactor.core.publisher.FluxMapFuseable$MapFuseableConditionalSubscriber.onNext(FluxMapFuseable.java:287) ~[reactor-core-3.3.0]
at reactor.core.publisher.FluxFilterFuseable$FilterFuseableConditionalSubscriber.onNext(FluxFilterFuseable.java:331) ~[reactor-core-3.3.0]
at reactor.core.publisher.Operators$MonoSubscriber.complete(Operators.java:1575) ~[reactor-core-3.3.0]
at reactor.core.publisher.MonoCollectList$MonoCollectListSubscriber.onComplete(MonoCollectList.java:121) ~[reactor-core-3.3.0]
at reactor.core.publisher.FluxMap$MapSubscriber.onComplete(FluxMap.java:136) ~[reactor-core-3.3.0]
at reactor.core.publisher.FluxPeek$PeekSubscriber.onComplete(FluxPeek.java:252) ~[reactor-core-3.3.0]
at reactor.core.publisher.FluxPeek$PeekSubscriber.onComplete(FluxPeek.java:252) ~[reactor-core-3.3.0]
at reactor.core.publisher.FluxMap$MapSubscriber.onComplete(FluxMap.java:136) ~[reactor-core-3.3.0]
at reactor.netty.channel.FluxReceive.terminateReceiver(FluxReceive.java:391) ~[reactor-netty-0.9.0]
at reactor.netty.channel.FluxReceive.drainReceiver(FluxReceive.java:197) ~[reactor-netty-0.9.0]
at reactor.netty.channel.FluxReceive.onInboundComplete(FluxReceive.java:338) ~[reactor-netty-0.9.0]
at reactor.netty.channel.ChannelOperations.onInboundComplete(ChannelOperations.java:350) ~[reactor-netty-0.9.0]
at reactor.netty.channel.ChannelOperations.terminate(ChannelOperations.java:399) ~[reactor-netty-0.9.0]
at reactor.netty.http.client.HttpClientOperations.onInboundNext(HttpClientOperations.java:555) ~[reactor-netty-0.9.0]
…
You ?
Using blocking code in reactive callbacks
10
TradingCompany tradingCompany = this.restTemplate.exchange(
get("http://localhost:8082/details/{ticker}", ticker),
TradingCompany.class)
.getBody();
Using blocking code in reactive callbacks
11
someMono.doOnSuccess(data -> {
TradingCompany tradingCompany = this.restTemplate.exchange(
get("http://localhost:8082/details/{ticker}", ticker),
TradingCompany.class)
.getBody();
return tradingCompany;
});
💩
What are you priorities ?
12
What are you priorities ?
13
Time To Market / Dev Productivity
What are you priorities ?
14
Time To Market / Dev Productivity
Day 2 Operations / Observability
What are you priorities ?
15
Time To Market / Dev Productivity
Day 2 Operations / Observability
[…]
What are you priorities ?
16
Time To Market / Dev Productivity
Day 2 Operations / Observability
Running costs / efficiency
[…]
What are you priorities ?
17
Time To Market / Dev Productivity
Day 2 Operations / Observability
Reactive ?Running costs / efficiency
[…]
Give me
18
Reasons
To use this stuff
19
Order(s) of Magnitude 

more efficient
🤑
• Lower Number of processes/threads used by instance
• Lower Memory Pressure and associated costs (Garbage collectors)
• Lower Hardware specification requirements
• Lower Startup time
20
Order(s) of Magnitude 

more efficient
Show me some numbers
21
Order(s) of Magnitude 

more efficient
22
Order(s) of Magnitude 

more efficient
Spring WebFlux.Fn - Reactor Netty - 4 threads
&
Spring MVC - Tomcat - 200 threads
With a simple hello world String rendering
128 / steps up to 4000 20s 20min
23
Order(s) of Magnitude 

more efficient
24
Order(s) of Magnitude 

more efficient MVCWebFlux
25
Order(s) of Magnitude 

more efficient
😎
🤒
26
Order(s) of Magnitude 

more efficient
Moar Old Gen
Moar Young Gen
27
Order(s) of Magnitude 

more efficient
28
Order(s) of Magnitude 

more efficient
x2
29
Order(s) of Magnitude 

more efficient
😎 ⏰
30
Designed for 

connection volume scalability
📱Order(s) of Magnitude 

more efficient
• Lower Number of instances running a same application
• Lower Impact from traffic latency diversity
• Lower Impact from persistent http traffic (websocket, sse, http2…)
31
Designed for 

connection volume scalability
32
Spring WebFlux.Fn - Reactor Netty - 4 threads
&
Spring MVC - Tomcat - 200 threads
With a 100ms delayed hello world String rendering
128 / steps up to 4000 20s 20min
Designed for 

connection volume scalability
Designed for 

connection volume scalability
33
MVC (async)WebFlux
Designed for 

connection volume scalability
34🤢
35
Designed for 

connection volume scalability
36
x4
Designed for 

connection volume scalability
37
⏰⏰
Designed for 

connection volume scalability
How does the response delay impact each model ?
38
Designed for 

connection volume scalability
39
Designed for 

connection volume scalability
WebFlux WebFlux (with response delay)
WebFlux WebFlux (with response delay)
40
Designed for 

connection volume scalability
WebFlux WebFlux (with response delay)
41
Designed for 

connection volume scalability
No major impact from backend delays
42
Designed for 

connection volume scalability
WebMVC (with response delay)WebMVC
43
Designed for 

connection volume scalability
WebMVC (with response delay)WebMVC
Rapidly degrading running conditions
44
Designed for 

connection volume scalability
WebMVC WebMVC (with response delay)
45
Designed for 

connection volume scalability
WebMVC WebMVC (with response delay)
x4 slower due to backend delays
46
Designed for 

connection volume scalability
📱Order(s) of Magnitude 

more efficient
47
Sleep Well,

get less paged
📟
Order(s) of Magnitude 

more efficient Designed for 

connection volume scalability
Sleep Well,

get less paged
• Greater resilience to runtime errors, including memory issues
• Greater availability at any point in time, specially under stress
• Easier resources use modeling
48
Sleep Well,

get less paged
49
Figure 1.a: 

A blocking JVM HTTP server with no flow control
Sleep Well,

get less paged
Reactive IO allows reading when application capacity permits
50
Sleep Well,

get less paged
Reactive IO only writes back application data when client capacity permits
51
52
WebFlux WebFlux (with response delay)
Sleep Well,

get less paged
53
WebFlux WebFlux (with response delay)
Very similar resources use profile
Sleep Well,

get less paged
Sleep Well,

get less paged
54
Can reactive programming help with JVM OutOfMemory
exceptions caused by incoming request traffic ?
Sleep Well,

get less paged
• Yes, using a reactive IO runtime, request body overflow is isolated
• A Connection Read causing an OutOfMemory will be rejected
55
Sleep Well,

get less paged
• Yes, using a reactive IO runtime, request body overflow is isolated
• A Connection Read causing an OutOfMemory will be rejected
• With a blocking IO runtime, request body overflow will be fatal
• The entire application will crash or be in unrecoverable state
56
57
Sleep Well,

get less paged
Order(s) of Magnitude 

more efficient
Designed for 

connection volume scalability
58
Sleep Well,

get less paged
Order(s) of Magnitude 

more efficient
Designed for 

connection volume scalability
Event-Driven
Less Threads - Memory
Start quicker
Improve Latency*
Unlocks hyper concurrency
Connected Experience
Slow/Fast traffic
Near-Always Available
Flow Control
Predictable load
Resilient
59
What do you do with these
qualities ?
🤓
60
Write Any Microservice
Resilient
Smaller resources footprint
Remote calls parallelization
Hedge Clients
61
Write Any Microservice
Resilient
Smaller resources footprint
Remote calls parallelization
Hedge Clients
62
Remote calls parallelization
With Spring, you can start writing your app with WebMVC,
introduce WebClient to improve backend calls workflows,
then consider moving to WebFlux
63
Write an Edge API
Available
Traffic Control
Volume of Connections
64
Write an Edge API
Available
Traffic Control
Volume of Connections
65
Traffic Control
A reactive runtime will isolate ingress/egress traffic latency
and exceptions.
Given this isolation property, a reactive Edge API should
always be able to route traffic, even limit it or short-circuit
when required.
66
Mobile Backend
Scale with different traffic latency
Connected experience (notifications…)
Volume of clients
67
Mobile IoT Backend
Scale with different traffic latency
Connected experience (notifications…)
Volume of clients
Ok sounds cool, but what about the
developer experience ?
68
😷
69
Error has been observed at the following site(s):
|_ checkpoint ⇢ Handler io.spring.workshop.tradingservice.QuotesController#quotesDetails(String) [DispatcherHandler]
|_ checkpoint ⇢ org.springframework.security.web.server.authorization.AuthorizationWebFilter [DefaultWebFilterChain]
|_ checkpoint ⇢ org.springframework.security.web.server.authorization.ExceptionTranslationWebFilter [DefaultWebFilterChain]
|_ checkpoint ⇢ org.springframework.security.web.server.authentication.logout.LogoutWebFilter [DefaultWebFilterChain]
|_ checkpoint ⇢ org.springframework.security.web.server.savedrequest.ServerRequestCacheWebFilter [DefaultWebFilterChain]
|_ checkpoint ⇢ org.springframework.security.web.server.context.SecurityContextServerWebExchangeWebFilter [DefaultWebFilterChain]
|_ checkpoint ⇢ org.springframework.security.web.server.ui.LogoutPageGeneratingWebFilter [DefaultWebFilterChain]
|_ checkpoint ⇢ org.springframework.security.web.server.ui.LoginPageGeneratingWebFilter [DefaultWebFilterChain]
|_ checkpoint ⇢ org.springframework.security.web.server.authentication.AuthenticationWebFilter [DefaultWebFilterChain]
|_ checkpoint ⇢ org.springframework.security.web.server.authentication.AuthenticationWebFilter [DefaultWebFilterChain]
|_ checkpoint ⇢ org.springframework.security.web.server.context.ReactorContextWebFilter [DefaultWebFilterChain]
|_ checkpoint ⇢ org.springframework.security.web.server.csrf.CsrfWebFilter [DefaultWebFilterChain]
|_ checkpoint ⇢ org.springframework.security.web.server.header.HttpHeaderWriterWebFilter [DefaultWebFilterChain]
|_ checkpoint ⇢ org.springframework.security.config.web.server.ServerHttpSecurity$ServerWebExchangeReactorContextWebFilter [DefaultWebFilterChain]
|_ checkpoint ⇢ org.springframework.security.web.server.WebFilterChainProxy [DefaultWebFilterChain]
|_ checkpoint ⇢ org.springframework.boot.web.reactive.filter.OrderedHiddenHttpMethodFilter [DefaultWebFilterChain]
|_ checkpoint ⇢ org.springframework.boot.actuate.metrics.web.reactive.server.MetricsWebFilter [DefaultWebFilterChain]
|_ checkpoint ⇢ HTTP GET "/quotes/summary/MSFT" [ExceptionHandlingWebHandler]
Exceptions since Spring Framework 5.2
Actionable stacktraces
70
Error has been observed at the following site(s):
|_ Mono.doOnNext ⇢ at io.spring.workshop.tradingservice.TradingCompanyClient.getTradingCompany(TradingCompanyClient.java:38)
|_ Mono.switchIfEmpty ⇢ at io.spring.workshop.tradingservice.TradingCompanyClient.getTradingCompany(TradingCompanyClient.java:39)
|_ Mono.zipWith ⇢ at io.spring.workshop.tradingservice.QuotesController.quotesDetails(QuotesController.java:39)
|_ Mono.switchIfEmpty ⇢ at org.springframework.http.codec.EncoderHttpMessageWriter.write(EncoderHttpMessageWriter.java:119)
|_ Mono.flatMap ⇢ at org.springframework.http.codec.EncoderHttpMessageWriter.write(EncoderHttpMessageWriter.java:123)
|_ checkpoint ⇢ Handler io.spring.workshop.tradingservice.QuotesController#quotesDetails(String) [DispatcherHandler]
|_ Mono.flatMap ⇢ at org.springframework.web.reactive.DispatcherHandler.lambda$handleResult$5(DispatcherHandler.java:172)
|_ Mono.onErrorResume ⇢ at org.springframework.web.reactive.DispatcherHandler.handleResult(DispatcherHandler.java:171)
|_ Mono.flatMap ⇢ at org.springframework.web.reactive.DispatcherHandler.handle(DispatcherHandler.java:147)
|_ Mono.defer ⇢ at org.springframework.web.server.handler.DefaultWebFilterChain.filter(DefaultWebFilterChain.java:119)
|_ Mono.defer ⇢ at org.springframework.web.server.handler.DefaultWebFilterChain.filter(DefaultWebFilterChain.java:119)
|_ Mono.switchIfEmpty ⇢ at org.springframework.security.web.server.authorization.AuthorizationWebFilter.filter(AuthorizationWebFilter.java:46)
|_ checkpoint ⇢ org.springframework.security.web.server.authorization.AuthorizationWebFilter [DefaultWebFilterChain]
|_ Mono.defer ⇢ at org.springframework.web.server.handler.DefaultWebFilterChain.filter(DefaultWebFilterChain.java:119)
|_ FluxMap$MapSubscriber.onComplete ⇢ at reactor.netty.channel.FluxReceive.terminateReceiver(FluxReceive.java:391)
Exceptions with debug mode enabled
71
Error has been observed at the following site(s):
|_ Mono.doOnNext ⇢ at io.spring.workshop.tradingservice.TradingCompanyClient.getTradingCompany(TradingCompanyClient.java:38)
|_ Mono.switchIfEmpty ⇢ at io.spring.workshop.tradingservice.TradingCompanyClient.getTradingCompany(TradingCompanyClient.java:39)
|_ Mono.zipWith ⇢ at io.spring.workshop.tradingservice.QuotesController.quotesDetails(QuotesController.java:39)
|_ Mono.switchIfEmpty ⇢ at org.springframework.http.codec.EncoderHttpMessageWriter.write(EncoderHttpMessageWriter.java:119)
|_ Mono.flatMap ⇢ at org.springframework.http.codec.EncoderHttpMessageWriter.write(EncoderHttpMessageWriter.java:123)
|_ checkpoint ⇢ Handler io.spring.workshop.tradingservice.QuotesController#quotesDetails(String) [DispatcherHandler]
|_ Mono.flatMap ⇢ at org.springframework.web.reactive.DispatcherHandler.lambda$handleResult$5(DispatcherHandler.java:172)
|_ Mono.onErrorResume ⇢ at org.springframework.web.reactive.DispatcherHandler.handleResult(DispatcherHandler.java:171)
|_ Mono.flatMap ⇢ at org.springframework.web.reactive.DispatcherHandler.handle(DispatcherHandler.java:147)
|_ Mono.defer ⇢ at org.springframework.web.server.handler.DefaultWebFilterChain.filter(DefaultWebFilterChain.java:119)
|_ Mono.defer ⇢ at org.springframework.web.server.handler.DefaultWebFilterChain.filter(DefaultWebFilterChain.java:119)
|_ Mono.switchIfEmpty ⇢ at org.springframework.security.web.server.authorization.AuthorizationWebFilter.filter(AuthorizationWebFilter.java:46)
|_ checkpoint ⇢ org.springframework.security.web.server.authorization.AuthorizationWebFilter [DefaultWebFilterChain]
|_ Mono.defer ⇢ at org.springframework.web.server.handler.DefaultWebFilterChain.filter(DefaultWebFilterChain.java:119)
|_ FluxMap$MapSubscriber.onComplete ⇢ at reactor.netty.channel.FluxReceive.terminateReceiver(FluxReceive.java:391)
Exceptions with debug mode enabled
Reactive Developer productivity
72
Soon coming as a jvm agent
Mobile Backend
Scale even with different traffic latency
Connected experience (notifications…)
Volume of clients
73
Soon coming as a jvm agent
Mobile Backend
Scale even with different traffic latency
Connected experience (notifications…)
Volume of clients
Speaking of which…
74
BlockHound !
Mobile Backend
Scale even with different traffic latency
Connected experience (notifications…)
Volume of clients
https://github.com/reactor/BlockHound
Detecting blocking code in reactive stack
75
BlockHound.install();
someMono.doOnSuccess(data -> {
TradingCompany tradingCompany = this.restTemplate.exchange(
get("http://localhost:8082/details/{ticker}", ticker),
TradingCompany.class)
.getBody();
return tradingCompany;
});
Detecting blocking code in reactive stack
76
BlockHound.install();
someMono.doOnSuccess(data -> {
TradingCompany tradingCompany = this.restTemplate.exchange(
get("http://localhost:8082/details/{ticker}", ticker),
TradingCompany.class)
.getBody();
return tradingCompany;
});
java.lang.Error:	Blocking	call!	java.net.Socket#connect	
	 at	reactor.blockhound.BlockHound$Builder.lambda$new$0(BlockHound.java:154)	
~[blockhound-1.0.0.jar:na]	
	 at	reactor.blockhound.BlockHound$Builder.lambda$install$8(BlockHound.java:254)	
~[blockhound-1.0.0.jar:na]	
	 at	reactor.blockhound.BlockHoundRuntime.checkBlocking(BlockHoundRuntime.java:43)	
~[blockhound-1.0.0.jar:na]	
	 at	java.net.Socket.connect(Socket.java)	~[na:1.8.0_144]	
	 at	sun.net.NetworkClient.doConnect(NetworkClient.java:180)	~[na:1.8.0_144]	
	 at	sun.net.www.http.HttpClient.openServer(HttpClient.java:463)	~[na:1.8.0_144]	
	 at	sun.net.www.http.HttpClient.openServer(HttpClient.java:558)	~[na:1.8.0_144]	
	 at	sun.net.www.http.HttpClient.<init>(HttpClient.java:242)	~[na:1.8.0_144]	
	 at	sun.net.www.http.HttpClient.New(HttpClient.java:339)	~[na:1.8.0_144]	
	 at	sun.net.www.http.HttpClient.New(HttpClient.java:357)	~[na:1.8.0_144]
Quickly detect during pre-production
workflows that will likely degrade your
reactive stack experience
More reactive microservices ?
77
🤗
~80% of apps generated by start.spring.io are using a SQL driver
78
~80% of apps generated by start.spring.io are using a SQL driver
79
r2dbc.io
What should I look after I successfully have written my first Reactive apps ?
80
Monitoring with Micrometer
81
micrometer.io
82
Networking with RSocket
rsocket.io
83
Having fun developing with Kotlin
kotlinlang.org
So In Conclusion
84
What are you priorities ?
85
Time To Market / Dev Productivity
Day 2 Operations / Observability
Running costs / efficiency
[…]
With Reactive
You can actually be more productive in
writing state of the art, scalable
microservices
What are you priorities ?
86
Time To Market / Dev Productivity
Day 2 Operations / Observability
Running costs / efficiency
[…]
With Reactive
Your Applications are designed to be
resilient under stress and lower
maintenance
What are you priorities ?
87
Time To Market / Dev Productivity
Day 2 Operations / Observability
Running costs / efficiency
[…]
With Reactive
You run more for less
What are you priorities ?
88
Time To Market / Dev Productivity
Day 2 Operations / Observability
Running costs / efficiency
[…]
89
Establish the right project to experiment
Reactive Programming with
90
Do it progressively, migrate a few dedicated
backend routes then an entire application
You can already parallelize some workloads
even on your blocking stack
91
92
Use all the developers tools you can to
accelerate your reactive adoption and
build trust
93
Once the cost of learning has been paid
and the benefits realized- it’s usually
difficult to come back to blocking solutions.
94
In fact it’s difficult in today’s world of
distributed systems to not find a reason
for giving a go to any Reactive stack.
95
In fact it’s difficult in today’s world of
distributed systems to not find a reason
for giving a go to any Reactive stack.
It’s just designed for them
THANK YOU
@smaldini
smaldini

More Related Content

The Value of Reactive

  • 1. The Value Of Reactive Stephane Maldini - Reactive Engineering @ Pivotal @smaldini
  • 2. The Value Of Reactive What is it ? Where is the value ?
  • 3. 3 No, I do not have a medium blog =+ @smaldini
  • 4. Reactive Programming ● The next frontier for high-efficiency applications ● Non-blocking and allows for concurrent executions ● Often associated with functional programming ● Have no opinion on async and many flows are totally synchronous ● Resilient with graceful error handling and interruptions (producer or consumer related) 😴
  • 6. A reactive API primer 6 @GetMapping("/health") public Mono<Health> compositeHealth() { return Mono.zip( webClient.get() .uri(“https://alpha-service/health") .retrieve() .bodyToMono(Health.class), webClient.get() .uri("https://bravo-service/health") .retrieve() .bodyToMono(Health.class), (alpha, bravo) -> composite(alpha, bravo)) .switchIfEmpty(emptyComposite()); }
  • 7. Is declarative style too disruptive to scale across dev teams ? 7
  • 8. Debugging Reactive flows 8 java.lang.RuntimeException: Am I looking like a nice stacktrace friends ? at io.spring.workshop.tradingservice.TradingCompanyClient.lambda$getTradingCompany$0(TradingCompanyClient.java:38) ~[classes/:na] at reactor.core.publisher.FluxPeekFuseable$PeekFuseableSubscriber.onNext(FluxPeekFuseable.java:190) ~[reactor-core-3.3.0] at reactor.core.publisher.Operators$MonoSubscriber.complete(Operators.java:1575) ~[reactor-core-3.3.0] at reactor.core.publisher.MonoFlatMap$FlatMapInner.onNext(MonoFlatMap.java:241) ~[reactor-core-3.3.0] at reactor.core.publisher.FluxOnAssembly$OnAssemblySubscriber.onNext(FluxOnAssembly.java:349) ~[reactor-core-3.3.0] at reactor.core.publisher.FluxMapFuseable$MapFuseableSubscriber.onNext(FluxMapFuseable.java:121) ~[reactor-core-3.3.0] at reactor.core.publisher.FluxContextStart$ContextStartSubscriber.onNext(FluxContextStart.java:103) ~[reactor-core-3.3.0] at reactor.core.publisher.FluxMapFuseable$MapFuseableConditionalSubscriber.onNext(FluxMapFuseable.java:287) ~[reactor-core-3.3.0] at reactor.core.publisher.FluxFilterFuseable$FilterFuseableConditionalSubscriber.onNext(FluxFilterFuseable.java:331) ~[reactor-core-3.3.0] at reactor.core.publisher.Operators$MonoSubscriber.complete(Operators.java:1575) ~[reactor-core-3.3.0] at reactor.core.publisher.MonoCollectList$MonoCollectListSubscriber.onComplete(MonoCollectList.java:121) ~[reactor-core-3.3.0] at reactor.core.publisher.FluxMap$MapSubscriber.onComplete(FluxMap.java:136) ~[reactor-core-3.3.0] at reactor.core.publisher.FluxPeek$PeekSubscriber.onComplete(FluxPeek.java:252) ~[reactor-core-3.3.0] at reactor.core.publisher.FluxPeek$PeekSubscriber.onComplete(FluxPeek.java:252) ~[reactor-core-3.3.0] at reactor.core.publisher.FluxMap$MapSubscriber.onComplete(FluxMap.java:136) ~[reactor-core-3.3.0] at reactor.netty.channel.FluxReceive.terminateReceiver(FluxReceive.java:391) ~[reactor-netty-0.9.0] at reactor.netty.channel.FluxReceive.drainReceiver(FluxReceive.java:197) ~[reactor-netty-0.9.0] at reactor.netty.channel.FluxReceive.onInboundComplete(FluxReceive.java:338) ~[reactor-netty-0.9.0] at reactor.netty.channel.ChannelOperations.onInboundComplete(ChannelOperations.java:350) ~[reactor-netty-0.9.0] at reactor.netty.channel.ChannelOperations.terminate(ChannelOperations.java:399) ~[reactor-netty-0.9.0] at reactor.netty.http.client.HttpClientOperations.onInboundNext(HttpClientOperations.java:555) ~[reactor-netty-0.9.0] …
  • 9. Debugging Reactive flows 9 java.lang.RuntimeException: Am I looking like a nice stacktrace friends ? at io.spring.workshop.tradingservice.TradingCompanyClient.lambda$getTradingCompany$0(TradingCompanyClient.java:38) ~[classes/:na] at reactor.core.publisher.FluxPeekFuseable$PeekFuseableSubscriber.onNext(FluxPeekFuseable.java:190) ~[reactor-core-3.3.0] at reactor.core.publisher.Operators$MonoSubscriber.complete(Operators.java:1575) ~[reactor-core-3.3.0] at reactor.core.publisher.MonoFlatMap$FlatMapInner.onNext(MonoFlatMap.java:241) ~[reactor-core-3.3.0] at reactor.core.publisher.FluxOnAssembly$OnAssemblySubscriber.onNext(FluxOnAssembly.java:349) ~[reactor-core-3.3.0] at reactor.core.publisher.FluxMapFuseable$MapFuseableSubscriber.onNext(FluxMapFuseable.java:121) ~[reactor-core-3.3.0] at reactor.core.publisher.FluxContextStart$ContextStartSubscriber.onNext(FluxContextStart.java:103) ~[reactor-core-3.3.0] at reactor.core.publisher.FluxMapFuseable$MapFuseableConditionalSubscriber.onNext(FluxMapFuseable.java:287) ~[reactor-core-3.3.0] at reactor.core.publisher.FluxFilterFuseable$FilterFuseableConditionalSubscriber.onNext(FluxFilterFuseable.java:331) ~[reactor-core-3.3.0] at reactor.core.publisher.Operators$MonoSubscriber.complete(Operators.java:1575) ~[reactor-core-3.3.0] at reactor.core.publisher.MonoCollectList$MonoCollectListSubscriber.onComplete(MonoCollectList.java:121) ~[reactor-core-3.3.0] at reactor.core.publisher.FluxMap$MapSubscriber.onComplete(FluxMap.java:136) ~[reactor-core-3.3.0] at reactor.core.publisher.FluxPeek$PeekSubscriber.onComplete(FluxPeek.java:252) ~[reactor-core-3.3.0] at reactor.core.publisher.FluxPeek$PeekSubscriber.onComplete(FluxPeek.java:252) ~[reactor-core-3.3.0] at reactor.core.publisher.FluxMap$MapSubscriber.onComplete(FluxMap.java:136) ~[reactor-core-3.3.0] at reactor.netty.channel.FluxReceive.terminateReceiver(FluxReceive.java:391) ~[reactor-netty-0.9.0] at reactor.netty.channel.FluxReceive.drainReceiver(FluxReceive.java:197) ~[reactor-netty-0.9.0] at reactor.netty.channel.FluxReceive.onInboundComplete(FluxReceive.java:338) ~[reactor-netty-0.9.0] at reactor.netty.channel.ChannelOperations.onInboundComplete(ChannelOperations.java:350) ~[reactor-netty-0.9.0] at reactor.netty.channel.ChannelOperations.terminate(ChannelOperations.java:399) ~[reactor-netty-0.9.0] at reactor.netty.http.client.HttpClientOperations.onInboundNext(HttpClientOperations.java:555) ~[reactor-netty-0.9.0] … You ?
  • 10. Using blocking code in reactive callbacks 10 TradingCompany tradingCompany = this.restTemplate.exchange( get("http://localhost:8082/details/{ticker}", ticker), TradingCompany.class) .getBody();
  • 11. Using blocking code in reactive callbacks 11 someMono.doOnSuccess(data -> { TradingCompany tradingCompany = this.restTemplate.exchange( get("http://localhost:8082/details/{ticker}", ticker), TradingCompany.class) .getBody(); return tradingCompany; }); 💩
  • 12. What are you priorities ? 12
  • 13. What are you priorities ? 13 Time To Market / Dev Productivity
  • 14. What are you priorities ? 14 Time To Market / Dev Productivity Day 2 Operations / Observability
  • 15. What are you priorities ? 15 Time To Market / Dev Productivity Day 2 Operations / Observability […]
  • 16. What are you priorities ? 16 Time To Market / Dev Productivity Day 2 Operations / Observability Running costs / efficiency […]
  • 17. What are you priorities ? 17 Time To Market / Dev Productivity Day 2 Operations / Observability Reactive ?Running costs / efficiency […]
  • 19. 19 Order(s) of Magnitude 
 more efficient 🤑
  • 20. • Lower Number of processes/threads used by instance • Lower Memory Pressure and associated costs (Garbage collectors) • Lower Hardware specification requirements • Lower Startup time 20 Order(s) of Magnitude 
 more efficient
  • 21. Show me some numbers 21 Order(s) of Magnitude 
 more efficient
  • 22. 22 Order(s) of Magnitude 
 more efficient Spring WebFlux.Fn - Reactor Netty - 4 threads & Spring MVC - Tomcat - 200 threads With a simple hello world String rendering 128 / steps up to 4000 20s 20min
  • 23. 23 Order(s) of Magnitude 
 more efficient
  • 24. 24 Order(s) of Magnitude 
 more efficient MVCWebFlux
  • 25. 25 Order(s) of Magnitude 
 more efficient 😎 🤒
  • 26. 26 Order(s) of Magnitude 
 more efficient Moar Old Gen Moar Young Gen
  • 27. 27 Order(s) of Magnitude 
 more efficient
  • 28. 28 Order(s) of Magnitude 
 more efficient x2
  • 29. 29 Order(s) of Magnitude 
 more efficient 😎 ⏰
  • 30. 30 Designed for 
 connection volume scalability 📱Order(s) of Magnitude 
 more efficient
  • 31. • Lower Number of instances running a same application • Lower Impact from traffic latency diversity • Lower Impact from persistent http traffic (websocket, sse, http2…) 31 Designed for 
 connection volume scalability
  • 32. 32 Spring WebFlux.Fn - Reactor Netty - 4 threads & Spring MVC - Tomcat - 200 threads With a 100ms delayed hello world String rendering 128 / steps up to 4000 20s 20min Designed for 
 connection volume scalability
  • 33. Designed for 
 connection volume scalability 33 MVC (async)WebFlux
  • 34. Designed for 
 connection volume scalability 34🤢
  • 35. 35 Designed for 
 connection volume scalability
  • 36. 36 x4 Designed for 
 connection volume scalability
  • 38. How does the response delay impact each model ? 38 Designed for 
 connection volume scalability
  • 39. 39 Designed for 
 connection volume scalability WebFlux WebFlux (with response delay)
  • 40. WebFlux WebFlux (with response delay) 40 Designed for 
 connection volume scalability
  • 41. WebFlux WebFlux (with response delay) 41 Designed for 
 connection volume scalability No major impact from backend delays
  • 42. 42 Designed for 
 connection volume scalability WebMVC (with response delay)WebMVC
  • 43. 43 Designed for 
 connection volume scalability WebMVC (with response delay)WebMVC Rapidly degrading running conditions
  • 44. 44 Designed for 
 connection volume scalability WebMVC WebMVC (with response delay)
  • 45. 45 Designed for 
 connection volume scalability WebMVC WebMVC (with response delay) x4 slower due to backend delays
  • 46. 46 Designed for 
 connection volume scalability 📱Order(s) of Magnitude 
 more efficient
  • 47. 47 Sleep Well,
 get less paged 📟 Order(s) of Magnitude 
 more efficient Designed for 
 connection volume scalability
  • 48. Sleep Well,
 get less paged • Greater resilience to runtime errors, including memory issues • Greater availability at any point in time, specially under stress • Easier resources use modeling 48
  • 49. Sleep Well,
 get less paged 49 Figure 1.a: 
 A blocking JVM HTTP server with no flow control
  • 50. Sleep Well,
 get less paged Reactive IO allows reading when application capacity permits 50
  • 51. Sleep Well,
 get less paged Reactive IO only writes back application data when client capacity permits 51
  • 52. 52 WebFlux WebFlux (with response delay) Sleep Well,
 get less paged
  • 53. 53 WebFlux WebFlux (with response delay) Very similar resources use profile Sleep Well,
 get less paged
  • 54. Sleep Well,
 get less paged 54 Can reactive programming help with JVM OutOfMemory exceptions caused by incoming request traffic ?
  • 55. Sleep Well,
 get less paged • Yes, using a reactive IO runtime, request body overflow is isolated • A Connection Read causing an OutOfMemory will be rejected 55
  • 56. Sleep Well,
 get less paged • Yes, using a reactive IO runtime, request body overflow is isolated • A Connection Read causing an OutOfMemory will be rejected • With a blocking IO runtime, request body overflow will be fatal • The entire application will crash or be in unrecoverable state 56
  • 57. 57 Sleep Well,
 get less paged Order(s) of Magnitude 
 more efficient Designed for 
 connection volume scalability
  • 58. 58 Sleep Well,
 get less paged Order(s) of Magnitude 
 more efficient Designed for 
 connection volume scalability Event-Driven Less Threads - Memory Start quicker Improve Latency* Unlocks hyper concurrency Connected Experience Slow/Fast traffic Near-Always Available Flow Control Predictable load Resilient
  • 59. 59 What do you do with these qualities ? 🤓
  • 60. 60 Write Any Microservice Resilient Smaller resources footprint Remote calls parallelization Hedge Clients
  • 61. 61 Write Any Microservice Resilient Smaller resources footprint Remote calls parallelization Hedge Clients
  • 62. 62 Remote calls parallelization With Spring, you can start writing your app with WebMVC, introduce WebClient to improve backend calls workflows, then consider moving to WebFlux
  • 63. 63 Write an Edge API Available Traffic Control Volume of Connections
  • 64. 64 Write an Edge API Available Traffic Control Volume of Connections
  • 65. 65 Traffic Control A reactive runtime will isolate ingress/egress traffic latency and exceptions. Given this isolation property, a reactive Edge API should always be able to route traffic, even limit it or short-circuit when required.
  • 66. 66 Mobile Backend Scale with different traffic latency Connected experience (notifications…) Volume of clients
  • 67. 67 Mobile IoT Backend Scale with different traffic latency Connected experience (notifications…) Volume of clients
  • 68. Ok sounds cool, but what about the developer experience ? 68 😷
  • 69. 69 Error has been observed at the following site(s): |_ checkpoint ⇢ Handler io.spring.workshop.tradingservice.QuotesController#quotesDetails(String) [DispatcherHandler] |_ checkpoint ⇢ org.springframework.security.web.server.authorization.AuthorizationWebFilter [DefaultWebFilterChain] |_ checkpoint ⇢ org.springframework.security.web.server.authorization.ExceptionTranslationWebFilter [DefaultWebFilterChain] |_ checkpoint ⇢ org.springframework.security.web.server.authentication.logout.LogoutWebFilter [DefaultWebFilterChain] |_ checkpoint ⇢ org.springframework.security.web.server.savedrequest.ServerRequestCacheWebFilter [DefaultWebFilterChain] |_ checkpoint ⇢ org.springframework.security.web.server.context.SecurityContextServerWebExchangeWebFilter [DefaultWebFilterChain] |_ checkpoint ⇢ org.springframework.security.web.server.ui.LogoutPageGeneratingWebFilter [DefaultWebFilterChain] |_ checkpoint ⇢ org.springframework.security.web.server.ui.LoginPageGeneratingWebFilter [DefaultWebFilterChain] |_ checkpoint ⇢ org.springframework.security.web.server.authentication.AuthenticationWebFilter [DefaultWebFilterChain] |_ checkpoint ⇢ org.springframework.security.web.server.authentication.AuthenticationWebFilter [DefaultWebFilterChain] |_ checkpoint ⇢ org.springframework.security.web.server.context.ReactorContextWebFilter [DefaultWebFilterChain] |_ checkpoint ⇢ org.springframework.security.web.server.csrf.CsrfWebFilter [DefaultWebFilterChain] |_ checkpoint ⇢ org.springframework.security.web.server.header.HttpHeaderWriterWebFilter [DefaultWebFilterChain] |_ checkpoint ⇢ org.springframework.security.config.web.server.ServerHttpSecurity$ServerWebExchangeReactorContextWebFilter [DefaultWebFilterChain] |_ checkpoint ⇢ org.springframework.security.web.server.WebFilterChainProxy [DefaultWebFilterChain] |_ checkpoint ⇢ org.springframework.boot.web.reactive.filter.OrderedHiddenHttpMethodFilter [DefaultWebFilterChain] |_ checkpoint ⇢ org.springframework.boot.actuate.metrics.web.reactive.server.MetricsWebFilter [DefaultWebFilterChain] |_ checkpoint ⇢ HTTP GET "/quotes/summary/MSFT" [ExceptionHandlingWebHandler] Exceptions since Spring Framework 5.2 Actionable stacktraces
  • 70. 70 Error has been observed at the following site(s): |_ Mono.doOnNext ⇢ at io.spring.workshop.tradingservice.TradingCompanyClient.getTradingCompany(TradingCompanyClient.java:38) |_ Mono.switchIfEmpty ⇢ at io.spring.workshop.tradingservice.TradingCompanyClient.getTradingCompany(TradingCompanyClient.java:39) |_ Mono.zipWith ⇢ at io.spring.workshop.tradingservice.QuotesController.quotesDetails(QuotesController.java:39) |_ Mono.switchIfEmpty ⇢ at org.springframework.http.codec.EncoderHttpMessageWriter.write(EncoderHttpMessageWriter.java:119) |_ Mono.flatMap ⇢ at org.springframework.http.codec.EncoderHttpMessageWriter.write(EncoderHttpMessageWriter.java:123) |_ checkpoint ⇢ Handler io.spring.workshop.tradingservice.QuotesController#quotesDetails(String) [DispatcherHandler] |_ Mono.flatMap ⇢ at org.springframework.web.reactive.DispatcherHandler.lambda$handleResult$5(DispatcherHandler.java:172) |_ Mono.onErrorResume ⇢ at org.springframework.web.reactive.DispatcherHandler.handleResult(DispatcherHandler.java:171) |_ Mono.flatMap ⇢ at org.springframework.web.reactive.DispatcherHandler.handle(DispatcherHandler.java:147) |_ Mono.defer ⇢ at org.springframework.web.server.handler.DefaultWebFilterChain.filter(DefaultWebFilterChain.java:119) |_ Mono.defer ⇢ at org.springframework.web.server.handler.DefaultWebFilterChain.filter(DefaultWebFilterChain.java:119) |_ Mono.switchIfEmpty ⇢ at org.springframework.security.web.server.authorization.AuthorizationWebFilter.filter(AuthorizationWebFilter.java:46) |_ checkpoint ⇢ org.springframework.security.web.server.authorization.AuthorizationWebFilter [DefaultWebFilterChain] |_ Mono.defer ⇢ at org.springframework.web.server.handler.DefaultWebFilterChain.filter(DefaultWebFilterChain.java:119) |_ FluxMap$MapSubscriber.onComplete ⇢ at reactor.netty.channel.FluxReceive.terminateReceiver(FluxReceive.java:391) Exceptions with debug mode enabled
  • 71. 71 Error has been observed at the following site(s): |_ Mono.doOnNext ⇢ at io.spring.workshop.tradingservice.TradingCompanyClient.getTradingCompany(TradingCompanyClient.java:38) |_ Mono.switchIfEmpty ⇢ at io.spring.workshop.tradingservice.TradingCompanyClient.getTradingCompany(TradingCompanyClient.java:39) |_ Mono.zipWith ⇢ at io.spring.workshop.tradingservice.QuotesController.quotesDetails(QuotesController.java:39) |_ Mono.switchIfEmpty ⇢ at org.springframework.http.codec.EncoderHttpMessageWriter.write(EncoderHttpMessageWriter.java:119) |_ Mono.flatMap ⇢ at org.springframework.http.codec.EncoderHttpMessageWriter.write(EncoderHttpMessageWriter.java:123) |_ checkpoint ⇢ Handler io.spring.workshop.tradingservice.QuotesController#quotesDetails(String) [DispatcherHandler] |_ Mono.flatMap ⇢ at org.springframework.web.reactive.DispatcherHandler.lambda$handleResult$5(DispatcherHandler.java:172) |_ Mono.onErrorResume ⇢ at org.springframework.web.reactive.DispatcherHandler.handleResult(DispatcherHandler.java:171) |_ Mono.flatMap ⇢ at org.springframework.web.reactive.DispatcherHandler.handle(DispatcherHandler.java:147) |_ Mono.defer ⇢ at org.springframework.web.server.handler.DefaultWebFilterChain.filter(DefaultWebFilterChain.java:119) |_ Mono.defer ⇢ at org.springframework.web.server.handler.DefaultWebFilterChain.filter(DefaultWebFilterChain.java:119) |_ Mono.switchIfEmpty ⇢ at org.springframework.security.web.server.authorization.AuthorizationWebFilter.filter(AuthorizationWebFilter.java:46) |_ checkpoint ⇢ org.springframework.security.web.server.authorization.AuthorizationWebFilter [DefaultWebFilterChain] |_ Mono.defer ⇢ at org.springframework.web.server.handler.DefaultWebFilterChain.filter(DefaultWebFilterChain.java:119) |_ FluxMap$MapSubscriber.onComplete ⇢ at reactor.netty.channel.FluxReceive.terminateReceiver(FluxReceive.java:391) Exceptions with debug mode enabled Reactive Developer productivity
  • 72. 72 Soon coming as a jvm agent Mobile Backend Scale even with different traffic latency Connected experience (notifications…) Volume of clients
  • 73. 73 Soon coming as a jvm agent Mobile Backend Scale even with different traffic latency Connected experience (notifications…) Volume of clients Speaking of which…
  • 74. 74 BlockHound ! Mobile Backend Scale even with different traffic latency Connected experience (notifications…) Volume of clients https://github.com/reactor/BlockHound
  • 75. Detecting blocking code in reactive stack 75 BlockHound.install(); someMono.doOnSuccess(data -> { TradingCompany tradingCompany = this.restTemplate.exchange( get("http://localhost:8082/details/{ticker}", ticker), TradingCompany.class) .getBody(); return tradingCompany; });
  • 76. Detecting blocking code in reactive stack 76 BlockHound.install(); someMono.doOnSuccess(data -> { TradingCompany tradingCompany = this.restTemplate.exchange( get("http://localhost:8082/details/{ticker}", ticker), TradingCompany.class) .getBody(); return tradingCompany; }); java.lang.Error: Blocking call! java.net.Socket#connect at reactor.blockhound.BlockHound$Builder.lambda$new$0(BlockHound.java:154) ~[blockhound-1.0.0.jar:na] at reactor.blockhound.BlockHound$Builder.lambda$install$8(BlockHound.java:254) ~[blockhound-1.0.0.jar:na] at reactor.blockhound.BlockHoundRuntime.checkBlocking(BlockHoundRuntime.java:43) ~[blockhound-1.0.0.jar:na] at java.net.Socket.connect(Socket.java) ~[na:1.8.0_144] at sun.net.NetworkClient.doConnect(NetworkClient.java:180) ~[na:1.8.0_144] at sun.net.www.http.HttpClient.openServer(HttpClient.java:463) ~[na:1.8.0_144] at sun.net.www.http.HttpClient.openServer(HttpClient.java:558) ~[na:1.8.0_144] at sun.net.www.http.HttpClient.<init>(HttpClient.java:242) ~[na:1.8.0_144] at sun.net.www.http.HttpClient.New(HttpClient.java:339) ~[na:1.8.0_144] at sun.net.www.http.HttpClient.New(HttpClient.java:357) ~[na:1.8.0_144] Quickly detect during pre-production workflows that will likely degrade your reactive stack experience
  • 78. ~80% of apps generated by start.spring.io are using a SQL driver 78
  • 79. ~80% of apps generated by start.spring.io are using a SQL driver 79 r2dbc.io
  • 80. What should I look after I successfully have written my first Reactive apps ? 80
  • 83. 83 Having fun developing with Kotlin kotlinlang.org
  • 85. What are you priorities ? 85 Time To Market / Dev Productivity Day 2 Operations / Observability Running costs / efficiency […] With Reactive You can actually be more productive in writing state of the art, scalable microservices
  • 86. What are you priorities ? 86 Time To Market / Dev Productivity Day 2 Operations / Observability Running costs / efficiency […] With Reactive Your Applications are designed to be resilient under stress and lower maintenance
  • 87. What are you priorities ? 87 Time To Market / Dev Productivity Day 2 Operations / Observability Running costs / efficiency […] With Reactive You run more for less
  • 88. What are you priorities ? 88 Time To Market / Dev Productivity Day 2 Operations / Observability Running costs / efficiency […]
  • 89. 89 Establish the right project to experiment Reactive Programming with
  • 90. 90 Do it progressively, migrate a few dedicated backend routes then an entire application You can already parallelize some workloads even on your blocking stack
  • 91. 91
  • 92. 92 Use all the developers tools you can to accelerate your reactive adoption and build trust
  • 93. 93 Once the cost of learning has been paid and the benefits realized- it’s usually difficult to come back to blocking solutions.
  • 94. 94 In fact it’s difficult in today’s world of distributed systems to not find a reason for giving a go to any Reactive stack.
  • 95. 95 In fact it’s difficult in today’s world of distributed systems to not find a reason for giving a go to any Reactive stack. It’s just designed for them