try manejo excepciones catch java system.reactive reactive-programming rx-java

catch - manejo de excepciones en java



¿Cómo manejar las excepciones lanzadas por el observador enNext en RxJava? (1)

Considere el siguiente ejemplo:

Observable.range(1, 10).subscribe(i -> { System.out.println(i); if (i == 5) { throw new RuntimeException("oops!"); } }, Throwable::printStackTrace);

Esto genera números del 1 al 5 y luego imprime la excepción.

Lo que quiero lograr es que el observador permanezca suscrito y continúe ejecutándose después de lanzar una excepción, es decir, imprima todos los números del 1 al 10.

He intentado usar retry() y otros diversos operadores de manejo de errores , pero, como se dijo en la documentación, su propósito es manejar los errores emitidos por el observable en sí.

La solución más sencilla es envolver todo el cuerpo de onNext en un bloque try-catch, pero no me parece una buena solución. En la pregunta Rx.NET similar , la solución propuesta era hacer un método de extensión que hiciera el ajuste creando un proxy observable. Intenté rehacerlo:

Observable<Integer> origin = Observable.range(1, 10); Observable<Integer> proxy = Observable.create((Observable.OnSubscribe<Integer>) s -> origin.subscribe(i -> {try { s.onNext(i); } catch (Exception ignored) {}}, s::onError, s::onCompleted)); proxy.subscribe(i -> { System.out.println(i); if (i == 5) { throw new RuntimeException("oops!"); } }, Throwable::printStackTrace);

Esto no cambia nada, porque RxJava envuelve al suscriptor en un SafeSubscriber . Usar unsafeSubscribe para unsafeSubscribe tampoco parece ser una buena solución.

¿Qué puedo hacer para resolver este problema?


Esta es una pregunta común que surge al aprender Rx.

TL; DR

Su sugerencia de poner su lógica de manejo de excepciones en el suscriptor es preferible a la creación de un contenedor genérico observable.

Explicación

Recuerde, que Rx se trata de enviar eventos a los suscriptores.

Desde la interfaz observable, está claro que realmente no hay nada que un observable pueda saber sobre sus suscriptores, aparte del tiempo que tardaron en manejar un evento, o la información contenida en las excepciones lanzadas.

Una envoltura genérica para manejar las excepciones del suscriptor y continuar enviando eventos a ese suscriptor es una mala idea.

¿Por qué? Bueno, el observable solo debe saber realmente que el suscriptor se encuentra ahora en un estado de falla desconocido. Seguir con el envío de eventos en esta situación es imprudente: tal vez, por ejemplo, el suscriptor se encuentre en una condición en la que todos los eventos a partir de este momento generen una excepción y demoren un tiempo en hacerlo.

Una vez que un suscriptor ha lanzado una excepción, solo hay dos cursos de acción viables para el observable:

  • Vuelva a lanzar la excepción
  • Implemente el manejo genérico para registrar el error y detenga el envío de eventos (de cualquier tipo) y limpie los recursos debidos a ese suscriptor y continúe con las suscripciones restantes.

El manejo específico de las excepciones del suscriptor sería una mala elección de diseño; crearía un acoplamiento de comportamiento inapropiado entre el suscriptor y lo observable. Por lo tanto, si desea ser resistente a los malos suscriptores, las dos opciones anteriores son realmente el límite razonable de responsabilidad del observable en sí.

Si desea que su suscriptor sea ​​resistente y continúe, entonces debe envolverlo con la lógica de manejo de excepciones diseñada para manejar las excepciones específicas de las que sabe cómo recuperarse (y tal vez para manejar las excepciones transitorias, el registro, la lógica de reintento, el corte de circuitos, etc.). .).

Solo el suscriptor tendrá el contexto para entender si está en condiciones de recibir más eventos en caso de falla.

Si su situación justifica el desarrollo de una lógica de manejo de errores reutilizables, piense en envolver los controladores de eventos del observador en lugar de los observables , y tenga cuidado de no continuar transmitiendo eventos a ciegas ante el fracaso. ¡Liberarlo! Si bien no está escrito sobre Rx, es un entretenido software de ingeniería clásico que tiene mucho que decir sobre este último punto. Si no lo has leído, te lo recomiendo encarecidamente.