Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Reactive Design in Enterprise Applications #JEE...

Reactive Design in Enterprise Applications #JEEConf2017

Avatar for Grygoriy Gonchar

Grygoriy Gonchar

May 26, 2017

More Decks by Grygoriy Gonchar

Other Decks in Technology

Transcript

  1. Enterprise Application Has some business logic Integrates with others Persists

    data Data intensive Uses blocking implementations Resilient Well-tested
  2. Entity public class Person { private String id; private String

    firstname; private String lastname; private String ip; private IpInfo ipInfo; private List<Person> friends; // ... }
  3. Business Logic public Person addPerson(Person person) { String ipInfo =

    ipService.getIpInfo(person.getIp()); person.setIpInfo(ipInfo); return repository.save(person); }
  4. Get IP Information with Spring 5 Reactive WebClient public Mono<IpInfo>

    getIpInfo(String ip) { return WebClient.create("http://ip-api.com/") .get().uri("/json/{ip}", ip).exchange() .then(ipInfo -> ipInfo.bodyToMono(IpInfo.class)); }
  5. Save Person with Reactive Spring Data (MongoDB) public interface PersonRepository

    extends ReactiveCrudRepository<Person, String> { // <S> Mono<S> save(S var1); }
  6. Business Logic (Composition of Monadic Types) private Mono<Person> addPerson(Mono<Person> mono)

    { return mono .flatMap(this::addIpInfo) .flatMap(repository::save); }
  7. Monads in plain English interface Monad { <B> Monad<B> unit(arg

    B); <B> Monad<B> flatMap(Function<?, Monad<B>> f); }
  8. Business Logic (Nested Monadic Composition) public Mono<Person> addPerson(Mono<Person> mono) {

    return mono .flatMap(this::addIpInfo) .flatMap(repository::save); } private Mono<Person> addIpInfo(Person person) { return ipService.getIpInfo(person.getIp()) .map(ipInfo -> person.copyWithIpInfo(ipInfo)); }
  9. Local Variable Capture and Mutability public Mono<Person> addPerson(Mono<Person> mono) {

    return mono .flatMap(this::addIpInfo) .flatMap(repository::save); } private Mono<Person> addIpInfo(Person person) { return ipService.getIpInfo(person.getIp()) .map(ipInfo -> person.copyWithIpInfo(ipInfo)); }
  10. Pure Functions Referential Transparency (f(x) = x +1 and not

    global x++) No side effects (such as state change and IO)
  11. Pure Functions in Practice Patterns not common for Java developers

    (Reader, Kleisli, Free Monads) No pure functional ecosystem in Java (such as scalaz, http4s, doobie in Scala)
  12. Immutability public class Person { private final String id; private

    final String firstname; private final String lastname; private final String ip; private final IpInfo ipInfo; // immutable inside private final javaslang.collection.List<Person> friends; // immutable // init constructor and only getters }
  13. Immutability in Practice Problems with reflection libraries: No default constructor

    for entity No interoperable immutable collections: Javaslang, Guava, JDK9 If done right another challenges come: builders, aggregates, lenses Has better support in Scala, Clojure, Kotlin
  14. Reactive REST API with Spring 5 WebFlux return RouterFunctions.route(POST("/person") .and(contentType(APPLICATION_JSON)),

    request -> { final Mono<Person> p = addPerson(request.bodyToMono(Person.class)); return ServerResponse.ok().body(p, Person.class); } );
  15. Enterprise Application Has some business logic Integrates with others Persists

    data Uses blocking implementations Data intensive Resilient Well-tested
  16. Data Intensive Processing with Backpressure LocalDateTime dateTime = LocalDateTime.now().minusDays(90); return

    repository.findByUpdatedAtLessThan(dateTime) .flatMap(this::updateIpInfo);
  17. Data Intensive Processing with Backpressure LocalDateTime dateTime = LocalDateTime.now().minusDays(90); return

    repository.findByUpdatedAtLessThan(dateTime) .buffer(300) // communicating demand .flatMap(this::updateIpInfo);
  18. Data Intensive Processing with Backpressure LocalDateTime dateTime = LocalDateTime.now().minusDays(90); return

    repository.findByUpdatedAtLessThan(dateTime) .buffer(300) // communicating demand .parallel(2) // speed-up execution .runOn(Schedulers.newParallel("updateIpInfoScheduler", 2)) .flatMap(this::updateIpInfo);
  19. Backpressure Async message consumption or big datasets bring backpressure need

    On backpressure stop demanding (pull-based backpressure) Otherwise drop messages or signal an error in controlled manner
  20. Enterprise Application Has some business logic Integrates with others Persists

    data Data intensive Uses blocking implementations Resilient Well-tested
  21. Non-Blocking SQL Drivers != JDBC Vert.x mysql-postgresql-client Mauricio postgresql-async Alaisi

    postgres-async-driver Outworkers Morpheus Finagle ROC Non-blocking JDBC in Java 10?
  22. Circuit Breaker Useful to provide your clients fail response fast

    (better UX) Useful when fallback available (such as fallback service provider) Useful to let your dependencies recover
  23. Circuit Breaker Example with resilience4j return Try.of(CircuitBreaker.decorateCheckedSupplier(circuitBreaker, () -> getIpInfo(ip)

    )).getOrElse(() -> getFallbackIpInfo(ip)) .map(this::parse) .onErrorReturn(EMPTY_IP_INFO);
  24. Circuit Breaker Example with resilience4j return Try.of(CircuitBreaker.decorateCheckedSupplier(circuitBreaker, () -> getIpInfo(ip).onErrorResume(t

    -> { circuitBreaker.onError(Duration.ZERO, t); return getFallbackIpInfo(ip); }) )).getOrElse(() -> getFallbackIpInfo(ip)) .map(this::parse) .onErrorReturn(EMPTY_IP_INFO);
  25. Testing Reactive Application You can block() in tests Use testing

    features of your reactive library (like reactor-test) Test your resilience (with or without tools like Netflix's Chaos Monkey) Load test with expected throughput
  26. Conclusions Never block to stay Reactive (flatMap them all) Using

    Blocking IO libraries (such as JDBC) still possible Non-blocking functional programming might give mental overhead Not every application has high enough throughput Blocking can still be resilient, responsive and fast Use Resilience Patterns (such as Bulkheads, Circuit Breaker)