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

JVM Reactive Programming

JVM Reactive Programming

Presentación sobre Reactive Programming en la JVM para el meetup JVM_MX.

Se mostraron conceptos sobre Reactive Programming y Functional Reactive Programming con la biblioteca RxJava de Netflix.

Domingo Suarez Torres

October 24, 2016
Tweet

More Decks by Domingo Suarez Torres

Other Decks in Programming

Transcript

  1. La idea de ‘Live’ • Reuniones intermedias entre cada meetup

    presencial en CDMX • Para desarrolladores que no pueden asistir • Para expositores nacionales o internacionales • Esfuerzo paralelo a las actividades de JVM_MX • YOLO
  2. Reactive Programming • “Reactive Programming” es programar con flujos de

    datos asíncronos. • Flujo de datos (Data Stream): Una secuencia de valores • Modelo de programación basado en el principio de empujar (push) en lugar de obtener (pull). • Los valores se “emiten” cuando están listos, no cuando se solicitan de una forma no-bloqueante (non-blocking) • Se permite ejecutar operaciones en paralelo en lugar de forma serial.
  3. Functional Reactive Programming • Functional programming • https://maryrosecook.com/blog/post/a-practical- introduction-to-functional-programming •

    Lleva a Reactive Programming al siguiente nivel. • Permute aplicar funciones al flujo de datos. • map, filter, zip, take, etc.. • Integra flujo de tiempo y los eventos de composición en la programación funcional.
  4. ReactiveX Reactive eXtensions • Creado en Microsoft por Erik Meijer

    • Colección de funciones útiles para hacer programación reactiva. • ReactiveX esta implementado en mas de 10 lenguajes. • RxJava es la implementación de ReactiveX, fue escrita por el equipo de Netflix
  5. ReactiveX • Observable: fuente de flujos de datos (sender). •

    Observer: Escucha los valores emitidos (receiver) • El Observer se suscribe (escucha) al Observable • Los Observers reaccionan a cualquier elemento o secuencias de elementos que emita el Observable • Muchos Observers pueden suscribirse al mismo Observable.
  6. Observable Observer Pattern • Permite operaciones concurrentes: el Observer no

    necesita bloquear mientras espera que el Observable emita valores • El Observer espera a recibir valores cuando el Observable esta listo para emitirlos • Sobre la base de empuje (push) en lugar de obtener (pull)
  7. RxJava • Proyecto Open Source con Licencia Apache. • Implementación

    en Java de ReactiveX de Microsoft • El API de Netflix la usa para hacer la capa de servicio completamente asíncrona. • El objetivo es la JVM no el lenguaje. • Existe soporte para Java, Groovy, Clojure, y Scala
  8. RxJava Features • Composable: Fácilmente se puede encadenar o combinar

    • Flexible: Se puede usar para emitir: • Un valor escalar (network result) • Secuencia (elementos en una lista) • Flujos infinitos (sensores de clima) • Mitiga el callback hell: Fácilmente se puede transformar un flujo asíncrono en otro
  9. Usando Iterables • Antes de reactivo 1. Invocar un método

    2. Esperar el resultado 3. Almacenar el resultado en una variable 4. Usar la variable para hacer algo util.
  10. Usando Observables 1. Definir un Observer que especifica que hacer

    con cada valor emitido 2. Invocar un método que regrese un Observable 3. Suscribirse el Observer al Observable. Esto le dice al Observable que tiene un subscriptor esperando a recibir valores cuando estén disponibles.
  11. En RxJava • El método Subscribe conecta un Observer a

    un Observable • Una ves suscrito, no hay necesidad de bloquear el hilo actual. • Los valores llegaran al Observer cuando estén listos y disponibles
  12. void onCompleted(); 
 /**
 * Notifies the Observer that the

    * {@link Observable} has finished sending * push-based notifications.
 * <p>
 * The {@link Observable} will not call * this method if it calls {@link #onError}.
 */
 void onCompleted();
  13. void onCompleted(); • El Observable invoca este método después de

    que se invocó el método onNext por ultima ocasión y no encontró ningún error. • La llamada a onComplete finaliza la subscripción.
  14. void onError(Throwable e); /**
 * Notifies the Observer that the

    {@link Observable} * has experienced an error condition.
 * <p>
 * If the {@link Observable} calls this method, it * will not thereafter call {@link #onNext} or
 * {@link #onCompleted}.
 * 
 * @param e
 * the exception encountered by the * Observable
 */
 void onError(Throwable e);
  15. void onError(Throwable e); • El Observable invoca este método para

    indicar que ha fallado al obtener la información esperada o alguno otro problema. • Esto detiene al Observable y no hará mas invocaciones. • Envía la excepción que genero el problema.
  16. void onNext(T t) /**
 * Provides the Observer with a

    new item to observe.
 * <p>
 * The {@link Observable} may call this method 0 or * more times.
 * <p>
 * The {@code Observable} will not call this method * again after it calls either {@link #onCompleted} * or {@link #onError}.
 * 
 * @param t
 * the item emitted by the Observable
 */
 void onNext(T t);
  17. void onNext(T t) • El Observable invoca este método cada

    vez que el Observable emite un elemento. • Este método puede ser invocado cualquier número de veces (de cero a muchos). • Siempre seguido por onError o onComplete (pero no ambos)
  18. Uso sencillo public Observable<Double> dollarToCurrencyExchangeRate(String targetCurrencyCode) {
 // se crea

    de alguna manera el Observable
 return ...
 } public void foo() {
 dollarToCurrencyExchangeRate("MXN")
 .subscribe(System.out::println);
 }
  19. Composing el Observable public void foo() {
 dollarToCurrencyExchangeRate("MXN")
 .throttleWithTimeout(2, TimeUnit.MINUTES)


    .distinctUntilChanged()
 .filter(value -> value > 0)
 .map(Object::toString)
 .subscribe(System.out::println);
 }

  20. ¿Como esta implementado el Observable? • ¿Tal vez ejecuta su

    lógica en el hilo del subscriptor? • ¿Tal vez delega parte del trabajo a otros hilos? • ¿Usará NIO? • ¿Tal vez es un actor? • ¿Devolverá datos de un cache? • ¡Al Observer no le importa!
  21. Consumiendo Observables Modo largo… 
 rx.Observable.just(1, 2, 3)
 .subscribe(new rx.Observer<Integer>()

    {
 @Override
 public void onCompleted() {
 System.out.println("No más elementos.");
 }
 
 @Override
 public void onError(Throwable e) {
 System.out.println(
 String.format("Ocurrio un problema: %s", e.getMessage()));
 }
 
 @Override
 public void onNext(Integer integer) {
 System.out.println(
 String.format("Valor recibido: %d", integer));
 }
 });
  22. Consumiendo Observables Modo corto Java 8. 
 rx.Observable.just(1, 2, 3)


    .subscribe(
 value ->
 System.out.println(
 String.format("Valor recibido: %d", value)),
 throwable ->
 System.out.println(
 String.format("Ocurrio un problema: %s",
 throwable.getMessage())),
 () -> System.out.println("No más elementos."));
  23. Operadores doOn* rx.Observable.just(1, 2, 3, 4, 5)
 .doOnNext(value -> {


    if (Integer.valueOf(4).equals(value)) {
 throw new RuntimeException("El cuatro es feo.");
 }
 })
 .doOnError(throwable -> System.out.println(
 String.format("Ocurrio un problema: %s",
 throwable.getMessage())))
 .doOnCompleted(() -> System.out.println("No más elementos."))
 .subscribe(value ->
 System.out.println(
 String.format("Valor recibido: %d", value)));
  24. Creando Observable de forma explicita. rx.Observable.<Integer>create(subscriber -> {
 try {


    for (int i = 0; i < 5; i++) {
 subscriber.onNext(i);
 }
 // Si olvidamos invocar onCompleted se
 // pueden crear Observables sin fin.
 subscriber.onCompleted();
 } catch (Throwable cause) {
 subscriber.onError(cause);
 }
 });
  25. Transformando data map rx.Observable.just(1, 2, 3, 4, 5)
 .map(value ->

    String .format("Value: %s", value.toString()))
 .subscribe(System.out::println);
  26. Backpressure • ¿Que ocurre si un Observable esta emitiendo elementos

    más rápido de lo que el Observer puede procesarlos? • Cold Observable: • Emite una secuencia particular de elementos, puede empezar a emitirla cuando su Observer lo considere conveniente y a la tasa de entrega que el Observer desee, sin interferir la integridad de la secuencia. • Hot Observable: • Es un Observable que empieza a generar elementos inmediatamente cuando es creado. Los subscriptores pueden empezar a observar la secuencia de elementos emitidos a la mitad de la secuencia, empezando con el primer elemento emitido posterior al establecimiento de la subscripción. Dicho Observable emite elementos a su propio ritmo y es responsabilidad de los Observers mantener ese mismo ritmo.
  27. List<Observable<byte[]>> observables =
 //obtengo todas las instancias de los servicios


    discoveryClient.getInstances("service_id").stream()
 //Obtengo su URI remota (host:port)
 .map(serviceInstance -> serviceInstance.getUri().toString())
 //Genera un Worker que hará el trabajo de pedirle //a cada instancia del servicio el archivo. //DownloadCacheWorker implementa java.util.concurrent.Callable
 .map(baseUrl -> new DownloadLocalCacheWorker(baseUrl, bucket, key))
 //Genero un Future para hacerlo asíncrono
 .map(callable -> ((ThreadPoolTaskExecutor) taskExecutor).submit(callable))
 //Lo convierto a Observable para facilitar //el manejo de errores
 .map(Observable::from)
 //Genero una lista de Observables
 .collect(Collectors.toList());
  28. 
 //Genero un solo Observable a partir de todos
 Observable.merge(observables)


    //Si algo falla al obtener el archivo del //servicio remoto, simplemente regreso null
 .onErrorReturn(throwable -> {
 log.warn("No se encontró algo", throwable);
 return null;
 }).doOnCompleted(() -> {})
 //Descarto todos los null
 .filter(fileContent -> fileContent != null)
 //obtengo el primer resultado exitoso //(en teoría solo debe existir en un solo servidor)
 .firstOrDefault(null)
 //hago la llamada bloqueante
 .toBlocking()
 //aplico la lógica de manejo del archivo
 .subscribe(new DownloadLocalCacheObserver(response, key, notFound));

  29. A seguir • Project Reactor • https://projectreactor.io/ • Akka •

    http://akka.io/ • Reactive Streams • http://www.reactive-streams.org/