SlideShare a Scribd company logo
1 of 54
Designing, Implementing,
and Using Reactive APIs
Ben Hale
@nebhale
1
Paul Harris
@twoseat
&
Unless otherwise indicated, these slides are © 2013 -2017 Pivotal Software, Inc. and licensed under a Creative Commons
Attribution-NonCommercial license: http://creativecommons.org/licenses/by -nc/3.0/
Introduction to Reactive Programming
• Reactive is used to broadly define event-driven systems
• Moves imperative logic to
• asynchronous
• non-blocking
• functional-style code
• Allows stable, scalable access to external systems
2
Unless otherwise indicated, these slides are © 2013 -2017 Pivotal Software, Inc. and licensed under a Creative Commons
Attribution-NonCommercial license: http://creativecommons.org/licenses/by -nc/3.0/
Cloud Foundry Java Client
• Cloud Foundry is composed of
• RESTful APIs
• Secured by OAuth
• Transmitting large JSON request and response payloads
• APIs are low level, often requiring orchestration
3
Unless otherwise indicated, these slides are © 2013 -2017 Pivotal Software, Inc. and licensed under a Creative Commons
Attribution-NonCommercial license: http://creativecommons.org/licenses/by -nc/3.0/
Cloud Foundry Java Client
• Java has become the preferred language for orchestrating Cloud Foundry
• Complex orchestration is difficult when working against generic payloads
• A strongly typed Java API is required for maintainability
4
Unless otherwise indicated, these slides are © 2013 -2017 Pivotal Software, Inc. and licensed under a Creative Commons
Attribution-NonCommercial license: http://creativecommons.org/licenses/by -nc/3.0/
Generic Request and Response Payloads
Map<String, Object> request = new HashMap<>();
request.put("name", "test-application");
request.put("application", Paths.get("target/test-application.jar"));
request.put("buildpack", "java-buildpack");
this.operations.applications()
.push(request)
.map(response -> response.get("id"));
5
Unless otherwise indicated, these slides are © 2013 -2017 Pivotal Software, Inc. and licensed under a Creative Commons
Attribution-NonCommercial license: http://creativecommons.org/licenses/by -nc/3.0/
Strongly Typed Request and Response
Payloads
this.operations.applications()
.push(PushApplicationRequest.builder()
.name("test-application")
.application(Paths.get("target/test-application.jar"))
.buildpack("java-buildpack")
.build())
.map(CreateApplicationResponse::getId);
6
Unless otherwise indicated, these slides are © 2013 -2017 Pivotal Software, Inc. and licensed under a Creative Commons
Attribution-NonCommercial license: http://creativecommons.org/licenses/by -nc/3.0/
Cloud Foundry Java Client
• The high-latency network interaction is a good fit for a Reactive Design
• Encourages asynchronous and highly concurrent usage
• Partnering with Project Reactor early influenced both the design of the client and
of Reactor
7
Unless otherwise indicated, these slides are © 2013 -2017 Pivotal Software, Inc. and licensed under a Creative Commons
Attribution-NonCommercial license: http://creativecommons.org/licenses/by -nc/3.0/
Design
8
Unless otherwise indicated, these slides are © 2013 -2017 Pivotal Software, Inc. and licensed under a Creative Commons
Attribution-NonCommercial license: http://creativecommons.org/licenses/by -nc/3.0/
When To Use Reactive
• Networking
• Latency
• Failures
• Backpressure
• Highly Concurrent Operations
• Scalability
9
Unless otherwise indicated, these slides are © 2013 -2017 Pivotal Software, Inc. and licensed under a Creative Commons
Attribution-NonCommercial license: http://creativecommons.org/licenses/by -nc/3.0/
What Should a Reactive API Return?
• Flux<T>
• Returns 0 to N values
• Mono<T>
• Returns 0 to 1 value
• The Java Client often returns Monos containing collections
10
Unless otherwise indicated, these slides are © 2013 -2017 Pivotal Software, Inc. and licensed under a Creative Commons
Attribution-NonCommercial license: http://creativecommons.org/licenses/by -nc/3.0/
Using a Flux<T> Response
Flux<Application> listApplications() {...}
Flux<String> listApplicationNames() {
return listApplications()
.map(Application::getName);
}
void printApplicationName() {
listApplicationNames()
.subscribe(System.out::println);
}
11
Unless otherwise indicated, these slides are © 2013 -2017 Pivotal Software, Inc. and licensed under a Creative Commons
Attribution-NonCommercial license: http://creativecommons.org/licenses/by -nc/3.0/
Using a Mono<T> Response
Flux<Application> listApplications() {...}
Mono<List<String>> listApplicationNames() {
return listApplications()
.map(Application::getName)
.collectAsList();
}
Mono<Boolean> doesApplicationExist(String name) {
return listApplicationNames()
.map(names -> names.contains(name));
}
12
Unless otherwise indicated, these slides are © 2013 -2017 Pivotal Software, Inc. and licensed under a Creative Commons
Attribution-NonCommercial license: http://creativecommons.org/licenses/by -nc/3.0/
Every Method Must Return Something
• Unlike many imperative APIs, void is not an appropriate return type
• A reactive flow declares behavior but does not execute it
• Consumers must subscribe to a Flux or Mono in order to begin execution
13
Unless otherwise indicated, these slides are © 2013 -2017 Pivotal Software, Inc. and licensed under a Creative Commons
Attribution-NonCommercial license: http://creativecommons.org/licenses/by -nc/3.0/
Imperative Operation
void delete(String id) {
this.restTemplate.delete(URI, id);
}
public static void main(String[] args) {
delete("test-id");
}
14
Unless otherwise indicated, these slides are © 2013 -2017 Pivotal Software, Inc. and licensed under a Creative Commons
Attribution-NonCommercial license: http://creativecommons.org/licenses/by -nc/3.0/
Reactive Operation
Mono<Void> delete(String id) {
return this.httpClient.delete(URI, id);
}
public static void main(String[] args) {
CountDownLatch latch = new CountDownLatch(1);
delete("test-id")
.subscribe(n -> {}, Throwable::printStackTrace, () -> latch.countDown());
latch.await();
}
15
Unless otherwise indicated, these slides are © 2013 -2017 Pivotal Software, Inc. and licensed under a Creative Commons
Attribution-NonCommercial license: http://creativecommons.org/licenses/by -nc/3.0/
Scope of a Method
• Methods should be designed to be small and reusable
• Reusable methods can be more easily composed into larger operations
• These methods can be more flexibly combined into parallel or sequential
operations
16
Unless otherwise indicated, these slides are © 2013 -2017 Pivotal Software, Inc. and licensed under a Creative Commons
Attribution-NonCommercial license: http://creativecommons.org/licenses/by -nc/3.0/
Reusable Methods
Mono<ListApplicationsResponse> getPage(int page) {
return this.client.applicationsV2()
.list(ListApplicationsRequest.builder()
.page(page)
.build());
}
public static void main(String[] args) {
getPage(1)
.map(PaginatedResponse::getTotalPages)
.flatMapMany(totalPages -> Flux.range(2, totalPages)
.flatMap(page -> getPage(page)))
.subscribe(System.out::println);
}
17
Unless otherwise indicated, these slides are © 2013 -2017 Pivotal Software, Inc. and licensed under a Creative Commons
Attribution-NonCommercial license: http://creativecommons.org/licenses/by -nc/3.0/
Implement
18
Unless otherwise indicated, these slides are © 2013 -2017 Pivotal Software, Inc. and licensed under a Creative Commons
Attribution-NonCommercial license: http://creativecommons.org/licenses/by -nc/3.0/
Sequential and Parallel Coordination
• All significant performance improvements come from concurrency
• But, concurrency is very hard to do properly
• Reactive frameworks allow you to define sequential and parallel relationships
between operations
• The framework does the hard work of coordinating the operations
19
Unless otherwise indicated, these slides are © 2013 -2017 Pivotal Software, Inc. and licensed under a Creative Commons
Attribution-NonCommercial license: http://creativecommons.org/licenses/by -nc/3.0/
Coordination
Mono<ListApplicationsResponse> getPage(int page) {
return this.client.applicationsV2()
.list(ListApplicationsRequest.builder()
.page(page)
.build());
}
public static void main(String[] args) {
getPage(1)
.map(PaginatedResponse::getTotalPages)
.flatMapMany(totalPages -> Flux.range(2, totalPages)
.flatMap(page -> getPage(page)))
.subscribe(System.out::println);
}
20
Unless otherwise indicated, these slides are © 2013 -2017 Pivotal Software, Inc. and licensed under a Creative Commons
Attribution-NonCommercial license: http://creativecommons.org/licenses/by -nc/3.0/
Conditional Logic
• Like normal values, errors pass through the flow’s operations
• These errors can be passed all the way to consumers, or flows can change
behavior based on them
• Flows can transform errors or generate new results based on the error
21
Unless otherwise indicated, these slides are © 2013 -2017 Pivotal Software, Inc. and licensed under a Creative Commons
Attribution-NonCommercial license: http://creativecommons.org/licenses/by -nc/3.0/
Error Logic
public Mono<AppStatsResponse> getApp(GetAppRequest request) {
return client.applications()
.statistics(AppStatsRequest.builder()
.applicationId(request.id())
.build())
.onErrorResume(ExceptionUtils.statusCode(APP_STOPPED_ERROR),
t -> Mono.just(AppStatsResponse.builder().build()));
}
22
Unless otherwise indicated, these slides are © 2013 -2017 Pivotal Software, Inc. and licensed under a Creative Commons
Attribution-NonCommercial license: http://creativecommons.org/licenses/by -nc/3.0/
Conditional Logic
• It is valid for a flow to complete without sending any elements
• This is often equivalent to returning null from an imperative API
• This completion can be passed all the way to consumers
• Alternatively, flows can switch behavior or generate new elements based on the
completion
23
Unless otherwise indicated, these slides are © 2013 -2017 Pivotal Software, Inc. and licensed under a Creative Commons
Attribution-NonCommercial license: http://creativecommons.org/licenses/by -nc/3.0/
Empty Logic
public Flux<GetDomainsResponse> getDomains(GetDomainsRequest request) {
return requestPrivateDomains(request.getId())
.switchIfEmpty(requestSharedDomains(request.getId));
}
24
Unless otherwise indicated, these slides are © 2013 -2017 Pivotal Software, Inc. and licensed under a Creative Commons
Attribution-NonCommercial license: http://creativecommons.org/licenses/by -nc/3.0/
Empty Logic
public Mono<String> getDomainId(GetDomainIdRequest request) {
return getPrivateDomainId(request.getName())
.switchIfEmpty(getSharedDomainId(request.getName()))
.switchIfEmpty(ExceptionUtils.illegalState(
"Domain %s not found", request.getName()));
}
25
Unless otherwise indicated, these slides are © 2013 -2017 Pivotal Software, Inc. and licensed under a Creative Commons
Attribution-NonCommercial license: http://creativecommons.org/licenses/by -nc/3.0/
Conditional Logic
• Sometimes you want to make decisions not based on errors or emptiness, but on
values themselves
• While it’s possible to implement this logic using operators, it often proves to be
more complex than is worthwhile
• It’s OK to use imperative conditional statements
26
Unless otherwise indicated, these slides are © 2013 -2017 Pivotal Software, Inc. and licensed under a Creative Commons
Attribution-NonCommercial license: http://creativecommons.org/licenses/by -nc/3.0/
Conditional Logic Avoiding Imperative
public Mono<String> getDomainId(String domain, String organizationId) {
return Mono.just(domain)
.filter(d -> d == null)
.then(getSharedDomainIds()
.switchIfEmpty(getPrivateDomainIds(organizationId))
.next()
.switchIfEmpty(ExceptionUtils.illegalState("Domain not found")))
.switchIfEmpty(getPrivateDomainId(domain, organizationId)
.switchIfEmpty(getSharedDomainId(domain))
.switchIfEmpty(ExceptionUtils.illegalState("Domain %s not found", domain)));
}
27
Unless otherwise indicated, these slides are © 2013 -2017 Pivotal Software, Inc. and licensed under a Creative Commons
Attribution-NonCommercial license: http://creativecommons.org/licenses/by -nc/3.0/
Conditional Logic Using Imperative
public Mono<String> getDomainId(String domain, String organizationId) {
if (domain == null) {
return getSharedDomainIds()
.switchIfEmpty(getPrivateDomainIds(organizationId))
.next()
.switchIfEmpty(ExceptionUtils.illegalState("Domain not found"));
} else {
return getPrivateDomainId(domain, organizationId)
.switchIfEmpty(getSharedDomainId(domain))
.switchIfEmpty(ExceptionUtils.illegalState("Domain %s not found", domain));
}
}
28
Unless otherwise indicated, these slides are © 2013 -2017 Pivotal Software, Inc. and licensed under a Creative Commons
Attribution-NonCommercial license: http://creativecommons.org/licenses/by -nc/3.0/
Testing
• Most useful flows will be asynchronous
• Testing frameworks are aggressively synchronous, registering results before
asynchronous results return
• To compensate for this you must block the main thread and make test assertions
in the asynchronous thread
29
Unless otherwise indicated, these slides are © 2013 -2017 Pivotal Software, Inc. and licensed under a Creative Commons
Attribution-NonCommercial license: http://creativecommons.org/licenses/by -nc/3.0/
Test Finishing Before Assertions
@Test
public void noLatch() {
Mono.just("alpha")
.subscribeOn(Schedulers.single())
.subscribe(s -> assertEquals("bravo", s));
}
30
Unless otherwise indicated, these slides are © 2013 -2017 Pivotal Software, Inc. and licensed under a Creative Commons
Attribution-NonCommercial license: http://creativecommons.org/licenses/by -nc/3.0/
Test Finishing Before Assertions
@Test
public void noLatch() {
Mono.just("alpha")
.subscribeOn(Schedulers.single())
.subscribe(s -> assertEquals("bravo", s));
}
31
Unless otherwise indicated, these slides are © 2013 -2017 Pivotal Software, Inc. and licensed under a Creative Commons
Attribution-NonCommercial license: http://creativecommons.org/licenses/by -nc/3.0/
Test Blocking Using CountDownLatch
@Test
public void latch() throws InterruptedException {
CountDownLatch latch = new CountDownLatch(1);
AtomicReference<String> actual = new AtomicReference<>();
Mono.just("alpha")
.subscribeOn(Schedulers.single())
.subscribe(actual::set, t -> latch.countDown(), latch::countDown);
latch.await();
assertEquals("bravo", actual.get());
}
32
Unless otherwise indicated, these slides are © 2013 -2017 Pivotal Software, Inc. and licensed under a Creative Commons
Attribution-NonCommercial license: http://creativecommons.org/licenses/by -nc/3.0/
Test Blocking Using CountDownLatch
@Test
public void latch() throws InterruptedException {
CountDownLatch latch = new CountDownLatch(1);
AtomicReference<String> actual = new AtomicReference<>();
Mono.just("alpha")
.subscribeOn(Schedulers.single())
.subscribe(actual::set, t -> latch.countDown(), latch::countDown);
latch.await();
assertEquals("bravo", actual.get());
}
33
Unless otherwise indicated, these slides are © 2013 -2017 Pivotal Software, Inc. and licensed under a Creative Commons
Attribution-NonCommercial license: http://creativecommons.org/licenses/by -nc/3.0/
Testing using StepVerifier
• Testing a Reactive design requires more than just blocking
• Multiple value assertion
• Expected error assertion
• Unexpected error failure
• Using StepVerifier handles all these cases.
34
Unless otherwise indicated, these slides are © 2013 -2017 Pivotal Software, Inc. and licensed under a Creative Commons
Attribution-NonCommercial license: http://creativecommons.org/licenses/by -nc/3.0/
Test Multiple Values
@Test
public void testMultipleValues() {
Flux.just("alpha", “bravo")
.as(StepVerifier::create)
.expectNext(“alpha”)
.expectNext(“bravo”)
.expectComplete()
.verify(Duration.ofSeconds(5));
}
35
Unless otherwise indicated, these slides are © 2013 -2017 Pivotal Software, Inc. and licensed under a Creative Commons
Attribution-NonCommercial license: http://creativecommons.org/licenses/by -nc/3.0/
Test Expected Error
@Test
public void shareFails() {
this.domains
.share(ShareDomainRequest.builder()
.domain("test-domain")
.organization(“test-organization")
.build())
.as(StepVerifier::create)
.consumeErrorWith(t -> assertThat(t)
.isInstanceOf(IllegalArgumentException.class)
.hasMessage("Private domain test-domain does not exist"))
.verify(Duration.ofSeconds(5));
}
36
Unless otherwise indicated, these slides are © 2013 -2017 Pivotal Software, Inc. and licensed under a Creative Commons
Attribution-NonCommercial license: http://creativecommons.org/licenses/by -nc/3.0/
Use
37
Unless otherwise indicated, these slides are © 2013 -2017 Pivotal Software, Inc. and licensed under a Creative Commons
Attribution-NonCommercial license: http://creativecommons.org/licenses/by -nc/3.0/
Countdown Latches
• Reactive frameworks can only coordinate their own operations
• Many execution environments have processes that outlast individual threads
• Reactive programming plays nicely here
• Some execution environments aggressively terminate the process before any
individual thread
38
Unless otherwise indicated, these slides are © 2013 -2017 Pivotal Software, Inc. and licensed under a Creative Commons
Attribution-NonCommercial license: http://creativecommons.org/licenses/by -nc/3.0/
main() Finishing Before Subscriber<T>
public static void main(String[] args) {
Mono.just("alpha")
.delaySubscription(Duration.ofSeconds(1))
.subscribeOn(Schedulers.single())
.subscribe(System.out::println);
}
39
Unless otherwise indicated, these slides are © 2013 -2017 Pivotal Software, Inc. and licensed under a Creative Commons
Attribution-NonCommercial license: http://creativecommons.org/licenses/by -nc/3.0/
main() Finishing Before Subscriber<T>
public static void main(String[] args) {
Mono.just("alpha")
.delaySubscription(Duration.ofSeconds(1))
.subscribeOn(Schedulers.single())
.subscribe(System.out::println);
}
40
Unless otherwise indicated, these slides are © 2013 -2017 Pivotal Software, Inc. and licensed under a Creative Commons
Attribution-NonCommercial license: http://creativecommons.org/licenses/by -nc/3.0/
main() Waiting for Subscriber<T>
public static void main(String[] args) throws InterruptedException {
CountDownLatch latch = new CountDownLatch(1);
Mono.just("alpha")
.delaySubscription(Duration.ofSeconds(1))
.subscribeOn(Schedulers.single())
.subscribe(System.out::println, t -> latch.countDown(),
latch::countDown);
latch.await();
}
41
Unless otherwise indicated, these slides are © 2013 -2017 Pivotal Software, Inc. and licensed under a Creative Commons
Attribution-NonCommercial license: http://creativecommons.org/licenses/by -nc/3.0/
main() Waiting for Subscriber<T>
public static void main(String[] args) throws InterruptedException {
CountDownLatch latch = new CountDownLatch(1);
Mono.just("alpha")
.delaySubscription(Duration.ofSeconds(1))
.subscribeOn(Schedulers.single())
.subscribe(System.out::println, t -> latch.countDown(),
latch::countDown);
latch.await();
}
42
Unless otherwise indicated, these slides are © 2013 -2017 Pivotal Software, Inc. and licensed under a Creative Commons
Attribution-NonCommercial license: http://creativecommons.org/licenses/by -nc/3.0/
Blocking Flows
• It’s very common to bridge between imperative and reactive APIs
• In those cases blocking while waiting for a result is appropriate.
43
Unless otherwise indicated, these slides are © 2013 -2017 Pivotal Software, Inc. and licensed under a Creative Commons
Attribution-NonCommercial license: http://creativecommons.org/licenses/by -nc/3.0/
Bridging Imperative and Reactive using block()
Mono<User> requestUser(String name) {...}
@Override
User getUser(String name) {
return requestUser(name)
.block();
}
44
Unless otherwise indicated, these slides are © 2013 -2017 Pivotal Software, Inc. and licensed under a Creative Commons
Attribution-NonCommercial license: http://creativecommons.org/licenses/by -nc/3.0/
Bridging Imperative and Reactive using block()
Flux<User> requestUsers() {...}
@Override
List<User> listUsers() {
return requestUsers()
.collectList()
.block();
}
45
Unless otherwise indicated, these slides are © 2013 -2017 Pivotal Software, Inc. and licensed under a Creative Commons
Attribution-NonCommercial license: http://creativecommons.org/licenses/by -nc/3.0/
Error Handling
• Because errors are values they must be handled, they do not just show up
• Subscribe has 0…3 parameters
• Release latches on error
46
Unless otherwise indicated, these slides are © 2013 -2017 Pivotal Software, Inc. and licensed under a Creative Commons
Attribution-NonCommercial license: http://creativecommons.org/licenses/by -nc/3.0/
Error Handling
public static void main(String[] args) throws InterruptedException {
CountDownLatch latch = new CountDownLatch(1);
Flux.concat(Mono.just("alpha"), Mono.error(new IllegalStateException()))
.subscribe(System.out::println, t -> {
t.printStackTrace();
latch.countDown();
}, latch::countDown);
latch.await();
}
47
Unless otherwise indicated, these slides are © 2013 -2017 Pivotal Software, Inc. and licensed under a Creative Commons
Attribution-NonCommercial license: http://creativecommons.org/licenses/by -nc/3.0/
Composable Method References
• Reactive programming is susceptible to callback hell, but it doesn’t have to be
• Extracting behavior into private methods can be even more valuable than in
imperative programming
• Well named methods, and method reference syntax, lead to very readable flows
48
Unless otherwise indicated, these slides are © 2013 -2017 Pivotal Software, Inc. and licensed under a Creative Commons
Attribution-NonCommercial license: http://creativecommons.org/licenses/by -nc/3.0/
Composable Method References
@Override
public Flux<ApplicationSummary> list() {
return Mono
.zip(this.cloudFoundryClient, this.spaceId)
.flatMap(function(DefaultApplications::requestSpaceSummary))
.flatMapMany(DefaultApplications::extractApplications)
.map(DefaultApplications::toApplicationSummary);
}
49
Unless otherwise indicated, these slides are © 2013 -2017 Pivotal Software, Inc. and licensed under a Creative Commons
Attribution-NonCommercial license: http://creativecommons.org/licenses/by -nc/3.0/
Point Free
• You may have noticed that our code samples use a very compact style
• Point Free (http://bit.ly/Point-Free)
• It helps the developer think about composing functions (high level), rather than
shuffling data (low level)
• You don’t have to use, but we find that most people prefer it (eventually)
50
Unless otherwise indicated, these slides are © 2013 -2017 Pivotal Software, Inc. and licensed under a Creative Commons
Attribution-NonCommercial license: http://creativecommons.org/licenses/by -nc/3.0/
Composable Method References
Mono<Void> deleteApplication(String name) {
return PaginationUtils
.requestClientV2Resources(page -> this.client.applicationsV2()
.list(ListApplicationsRequest.builder()
.name(name)
.page(page)
.build()))
.single()
.map(applicationResource -> applicationResource.getMetadata().getId())
.flatMap(applicationId -> this.client.applicationsV2()
.delete(DeleteApplicationRequest.builder()
.applicationId(applicationId)
.build()));
}
51
Unless otherwise indicated, these slides are © 2013 -2017 Pivotal Software, Inc. and licensed under a Creative Commons
Attribution-NonCommercial license: http://creativecommons.org/licenses/by -nc/3.0/
Summary
52
Unless otherwise indicated, these slides are © 2013 -2017 Pivotal Software, Inc. and licensed under a Creative Commons
Attribution-NonCommercial license: http://creativecommons.org/licenses/by -nc/3.0/
Designing, Implementing and Using Reactive APIs
• Design
• When to use
• Return Mono/Flux
• Reusable Methods
• Implement
• Sequential and Parallel
• Conditional logic
• Testing
53
• Use
• Countdown Latches
• Blocking flows
• Error Handling
• Composable methods
• Point Free Style
Learn More. Stay Connected.
https://github.com/cloudfoundry/cf-java-client
54
#springone@s1p

More Related Content

What's hot

Open Service Broker APIとKubernetes Service Catalog #k8sjp
Open Service Broker APIとKubernetes Service Catalog #k8sjpOpen Service Broker APIとKubernetes Service Catalog #k8sjp
Open Service Broker APIとKubernetes Service Catalog #k8sjpToshiaki Maki
 
Bulding a reactive game engine with Spring 5 & Couchbase
Bulding a reactive game engine with Spring 5 & CouchbaseBulding a reactive game engine with Spring 5 & Couchbase
Bulding a reactive game engine with Spring 5 & CouchbaseAlex Derkach
 
How to monitor your micro-service with Prometheus?
How to monitor your micro-service with Prometheus?How to monitor your micro-service with Prometheus?
How to monitor your micro-service with Prometheus?Wojciech Barczyński
 
Monitor your Java application with Prometheus Stack
Monitor your Java application with Prometheus StackMonitor your Java application with Prometheus Stack
Monitor your Java application with Prometheus StackWojciech Barczyński
 
Microservices with Netflix OSS & Spring Cloud - Arnaud Cogoluègnes
 Microservices with Netflix OSS & Spring Cloud - Arnaud Cogoluègnes Microservices with Netflix OSS & Spring Cloud - Arnaud Cogoluègnes
Microservices with Netflix OSS & Spring Cloud - Arnaud Cogoluègnesdistributed matters
 
Kubernetes Java Operator
Kubernetes Java OperatorKubernetes Java Operator
Kubernetes Java OperatorAnthony Dahanne
 
Spring Boot Revisited with KoFu and JaFu
Spring Boot Revisited with KoFu and JaFuSpring Boot Revisited with KoFu and JaFu
Spring Boot Revisited with KoFu and JaFuVMware Tanzu
 
Test your Kubernetes operator with Operator Lifecycle Management
Test your Kubernetes operator with Operator Lifecycle ManagementTest your Kubernetes operator with Operator Lifecycle Management
Test your Kubernetes operator with Operator Lifecycle ManagementBaiju Muthukadan
 
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
 
End to End Akka Streams / Reactive Streams - from Business to Socket
End to End Akka Streams / Reactive Streams - from Business to SocketEnd to End Akka Streams / Reactive Streams - from Business to Socket
End to End Akka Streams / Reactive Streams - from Business to SocketKonrad Malawski
 
Hands-on monitoring with Prometheus
Hands-on monitoring with PrometheusHands-on monitoring with Prometheus
Hands-on monitoring with PrometheusBrice Fernandes
 
Monitoring kubernetes with prometheus
Monitoring kubernetes with prometheusMonitoring kubernetes with prometheus
Monitoring kubernetes with prometheusBrice Fernandes
 
クラウド時代の Spring Framework (aka Spring Framework in Cloud Era)
クラウド時代の Spring Framework (aka Spring Framework in Cloud Era)クラウド時代の Spring Framework (aka Spring Framework in Cloud Era)
クラウド時代の Spring Framework (aka Spring Framework in Cloud Era)Tsuyoshi Miyake
 
Reactive Programming in Java 8 with Rx-Java
Reactive Programming in Java 8 with Rx-JavaReactive Programming in Java 8 with Rx-Java
Reactive Programming in Java 8 with Rx-JavaKasun Indrasiri
 
Monitoring MySQL with Prometheus, Grafana and Percona Dashboards
Monitoring MySQL with Prometheus, Grafana and Percona DashboardsMonitoring MySQL with Prometheus, Grafana and Percona Dashboards
Monitoring MySQL with Prometheus, Grafana and Percona DashboardsJulien Pivotto
 
Red Hat OpenShift Operators - Operators ABC
Red Hat OpenShift Operators - Operators ABCRed Hat OpenShift Operators - Operators ABC
Red Hat OpenShift Operators - Operators ABCRobert Bohne
 
jbang: Unleash the power of Java for shell scripting
jbang: Unleash the power of Java for shell scriptingjbang: Unleash the power of Java for shell scripting
jbang: Unleash the power of Java for shell scriptingRed Hat Developers
 

What's hot (20)

Open Service Broker APIとKubernetes Service Catalog #k8sjp
Open Service Broker APIとKubernetes Service Catalog #k8sjpOpen Service Broker APIとKubernetes Service Catalog #k8sjp
Open Service Broker APIとKubernetes Service Catalog #k8sjp
 
Bulding a reactive game engine with Spring 5 & Couchbase
Bulding a reactive game engine with Spring 5 & CouchbaseBulding a reactive game engine with Spring 5 & Couchbase
Bulding a reactive game engine with Spring 5 & Couchbase
 
How to monitor your micro-service with Prometheus?
How to monitor your micro-service with Prometheus?How to monitor your micro-service with Prometheus?
How to monitor your micro-service with Prometheus?
 
Monitor your Java application with Prometheus Stack
Monitor your Java application with Prometheus StackMonitor your Java application with Prometheus Stack
Monitor your Java application with Prometheus Stack
 
Microservices with Netflix OSS & Spring Cloud - Arnaud Cogoluègnes
 Microservices with Netflix OSS & Spring Cloud - Arnaud Cogoluègnes Microservices with Netflix OSS & Spring Cloud - Arnaud Cogoluègnes
Microservices with Netflix OSS & Spring Cloud - Arnaud Cogoluègnes
 
Epoxy 介紹
Epoxy 介紹Epoxy 介紹
Epoxy 介紹
 
Kubernetes Java Operator
Kubernetes Java OperatorKubernetes Java Operator
Kubernetes Java Operator
 
Spring Boot Revisited with KoFu and JaFu
Spring Boot Revisited with KoFu and JaFuSpring Boot Revisited with KoFu and JaFu
Spring Boot Revisited with KoFu and JaFu
 
Test your Kubernetes operator with Operator Lifecycle Management
Test your Kubernetes operator with Operator Lifecycle ManagementTest your Kubernetes operator with Operator Lifecycle Management
Test your Kubernetes operator with Operator Lifecycle Management
 
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
 
End to End Akka Streams / Reactive Streams - from Business to Socket
End to End Akka Streams / Reactive Streams - from Business to SocketEnd to End Akka Streams / Reactive Streams - from Business to Socket
End to End Akka Streams / Reactive Streams - from Business to Socket
 
Hands-on monitoring with Prometheus
Hands-on monitoring with PrometheusHands-on monitoring with Prometheus
Hands-on monitoring with Prometheus
 
Monitoring kubernetes with prometheus
Monitoring kubernetes with prometheusMonitoring kubernetes with prometheus
Monitoring kubernetes with prometheus
 
クラウド時代の Spring Framework (aka Spring Framework in Cloud Era)
クラウド時代の Spring Framework (aka Spring Framework in Cloud Era)クラウド時代の Spring Framework (aka Spring Framework in Cloud Era)
クラウド時代の Spring Framework (aka Spring Framework in Cloud Era)
 
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
 
Reactive Programming in Java 8 with Rx-Java
Reactive Programming in Java 8 with Rx-JavaReactive Programming in Java 8 with Rx-Java
Reactive Programming in Java 8 with Rx-Java
 
Monitoring MySQL with Prometheus, Grafana and Percona Dashboards
Monitoring MySQL with Prometheus, Grafana and Percona DashboardsMonitoring MySQL with Prometheus, Grafana and Percona Dashboards
Monitoring MySQL with Prometheus, Grafana and Percona Dashboards
 
Red Hat OpenShift Operators - Operators ABC
Red Hat OpenShift Operators - Operators ABCRed Hat OpenShift Operators - Operators ABC
Red Hat OpenShift Operators - Operators ABC
 
JEE on DC/OS
JEE on DC/OSJEE on DC/OS
JEE on DC/OS
 
jbang: Unleash the power of Java for shell scripting
jbang: Unleash the power of Java for shell scriptingjbang: Unleash the power of Java for shell scripting
jbang: Unleash the power of Java for shell scripting
 

Similar to Designing, Implementing, and Using Reactive APIs

High Performance Cloud Native APIs Using Apache Geode
High Performance Cloud Native APIs Using Apache Geode High Performance Cloud Native APIs Using Apache Geode
High Performance Cloud Native APIs Using Apache Geode VMware Tanzu
 
Introduction to Reactive Streams and Reactor 2.5
Introduction to Reactive Streams and Reactor 2.5Introduction to Reactive Streams and Reactor 2.5
Introduction to Reactive Streams and Reactor 2.5Stéphane Maldini
 
Intro To Reactive Programming
Intro To Reactive ProgrammingIntro To Reactive Programming
Intro To Reactive ProgrammingRossen Stoyanchev
 
Intro to Reactive Programming
Intro to Reactive ProgrammingIntro to Reactive Programming
Intro to Reactive ProgrammingStéphane Maldini
 
Building .NET Microservices
Building .NET MicroservicesBuilding .NET Microservices
Building .NET MicroservicesVMware Tanzu
 
Consumer Driven Contracts and Your Microservice Architecture
Consumer Driven Contracts and Your Microservice ArchitectureConsumer Driven Contracts and Your Microservice Architecture
Consumer Driven Contracts and Your Microservice ArchitectureVMware Tanzu
 
Migrating to Angular 5 for Spring Developers
Migrating to Angular 5 for Spring DevelopersMigrating to Angular 5 for Spring Developers
Migrating to Angular 5 for Spring DevelopersGunnar Hillert
 
Migrating to Angular 4 for Spring Developers
Migrating to Angular 4 for Spring Developers Migrating to Angular 4 for Spring Developers
Migrating to Angular 4 for Spring Developers VMware Tanzu
 
Cloud-Native Streaming and Event-Driven Microservices
Cloud-Native Streaming and Event-Driven MicroservicesCloud-Native Streaming and Event-Driven Microservices
Cloud-Native Streaming and Event-Driven MicroservicesVMware Tanzu
 
Consumer Driven Contracts and Your Microservice Architecture
Consumer Driven Contracts and Your Microservice ArchitectureConsumer Driven Contracts and Your Microservice Architecture
Consumer Driven Contracts and Your Microservice ArchitectureMarcin Grzejszczak
 
What's new in Spring Boot 2.0
What's new in Spring Boot 2.0What's new in Spring Boot 2.0
What's new in Spring Boot 2.0VMware Tanzu
 
Under the Hood of Reactive Data Access (2/2)
Under the Hood of Reactive Data Access (2/2)Under the Hood of Reactive Data Access (2/2)
Under the Hood of Reactive Data Access (2/2)VMware Tanzu
 
Welcome to the Reactive Revolution:RSocket and Spring Cloud Gateway - Spencer...
Welcome to the Reactive Revolution:RSocket and Spring Cloud Gateway - Spencer...Welcome to the Reactive Revolution:RSocket and Spring Cloud Gateway - Spencer...
Welcome to the Reactive Revolution:RSocket and Spring Cloud Gateway - Spencer...VMware Tanzu
 
Spring MVC 4.2: New and Noteworthy
Spring MVC 4.2: New and NoteworthySpring MVC 4.2: New and Noteworthy
Spring MVC 4.2: New and NoteworthyRossen Stoyanchev
 
Ratpack - SpringOne2GX 2015
Ratpack - SpringOne2GX 2015Ratpack - SpringOne2GX 2015
Ratpack - SpringOne2GX 2015Daniel Woods
 
SpringOnePlatform2017 recap
SpringOnePlatform2017 recapSpringOnePlatform2017 recap
SpringOnePlatform2017 recapminseok kim
 
The Beginner’s Guide To Spring Cloud
The Beginner’s Guide To Spring CloudThe Beginner’s Guide To Spring Cloud
The Beginner’s Guide To Spring CloudVMware Tanzu
 
P to V to C: The Value of Bringing “Everything” to Containers
P to V to C: The Value of Bringing “Everything” to ContainersP to V to C: The Value of Bringing “Everything” to Containers
P to V to C: The Value of Bringing “Everything” to ContainersVMware Tanzu
 
Running Java Applications on Cloud Foundry
Running Java Applications on Cloud FoundryRunning Java Applications on Cloud Foundry
Running Java Applications on Cloud FoundryVMware Tanzu
 

Similar to Designing, Implementing, and Using Reactive APIs (20)

Reactive Web Applications
Reactive Web ApplicationsReactive Web Applications
Reactive Web Applications
 
High Performance Cloud Native APIs Using Apache Geode
High Performance Cloud Native APIs Using Apache Geode High Performance Cloud Native APIs Using Apache Geode
High Performance Cloud Native APIs Using Apache Geode
 
Introduction to Reactive Streams and Reactor 2.5
Introduction to Reactive Streams and Reactor 2.5Introduction to Reactive Streams and Reactor 2.5
Introduction to Reactive Streams and Reactor 2.5
 
Intro To Reactive Programming
Intro To Reactive ProgrammingIntro To Reactive Programming
Intro To Reactive Programming
 
Intro to Reactive Programming
Intro to Reactive ProgrammingIntro to Reactive Programming
Intro to Reactive Programming
 
Building .NET Microservices
Building .NET MicroservicesBuilding .NET Microservices
Building .NET Microservices
 
Consumer Driven Contracts and Your Microservice Architecture
Consumer Driven Contracts and Your Microservice ArchitectureConsumer Driven Contracts and Your Microservice Architecture
Consumer Driven Contracts and Your Microservice Architecture
 
Migrating to Angular 5 for Spring Developers
Migrating to Angular 5 for Spring DevelopersMigrating to Angular 5 for Spring Developers
Migrating to Angular 5 for Spring Developers
 
Migrating to Angular 4 for Spring Developers
Migrating to Angular 4 for Spring Developers Migrating to Angular 4 for Spring Developers
Migrating to Angular 4 for Spring Developers
 
Cloud-Native Streaming and Event-Driven Microservices
Cloud-Native Streaming and Event-Driven MicroservicesCloud-Native Streaming and Event-Driven Microservices
Cloud-Native Streaming and Event-Driven Microservices
 
Consumer Driven Contracts and Your Microservice Architecture
Consumer Driven Contracts and Your Microservice ArchitectureConsumer Driven Contracts and Your Microservice Architecture
Consumer Driven Contracts and Your Microservice Architecture
 
What's new in Spring Boot 2.0
What's new in Spring Boot 2.0What's new in Spring Boot 2.0
What's new in Spring Boot 2.0
 
Under the Hood of Reactive Data Access (2/2)
Under the Hood of Reactive Data Access (2/2)Under the Hood of Reactive Data Access (2/2)
Under the Hood of Reactive Data Access (2/2)
 
Welcome to the Reactive Revolution:RSocket and Spring Cloud Gateway - Spencer...
Welcome to the Reactive Revolution:RSocket and Spring Cloud Gateway - Spencer...Welcome to the Reactive Revolution:RSocket and Spring Cloud Gateway - Spencer...
Welcome to the Reactive Revolution:RSocket and Spring Cloud Gateway - Spencer...
 
Spring MVC 4.2: New and Noteworthy
Spring MVC 4.2: New and NoteworthySpring MVC 4.2: New and Noteworthy
Spring MVC 4.2: New and Noteworthy
 
Ratpack - SpringOne2GX 2015
Ratpack - SpringOne2GX 2015Ratpack - SpringOne2GX 2015
Ratpack - SpringOne2GX 2015
 
SpringOnePlatform2017 recap
SpringOnePlatform2017 recapSpringOnePlatform2017 recap
SpringOnePlatform2017 recap
 
The Beginner’s Guide To Spring Cloud
The Beginner’s Guide To Spring CloudThe Beginner’s Guide To Spring Cloud
The Beginner’s Guide To Spring Cloud
 
P to V to C: The Value of Bringing “Everything” to Containers
P to V to C: The Value of Bringing “Everything” to ContainersP to V to C: The Value of Bringing “Everything” to Containers
P to V to C: The Value of Bringing “Everything” to Containers
 
Running Java Applications on Cloud Foundry
Running Java Applications on Cloud FoundryRunning Java Applications on Cloud Foundry
Running Java Applications on Cloud Foundry
 

More from VMware Tanzu

Spring into AI presented by Dan Vega 5/14
Spring into AI presented by Dan Vega 5/14Spring into AI presented by Dan Vega 5/14
Spring into AI presented by Dan Vega 5/14VMware Tanzu
 
What AI Means For Your Product Strategy And What To Do About It
What AI Means For Your Product Strategy And What To Do About ItWhat AI Means For Your Product Strategy And What To Do About It
What AI Means For Your Product Strategy And What To Do About ItVMware Tanzu
 
Make the Right Thing the Obvious Thing at Cardinal Health 2023
Make the Right Thing the Obvious Thing at Cardinal Health 2023Make the Right Thing the Obvious Thing at Cardinal Health 2023
Make the Right Thing the Obvious Thing at Cardinal Health 2023VMware Tanzu
 
Enhancing DevEx and Simplifying Operations at Scale
Enhancing DevEx and Simplifying Operations at ScaleEnhancing DevEx and Simplifying Operations at Scale
Enhancing DevEx and Simplifying Operations at ScaleVMware Tanzu
 
Spring Update | July 2023
Spring Update | July 2023Spring Update | July 2023
Spring Update | July 2023VMware Tanzu
 
Platforms, Platform Engineering, & Platform as a Product
Platforms, Platform Engineering, & Platform as a ProductPlatforms, Platform Engineering, & Platform as a Product
Platforms, Platform Engineering, & Platform as a ProductVMware Tanzu
 
Building Cloud Ready Apps
Building Cloud Ready AppsBuilding Cloud Ready Apps
Building Cloud Ready AppsVMware Tanzu
 
Spring Boot 3 And Beyond
Spring Boot 3 And BeyondSpring Boot 3 And Beyond
Spring Boot 3 And BeyondVMware Tanzu
 
Spring Cloud Gateway - SpringOne Tour 2023 Charles Schwab.pdf
Spring Cloud Gateway - SpringOne Tour 2023 Charles Schwab.pdfSpring Cloud Gateway - SpringOne Tour 2023 Charles Schwab.pdf
Spring Cloud Gateway - SpringOne Tour 2023 Charles Schwab.pdfVMware Tanzu
 
Simplify and Scale Enterprise Apps in the Cloud | Boston 2023
Simplify and Scale Enterprise Apps in the Cloud | Boston 2023Simplify and Scale Enterprise Apps in the Cloud | Boston 2023
Simplify and Scale Enterprise Apps in the Cloud | Boston 2023VMware Tanzu
 
Simplify and Scale Enterprise Apps in the Cloud | Seattle 2023
Simplify and Scale Enterprise Apps in the Cloud | Seattle 2023Simplify and Scale Enterprise Apps in the Cloud | Seattle 2023
Simplify and Scale Enterprise Apps in the Cloud | Seattle 2023VMware Tanzu
 
tanzu_developer_connect.pptx
tanzu_developer_connect.pptxtanzu_developer_connect.pptx
tanzu_developer_connect.pptxVMware Tanzu
 
Tanzu Virtual Developer Connect Workshop - French
Tanzu Virtual Developer Connect Workshop - FrenchTanzu Virtual Developer Connect Workshop - French
Tanzu Virtual Developer Connect Workshop - FrenchVMware Tanzu
 
Tanzu Developer Connect Workshop - English
Tanzu Developer Connect Workshop - EnglishTanzu Developer Connect Workshop - English
Tanzu Developer Connect Workshop - EnglishVMware Tanzu
 
Virtual Developer Connect Workshop - English
Virtual Developer Connect Workshop - EnglishVirtual Developer Connect Workshop - English
Virtual Developer Connect Workshop - EnglishVMware Tanzu
 
Tanzu Developer Connect - French
Tanzu Developer Connect - FrenchTanzu Developer Connect - French
Tanzu Developer Connect - FrenchVMware Tanzu
 
Simplify and Scale Enterprise Apps in the Cloud | Dallas 2023
Simplify and Scale Enterprise Apps in the Cloud | Dallas 2023Simplify and Scale Enterprise Apps in the Cloud | Dallas 2023
Simplify and Scale Enterprise Apps in the Cloud | Dallas 2023VMware Tanzu
 
SpringOne Tour: Deliver 15-Factor Applications on Kubernetes with Spring Boot
SpringOne Tour: Deliver 15-Factor Applications on Kubernetes with Spring BootSpringOne Tour: Deliver 15-Factor Applications on Kubernetes with Spring Boot
SpringOne Tour: Deliver 15-Factor Applications on Kubernetes with Spring BootVMware Tanzu
 
SpringOne Tour: The Influential Software Engineer
SpringOne Tour: The Influential Software EngineerSpringOne Tour: The Influential Software Engineer
SpringOne Tour: The Influential Software EngineerVMware Tanzu
 
SpringOne Tour: Domain-Driven Design: Theory vs Practice
SpringOne Tour: Domain-Driven Design: Theory vs PracticeSpringOne Tour: Domain-Driven Design: Theory vs Practice
SpringOne Tour: Domain-Driven Design: Theory vs PracticeVMware Tanzu
 

More from VMware Tanzu (20)

Spring into AI presented by Dan Vega 5/14
Spring into AI presented by Dan Vega 5/14Spring into AI presented by Dan Vega 5/14
Spring into AI presented by Dan Vega 5/14
 
What AI Means For Your Product Strategy And What To Do About It
What AI Means For Your Product Strategy And What To Do About ItWhat AI Means For Your Product Strategy And What To Do About It
What AI Means For Your Product Strategy And What To Do About It
 
Make the Right Thing the Obvious Thing at Cardinal Health 2023
Make the Right Thing the Obvious Thing at Cardinal Health 2023Make the Right Thing the Obvious Thing at Cardinal Health 2023
Make the Right Thing the Obvious Thing at Cardinal Health 2023
 
Enhancing DevEx and Simplifying Operations at Scale
Enhancing DevEx and Simplifying Operations at ScaleEnhancing DevEx and Simplifying Operations at Scale
Enhancing DevEx and Simplifying Operations at Scale
 
Spring Update | July 2023
Spring Update | July 2023Spring Update | July 2023
Spring Update | July 2023
 
Platforms, Platform Engineering, & Platform as a Product
Platforms, Platform Engineering, & Platform as a ProductPlatforms, Platform Engineering, & Platform as a Product
Platforms, Platform Engineering, & Platform as a Product
 
Building Cloud Ready Apps
Building Cloud Ready AppsBuilding Cloud Ready Apps
Building Cloud Ready Apps
 
Spring Boot 3 And Beyond
Spring Boot 3 And BeyondSpring Boot 3 And Beyond
Spring Boot 3 And Beyond
 
Spring Cloud Gateway - SpringOne Tour 2023 Charles Schwab.pdf
Spring Cloud Gateway - SpringOne Tour 2023 Charles Schwab.pdfSpring Cloud Gateway - SpringOne Tour 2023 Charles Schwab.pdf
Spring Cloud Gateway - SpringOne Tour 2023 Charles Schwab.pdf
 
Simplify and Scale Enterprise Apps in the Cloud | Boston 2023
Simplify and Scale Enterprise Apps in the Cloud | Boston 2023Simplify and Scale Enterprise Apps in the Cloud | Boston 2023
Simplify and Scale Enterprise Apps in the Cloud | Boston 2023
 
Simplify and Scale Enterprise Apps in the Cloud | Seattle 2023
Simplify and Scale Enterprise Apps in the Cloud | Seattle 2023Simplify and Scale Enterprise Apps in the Cloud | Seattle 2023
Simplify and Scale Enterprise Apps in the Cloud | Seattle 2023
 
tanzu_developer_connect.pptx
tanzu_developer_connect.pptxtanzu_developer_connect.pptx
tanzu_developer_connect.pptx
 
Tanzu Virtual Developer Connect Workshop - French
Tanzu Virtual Developer Connect Workshop - FrenchTanzu Virtual Developer Connect Workshop - French
Tanzu Virtual Developer Connect Workshop - French
 
Tanzu Developer Connect Workshop - English
Tanzu Developer Connect Workshop - EnglishTanzu Developer Connect Workshop - English
Tanzu Developer Connect Workshop - English
 
Virtual Developer Connect Workshop - English
Virtual Developer Connect Workshop - EnglishVirtual Developer Connect Workshop - English
Virtual Developer Connect Workshop - English
 
Tanzu Developer Connect - French
Tanzu Developer Connect - FrenchTanzu Developer Connect - French
Tanzu Developer Connect - French
 
Simplify and Scale Enterprise Apps in the Cloud | Dallas 2023
Simplify and Scale Enterprise Apps in the Cloud | Dallas 2023Simplify and Scale Enterprise Apps in the Cloud | Dallas 2023
Simplify and Scale Enterprise Apps in the Cloud | Dallas 2023
 
SpringOne Tour: Deliver 15-Factor Applications on Kubernetes with Spring Boot
SpringOne Tour: Deliver 15-Factor Applications on Kubernetes with Spring BootSpringOne Tour: Deliver 15-Factor Applications on Kubernetes with Spring Boot
SpringOne Tour: Deliver 15-Factor Applications on Kubernetes with Spring Boot
 
SpringOne Tour: The Influential Software Engineer
SpringOne Tour: The Influential Software EngineerSpringOne Tour: The Influential Software Engineer
SpringOne Tour: The Influential Software Engineer
 
SpringOne Tour: Domain-Driven Design: Theory vs Practice
SpringOne Tour: Domain-Driven Design: Theory vs PracticeSpringOne Tour: Domain-Driven Design: Theory vs Practice
SpringOne Tour: Domain-Driven Design: Theory vs Practice
 

Recently uploaded

MINDCTI Revenue Release Quarter One 2024
MINDCTI Revenue Release Quarter One 2024MINDCTI Revenue Release Quarter One 2024
MINDCTI Revenue Release Quarter One 2024MIND CTI
 
Decarbonising Commercial Real Estate: The Role of Operational Performance
Decarbonising Commercial Real Estate: The Role of Operational PerformanceDecarbonising Commercial Real Estate: The Role of Operational Performance
Decarbonising Commercial Real Estate: The Role of Operational PerformanceIES VE
 
Web Form Automation for Bonterra Impact Management (fka Social Solutions Apri...
Web Form Automation for Bonterra Impact Management (fka Social Solutions Apri...Web Form Automation for Bonterra Impact Management (fka Social Solutions Apri...
Web Form Automation for Bonterra Impact Management (fka Social Solutions Apri...Jeffrey Haguewood
 
WSO2 Micro Integrator for Enterprise Integration in a Decentralized, Microser...
WSO2 Micro Integrator for Enterprise Integration in a Decentralized, Microser...WSO2 Micro Integrator for Enterprise Integration in a Decentralized, Microser...
WSO2 Micro Integrator for Enterprise Integration in a Decentralized, Microser...WSO2
 
Navigating Identity and Access Management in the Modern Enterprise
Navigating Identity and Access Management in the Modern EnterpriseNavigating Identity and Access Management in the Modern Enterprise
Navigating Identity and Access Management in the Modern EnterpriseWSO2
 
API Governance and Monetization - The evolution of API governance
API Governance and Monetization -  The evolution of API governanceAPI Governance and Monetization -  The evolution of API governance
API Governance and Monetization - The evolution of API governanceWSO2
 
Platformless Horizons for Digital Adaptability
Platformless Horizons for Digital AdaptabilityPlatformless Horizons for Digital Adaptability
Platformless Horizons for Digital AdaptabilityWSO2
 
Modular Monolith - a Practical Alternative to Microservices @ Devoxx UK 2024
Modular Monolith - a Practical Alternative to Microservices @ Devoxx UK 2024Modular Monolith - a Practical Alternative to Microservices @ Devoxx UK 2024
Modular Monolith - a Practical Alternative to Microservices @ Devoxx UK 2024Victor Rentea
 
Navigating the Deluge_ Dubai Floods and the Resilience of Dubai International...
Navigating the Deluge_ Dubai Floods and the Resilience of Dubai International...Navigating the Deluge_ Dubai Floods and the Resilience of Dubai International...
Navigating the Deluge_ Dubai Floods and the Resilience of Dubai International...Orbitshub
 
Modernizing Legacy Systems Using Ballerina
Modernizing Legacy Systems Using BallerinaModernizing Legacy Systems Using Ballerina
Modernizing Legacy Systems Using BallerinaWSO2
 
Why Teams call analytics are critical to your entire business
Why Teams call analytics are critical to your entire businessWhy Teams call analytics are critical to your entire business
Why Teams call analytics are critical to your entire businesspanagenda
 
TEST BANK For Principles of Anatomy and Physiology, 16th Edition by Gerard J....
TEST BANK For Principles of Anatomy and Physiology, 16th Edition by Gerard J....TEST BANK For Principles of Anatomy and Physiology, 16th Edition by Gerard J....
TEST BANK For Principles of Anatomy and Physiology, 16th Edition by Gerard J....rightmanforbloodline
 
CNIC Information System with Pakdata Cf In Pakistan
CNIC Information System with Pakdata Cf In PakistanCNIC Information System with Pakdata Cf In Pakistan
CNIC Information System with Pakdata Cf In Pakistandanishmna97
 
AI in Action: Real World Use Cases by Anitaraj
AI in Action: Real World Use Cases by AnitarajAI in Action: Real World Use Cases by Anitaraj
AI in Action: Real World Use Cases by AnitarajAnitaRaj43
 
Repurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost Saving
Repurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost SavingRepurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost Saving
Repurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost SavingEdi Saputra
 
Stronger Together: Developing an Organizational Strategy for Accessible Desig...
Stronger Together: Developing an Organizational Strategy for Accessible Desig...Stronger Together: Developing an Organizational Strategy for Accessible Desig...
Stronger Together: Developing an Organizational Strategy for Accessible Desig...caitlingebhard1
 
Architecting Cloud Native Applications
Architecting Cloud Native ApplicationsArchitecting Cloud Native Applications
Architecting Cloud Native ApplicationsWSO2
 
Introduction to use of FHIR Documents in ABDM
Introduction to use of FHIR Documents in ABDMIntroduction to use of FHIR Documents in ABDM
Introduction to use of FHIR Documents in ABDMKumar Satyam
 
Choreo: Empowering the Future of Enterprise Software Engineering
Choreo: Empowering the Future of Enterprise Software EngineeringChoreo: Empowering the Future of Enterprise Software Engineering
Choreo: Empowering the Future of Enterprise Software EngineeringWSO2
 
AWS Community Day CPH - Three problems of Terraform
AWS Community Day CPH - Three problems of TerraformAWS Community Day CPH - Three problems of Terraform
AWS Community Day CPH - Three problems of TerraformAndrey Devyatkin
 

Recently uploaded (20)

MINDCTI Revenue Release Quarter One 2024
MINDCTI Revenue Release Quarter One 2024MINDCTI Revenue Release Quarter One 2024
MINDCTI Revenue Release Quarter One 2024
 
Decarbonising Commercial Real Estate: The Role of Operational Performance
Decarbonising Commercial Real Estate: The Role of Operational PerformanceDecarbonising Commercial Real Estate: The Role of Operational Performance
Decarbonising Commercial Real Estate: The Role of Operational Performance
 
Web Form Automation for Bonterra Impact Management (fka Social Solutions Apri...
Web Form Automation for Bonterra Impact Management (fka Social Solutions Apri...Web Form Automation for Bonterra Impact Management (fka Social Solutions Apri...
Web Form Automation for Bonterra Impact Management (fka Social Solutions Apri...
 
WSO2 Micro Integrator for Enterprise Integration in a Decentralized, Microser...
WSO2 Micro Integrator for Enterprise Integration in a Decentralized, Microser...WSO2 Micro Integrator for Enterprise Integration in a Decentralized, Microser...
WSO2 Micro Integrator for Enterprise Integration in a Decentralized, Microser...
 
Navigating Identity and Access Management in the Modern Enterprise
Navigating Identity and Access Management in the Modern EnterpriseNavigating Identity and Access Management in the Modern Enterprise
Navigating Identity and Access Management in the Modern Enterprise
 
API Governance and Monetization - The evolution of API governance
API Governance and Monetization -  The evolution of API governanceAPI Governance and Monetization -  The evolution of API governance
API Governance and Monetization - The evolution of API governance
 
Platformless Horizons for Digital Adaptability
Platformless Horizons for Digital AdaptabilityPlatformless Horizons for Digital Adaptability
Platformless Horizons for Digital Adaptability
 
Modular Monolith - a Practical Alternative to Microservices @ Devoxx UK 2024
Modular Monolith - a Practical Alternative to Microservices @ Devoxx UK 2024Modular Monolith - a Practical Alternative to Microservices @ Devoxx UK 2024
Modular Monolith - a Practical Alternative to Microservices @ Devoxx UK 2024
 
Navigating the Deluge_ Dubai Floods and the Resilience of Dubai International...
Navigating the Deluge_ Dubai Floods and the Resilience of Dubai International...Navigating the Deluge_ Dubai Floods and the Resilience of Dubai International...
Navigating the Deluge_ Dubai Floods and the Resilience of Dubai International...
 
Modernizing Legacy Systems Using Ballerina
Modernizing Legacy Systems Using BallerinaModernizing Legacy Systems Using Ballerina
Modernizing Legacy Systems Using Ballerina
 
Why Teams call analytics are critical to your entire business
Why Teams call analytics are critical to your entire businessWhy Teams call analytics are critical to your entire business
Why Teams call analytics are critical to your entire business
 
TEST BANK For Principles of Anatomy and Physiology, 16th Edition by Gerard J....
TEST BANK For Principles of Anatomy and Physiology, 16th Edition by Gerard J....TEST BANK For Principles of Anatomy and Physiology, 16th Edition by Gerard J....
TEST BANK For Principles of Anatomy and Physiology, 16th Edition by Gerard J....
 
CNIC Information System with Pakdata Cf In Pakistan
CNIC Information System with Pakdata Cf In PakistanCNIC Information System with Pakdata Cf In Pakistan
CNIC Information System with Pakdata Cf In Pakistan
 
AI in Action: Real World Use Cases by Anitaraj
AI in Action: Real World Use Cases by AnitarajAI in Action: Real World Use Cases by Anitaraj
AI in Action: Real World Use Cases by Anitaraj
 
Repurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost Saving
Repurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost SavingRepurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost Saving
Repurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost Saving
 
Stronger Together: Developing an Organizational Strategy for Accessible Desig...
Stronger Together: Developing an Organizational Strategy for Accessible Desig...Stronger Together: Developing an Organizational Strategy for Accessible Desig...
Stronger Together: Developing an Organizational Strategy for Accessible Desig...
 
Architecting Cloud Native Applications
Architecting Cloud Native ApplicationsArchitecting Cloud Native Applications
Architecting Cloud Native Applications
 
Introduction to use of FHIR Documents in ABDM
Introduction to use of FHIR Documents in ABDMIntroduction to use of FHIR Documents in ABDM
Introduction to use of FHIR Documents in ABDM
 
Choreo: Empowering the Future of Enterprise Software Engineering
Choreo: Empowering the Future of Enterprise Software EngineeringChoreo: Empowering the Future of Enterprise Software Engineering
Choreo: Empowering the Future of Enterprise Software Engineering
 
AWS Community Day CPH - Three problems of Terraform
AWS Community Day CPH - Three problems of TerraformAWS Community Day CPH - Three problems of Terraform
AWS Community Day CPH - Three problems of Terraform
 

Designing, Implementing, and Using Reactive APIs

  • 1. Designing, Implementing, and Using Reactive APIs Ben Hale @nebhale 1 Paul Harris @twoseat &
  • 2. Unless otherwise indicated, these slides are © 2013 -2017 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by -nc/3.0/ Introduction to Reactive Programming • Reactive is used to broadly define event-driven systems • Moves imperative logic to • asynchronous • non-blocking • functional-style code • Allows stable, scalable access to external systems 2
  • 3. Unless otherwise indicated, these slides are © 2013 -2017 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by -nc/3.0/ Cloud Foundry Java Client • Cloud Foundry is composed of • RESTful APIs • Secured by OAuth • Transmitting large JSON request and response payloads • APIs are low level, often requiring orchestration 3
  • 4. Unless otherwise indicated, these slides are © 2013 -2017 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by -nc/3.0/ Cloud Foundry Java Client • Java has become the preferred language for orchestrating Cloud Foundry • Complex orchestration is difficult when working against generic payloads • A strongly typed Java API is required for maintainability 4
  • 5. Unless otherwise indicated, these slides are © 2013 -2017 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by -nc/3.0/ Generic Request and Response Payloads Map<String, Object> request = new HashMap<>(); request.put("name", "test-application"); request.put("application", Paths.get("target/test-application.jar")); request.put("buildpack", "java-buildpack"); this.operations.applications() .push(request) .map(response -> response.get("id")); 5
  • 6. Unless otherwise indicated, these slides are © 2013 -2017 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by -nc/3.0/ Strongly Typed Request and Response Payloads this.operations.applications() .push(PushApplicationRequest.builder() .name("test-application") .application(Paths.get("target/test-application.jar")) .buildpack("java-buildpack") .build()) .map(CreateApplicationResponse::getId); 6
  • 7. Unless otherwise indicated, these slides are © 2013 -2017 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by -nc/3.0/ Cloud Foundry Java Client • The high-latency network interaction is a good fit for a Reactive Design • Encourages asynchronous and highly concurrent usage • Partnering with Project Reactor early influenced both the design of the client and of Reactor 7
  • 8. Unless otherwise indicated, these slides are © 2013 -2017 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by -nc/3.0/ Design 8
  • 9. Unless otherwise indicated, these slides are © 2013 -2017 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by -nc/3.0/ When To Use Reactive • Networking • Latency • Failures • Backpressure • Highly Concurrent Operations • Scalability 9
  • 10. Unless otherwise indicated, these slides are © 2013 -2017 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by -nc/3.0/ What Should a Reactive API Return? • Flux<T> • Returns 0 to N values • Mono<T> • Returns 0 to 1 value • The Java Client often returns Monos containing collections 10
  • 11. Unless otherwise indicated, these slides are © 2013 -2017 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by -nc/3.0/ Using a Flux<T> Response Flux<Application> listApplications() {...} Flux<String> listApplicationNames() { return listApplications() .map(Application::getName); } void printApplicationName() { listApplicationNames() .subscribe(System.out::println); } 11
  • 12. Unless otherwise indicated, these slides are © 2013 -2017 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by -nc/3.0/ Using a Mono<T> Response Flux<Application> listApplications() {...} Mono<List<String>> listApplicationNames() { return listApplications() .map(Application::getName) .collectAsList(); } Mono<Boolean> doesApplicationExist(String name) { return listApplicationNames() .map(names -> names.contains(name)); } 12
  • 13. Unless otherwise indicated, these slides are © 2013 -2017 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by -nc/3.0/ Every Method Must Return Something • Unlike many imperative APIs, void is not an appropriate return type • A reactive flow declares behavior but does not execute it • Consumers must subscribe to a Flux or Mono in order to begin execution 13
  • 14. Unless otherwise indicated, these slides are © 2013 -2017 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by -nc/3.0/ Imperative Operation void delete(String id) { this.restTemplate.delete(URI, id); } public static void main(String[] args) { delete("test-id"); } 14
  • 15. Unless otherwise indicated, these slides are © 2013 -2017 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by -nc/3.0/ Reactive Operation Mono<Void> delete(String id) { return this.httpClient.delete(URI, id); } public static void main(String[] args) { CountDownLatch latch = new CountDownLatch(1); delete("test-id") .subscribe(n -> {}, Throwable::printStackTrace, () -> latch.countDown()); latch.await(); } 15
  • 16. Unless otherwise indicated, these slides are © 2013 -2017 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by -nc/3.0/ Scope of a Method • Methods should be designed to be small and reusable • Reusable methods can be more easily composed into larger operations • These methods can be more flexibly combined into parallel or sequential operations 16
  • 17. Unless otherwise indicated, these slides are © 2013 -2017 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by -nc/3.0/ Reusable Methods Mono<ListApplicationsResponse> getPage(int page) { return this.client.applicationsV2() .list(ListApplicationsRequest.builder() .page(page) .build()); } public static void main(String[] args) { getPage(1) .map(PaginatedResponse::getTotalPages) .flatMapMany(totalPages -> Flux.range(2, totalPages) .flatMap(page -> getPage(page))) .subscribe(System.out::println); } 17
  • 18. Unless otherwise indicated, these slides are © 2013 -2017 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by -nc/3.0/ Implement 18
  • 19. Unless otherwise indicated, these slides are © 2013 -2017 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by -nc/3.0/ Sequential and Parallel Coordination • All significant performance improvements come from concurrency • But, concurrency is very hard to do properly • Reactive frameworks allow you to define sequential and parallel relationships between operations • The framework does the hard work of coordinating the operations 19
  • 20. Unless otherwise indicated, these slides are © 2013 -2017 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by -nc/3.0/ Coordination Mono<ListApplicationsResponse> getPage(int page) { return this.client.applicationsV2() .list(ListApplicationsRequest.builder() .page(page) .build()); } public static void main(String[] args) { getPage(1) .map(PaginatedResponse::getTotalPages) .flatMapMany(totalPages -> Flux.range(2, totalPages) .flatMap(page -> getPage(page))) .subscribe(System.out::println); } 20
  • 21. Unless otherwise indicated, these slides are © 2013 -2017 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by -nc/3.0/ Conditional Logic • Like normal values, errors pass through the flow’s operations • These errors can be passed all the way to consumers, or flows can change behavior based on them • Flows can transform errors or generate new results based on the error 21
  • 22. Unless otherwise indicated, these slides are © 2013 -2017 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by -nc/3.0/ Error Logic public Mono<AppStatsResponse> getApp(GetAppRequest request) { return client.applications() .statistics(AppStatsRequest.builder() .applicationId(request.id()) .build()) .onErrorResume(ExceptionUtils.statusCode(APP_STOPPED_ERROR), t -> Mono.just(AppStatsResponse.builder().build())); } 22
  • 23. Unless otherwise indicated, these slides are © 2013 -2017 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by -nc/3.0/ Conditional Logic • It is valid for a flow to complete without sending any elements • This is often equivalent to returning null from an imperative API • This completion can be passed all the way to consumers • Alternatively, flows can switch behavior or generate new elements based on the completion 23
  • 24. Unless otherwise indicated, these slides are © 2013 -2017 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by -nc/3.0/ Empty Logic public Flux<GetDomainsResponse> getDomains(GetDomainsRequest request) { return requestPrivateDomains(request.getId()) .switchIfEmpty(requestSharedDomains(request.getId)); } 24
  • 25. Unless otherwise indicated, these slides are © 2013 -2017 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by -nc/3.0/ Empty Logic public Mono<String> getDomainId(GetDomainIdRequest request) { return getPrivateDomainId(request.getName()) .switchIfEmpty(getSharedDomainId(request.getName())) .switchIfEmpty(ExceptionUtils.illegalState( "Domain %s not found", request.getName())); } 25
  • 26. Unless otherwise indicated, these slides are © 2013 -2017 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by -nc/3.0/ Conditional Logic • Sometimes you want to make decisions not based on errors or emptiness, but on values themselves • While it’s possible to implement this logic using operators, it often proves to be more complex than is worthwhile • It’s OK to use imperative conditional statements 26
  • 27. Unless otherwise indicated, these slides are © 2013 -2017 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by -nc/3.0/ Conditional Logic Avoiding Imperative public Mono<String> getDomainId(String domain, String organizationId) { return Mono.just(domain) .filter(d -> d == null) .then(getSharedDomainIds() .switchIfEmpty(getPrivateDomainIds(organizationId)) .next() .switchIfEmpty(ExceptionUtils.illegalState("Domain not found"))) .switchIfEmpty(getPrivateDomainId(domain, organizationId) .switchIfEmpty(getSharedDomainId(domain)) .switchIfEmpty(ExceptionUtils.illegalState("Domain %s not found", domain))); } 27
  • 28. Unless otherwise indicated, these slides are © 2013 -2017 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by -nc/3.0/ Conditional Logic Using Imperative public Mono<String> getDomainId(String domain, String organizationId) { if (domain == null) { return getSharedDomainIds() .switchIfEmpty(getPrivateDomainIds(organizationId)) .next() .switchIfEmpty(ExceptionUtils.illegalState("Domain not found")); } else { return getPrivateDomainId(domain, organizationId) .switchIfEmpty(getSharedDomainId(domain)) .switchIfEmpty(ExceptionUtils.illegalState("Domain %s not found", domain)); } } 28
  • 29. Unless otherwise indicated, these slides are © 2013 -2017 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by -nc/3.0/ Testing • Most useful flows will be asynchronous • Testing frameworks are aggressively synchronous, registering results before asynchronous results return • To compensate for this you must block the main thread and make test assertions in the asynchronous thread 29
  • 30. Unless otherwise indicated, these slides are © 2013 -2017 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by -nc/3.0/ Test Finishing Before Assertions @Test public void noLatch() { Mono.just("alpha") .subscribeOn(Schedulers.single()) .subscribe(s -> assertEquals("bravo", s)); } 30
  • 31. Unless otherwise indicated, these slides are © 2013 -2017 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by -nc/3.0/ Test Finishing Before Assertions @Test public void noLatch() { Mono.just("alpha") .subscribeOn(Schedulers.single()) .subscribe(s -> assertEquals("bravo", s)); } 31
  • 32. Unless otherwise indicated, these slides are © 2013 -2017 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by -nc/3.0/ Test Blocking Using CountDownLatch @Test public void latch() throws InterruptedException { CountDownLatch latch = new CountDownLatch(1); AtomicReference<String> actual = new AtomicReference<>(); Mono.just("alpha") .subscribeOn(Schedulers.single()) .subscribe(actual::set, t -> latch.countDown(), latch::countDown); latch.await(); assertEquals("bravo", actual.get()); } 32
  • 33. Unless otherwise indicated, these slides are © 2013 -2017 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by -nc/3.0/ Test Blocking Using CountDownLatch @Test public void latch() throws InterruptedException { CountDownLatch latch = new CountDownLatch(1); AtomicReference<String> actual = new AtomicReference<>(); Mono.just("alpha") .subscribeOn(Schedulers.single()) .subscribe(actual::set, t -> latch.countDown(), latch::countDown); latch.await(); assertEquals("bravo", actual.get()); } 33
  • 34. Unless otherwise indicated, these slides are © 2013 -2017 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by -nc/3.0/ Testing using StepVerifier • Testing a Reactive design requires more than just blocking • Multiple value assertion • Expected error assertion • Unexpected error failure • Using StepVerifier handles all these cases. 34
  • 35. Unless otherwise indicated, these slides are © 2013 -2017 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by -nc/3.0/ Test Multiple Values @Test public void testMultipleValues() { Flux.just("alpha", “bravo") .as(StepVerifier::create) .expectNext(“alpha”) .expectNext(“bravo”) .expectComplete() .verify(Duration.ofSeconds(5)); } 35
  • 36. Unless otherwise indicated, these slides are © 2013 -2017 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by -nc/3.0/ Test Expected Error @Test public void shareFails() { this.domains .share(ShareDomainRequest.builder() .domain("test-domain") .organization(“test-organization") .build()) .as(StepVerifier::create) .consumeErrorWith(t -> assertThat(t) .isInstanceOf(IllegalArgumentException.class) .hasMessage("Private domain test-domain does not exist")) .verify(Duration.ofSeconds(5)); } 36
  • 37. Unless otherwise indicated, these slides are © 2013 -2017 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by -nc/3.0/ Use 37
  • 38. Unless otherwise indicated, these slides are © 2013 -2017 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by -nc/3.0/ Countdown Latches • Reactive frameworks can only coordinate their own operations • Many execution environments have processes that outlast individual threads • Reactive programming plays nicely here • Some execution environments aggressively terminate the process before any individual thread 38
  • 39. Unless otherwise indicated, these slides are © 2013 -2017 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by -nc/3.0/ main() Finishing Before Subscriber<T> public static void main(String[] args) { Mono.just("alpha") .delaySubscription(Duration.ofSeconds(1)) .subscribeOn(Schedulers.single()) .subscribe(System.out::println); } 39
  • 40. Unless otherwise indicated, these slides are © 2013 -2017 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by -nc/3.0/ main() Finishing Before Subscriber<T> public static void main(String[] args) { Mono.just("alpha") .delaySubscription(Duration.ofSeconds(1)) .subscribeOn(Schedulers.single()) .subscribe(System.out::println); } 40
  • 41. Unless otherwise indicated, these slides are © 2013 -2017 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by -nc/3.0/ main() Waiting for Subscriber<T> public static void main(String[] args) throws InterruptedException { CountDownLatch latch = new CountDownLatch(1); Mono.just("alpha") .delaySubscription(Duration.ofSeconds(1)) .subscribeOn(Schedulers.single()) .subscribe(System.out::println, t -> latch.countDown(), latch::countDown); latch.await(); } 41
  • 42. Unless otherwise indicated, these slides are © 2013 -2017 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by -nc/3.0/ main() Waiting for Subscriber<T> public static void main(String[] args) throws InterruptedException { CountDownLatch latch = new CountDownLatch(1); Mono.just("alpha") .delaySubscription(Duration.ofSeconds(1)) .subscribeOn(Schedulers.single()) .subscribe(System.out::println, t -> latch.countDown(), latch::countDown); latch.await(); } 42
  • 43. Unless otherwise indicated, these slides are © 2013 -2017 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by -nc/3.0/ Blocking Flows • It’s very common to bridge between imperative and reactive APIs • In those cases blocking while waiting for a result is appropriate. 43
  • 44. Unless otherwise indicated, these slides are © 2013 -2017 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by -nc/3.0/ Bridging Imperative and Reactive using block() Mono<User> requestUser(String name) {...} @Override User getUser(String name) { return requestUser(name) .block(); } 44
  • 45. Unless otherwise indicated, these slides are © 2013 -2017 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by -nc/3.0/ Bridging Imperative and Reactive using block() Flux<User> requestUsers() {...} @Override List<User> listUsers() { return requestUsers() .collectList() .block(); } 45
  • 46. Unless otherwise indicated, these slides are © 2013 -2017 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by -nc/3.0/ Error Handling • Because errors are values they must be handled, they do not just show up • Subscribe has 0…3 parameters • Release latches on error 46
  • 47. Unless otherwise indicated, these slides are © 2013 -2017 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by -nc/3.0/ Error Handling public static void main(String[] args) throws InterruptedException { CountDownLatch latch = new CountDownLatch(1); Flux.concat(Mono.just("alpha"), Mono.error(new IllegalStateException())) .subscribe(System.out::println, t -> { t.printStackTrace(); latch.countDown(); }, latch::countDown); latch.await(); } 47
  • 48. Unless otherwise indicated, these slides are © 2013 -2017 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by -nc/3.0/ Composable Method References • Reactive programming is susceptible to callback hell, but it doesn’t have to be • Extracting behavior into private methods can be even more valuable than in imperative programming • Well named methods, and method reference syntax, lead to very readable flows 48
  • 49. Unless otherwise indicated, these slides are © 2013 -2017 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by -nc/3.0/ Composable Method References @Override public Flux<ApplicationSummary> list() { return Mono .zip(this.cloudFoundryClient, this.spaceId) .flatMap(function(DefaultApplications::requestSpaceSummary)) .flatMapMany(DefaultApplications::extractApplications) .map(DefaultApplications::toApplicationSummary); } 49
  • 50. Unless otherwise indicated, these slides are © 2013 -2017 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by -nc/3.0/ Point Free • You may have noticed that our code samples use a very compact style • Point Free (http://bit.ly/Point-Free) • It helps the developer think about composing functions (high level), rather than shuffling data (low level) • You don’t have to use, but we find that most people prefer it (eventually) 50
  • 51. Unless otherwise indicated, these slides are © 2013 -2017 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by -nc/3.0/ Composable Method References Mono<Void> deleteApplication(String name) { return PaginationUtils .requestClientV2Resources(page -> this.client.applicationsV2() .list(ListApplicationsRequest.builder() .name(name) .page(page) .build())) .single() .map(applicationResource -> applicationResource.getMetadata().getId()) .flatMap(applicationId -> this.client.applicationsV2() .delete(DeleteApplicationRequest.builder() .applicationId(applicationId) .build())); } 51
  • 52. Unless otherwise indicated, these slides are © 2013 -2017 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by -nc/3.0/ Summary 52
  • 53. Unless otherwise indicated, these slides are © 2013 -2017 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by -nc/3.0/ Designing, Implementing and Using Reactive APIs • Design • When to use • Return Mono/Flux • Reusable Methods • Implement • Sequential and Parallel • Conditional logic • Testing 53 • Use • Countdown Latches • Blocking flows • Error Handling • Composable methods • Point Free Style
  • 54. Learn More. Stay Connected. https://github.com/cloudfoundry/cf-java-client 54 #springone@s1p

Editor's Notes

  1. https://apidocs.cloudfoundry.org/280/apps/creating_an_app.html
  2. Battle tested Stephane’s ideas, and he made changes accordingly.
  3. Say Multicore!
  4. Also otherwiseReturn
  5. If not, use Java 8 Streams! e.g. JUnit
  6. e.g. Servlet Container e.g. Main methods and Junit
  7. Keep everything reactive for as long as possible, blocking only right at the point where you interact with the imperative API. Any reactive API can be made imperative, the reverse is not true.
  8. Used to be called .get(), which is friendly and accessible! Block is scary and evil, we don’t want to block! If you feel yourself typing Mono.block() stop! Do I really need to do this, and is this the right place to do it?
  9. Consume One of the following happens Error Complete So there is no ‘finally’, you have to take care of it