jvm reactive programming

52
JVM Reactive Programming Mexico City JVM Group October 2016 domix domix coderDog

Upload: domingo-suarez-torres

Post on 15-Apr-2017

850 views

Category:

Technology


1 download

TRANSCRIPT

JVM Reactive ProgrammingMexico City JVM Group

October 2016

domix domix coderDog

!Gracias por estar aqui¡

!Ya estamos en vivo¡

bit.ly/jm_live

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

Anuncio parroquial

Nuevo libro por Javeros Mexicanos

Raul Estrada (@BusinessRul) Isaac Ruiz Guerra (@rugi)

bit.ly/book_smack

Reactive Programming

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.

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.

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

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.

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)

RxJava

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

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

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.

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.

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

Interface rx.Observer

public interface rx.Observer<T> {

void onCompleted(); void onError(Throwable e); void onNext(T t);}

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();

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.

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);

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.

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);

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)

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);}

Composing el Observable

public void foo() { dollarToCurrencyExchangeRate("MXN") .throttleWithTimeout(2, TimeUnit.MINUTES) .distinctUntilChanged() .filter(value -> value > 0) .map(Object::toString) .subscribe(System.out::println); }

¿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!

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)); } });

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."));

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)));

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); } });

Como crear Observables

Manipulando Observable

Transformando data map

rx.Observable.just(1, 2, 3, 4, 5) .map(value -> String .format("Value: %s", value.toString())) .subscribe(System.out::println);

Combinando Observables

Filtrando

Limitando elementos

Ejercicio 1 Implementar la kata

FizzBuzz

http://codingdojo.org/cgi-bin/index.pl?KataFizzBuzz

https://en.wikipedia.org/wiki/Fizz_buzz

Hasta el número 20

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.

Debounce

throttleFirst

throttleWithTimeout

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());

//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));

A seguir• Project Reactor

• https://projectreactor.io/

• Akka

• http://akka.io/

• Reactive Streams

• http://www.reactive-streams.org/