Programación reactiva
Introducción
La historia de las aplicaciones reactivas comenzó en los años 1970, cuando surgieron los primeros conceptos de programación funcional. Sin embargo, no fue hasta la década de los años 1990 cuando empezó a desarrollarse la idea de reactividad en el contexto de las aplicaciones informáticas. En 1997, la programación reactiva se introdujo por primera vez con la publicación de "The Reactive Manifesto". Este manifiesto define los principios fundamentales de la programación reactiva, como la resiliencia, la elasticidad, la extensibilidad y la reactividad.
A lo largo de los años, numerosos lenguajes de programación han adoptado conceptos de programación funcional para permitir el desarrollo de aplicaciones reactivas. En 2004, Martin Odersky creó Scala para combinar las ventajas de la programación orientada a objetos y la programación funcional en un único lenguaje. Con la aparición de lenguajes JVM más potentes como Groovy y Scala en la década de 2000, las aplicaciones reactivas encontraron un terreno propicio para su desarrollo. En efecto estos lenguajes facilitan y hacen más expresiva la construcción de aplicaciones reactivas.
En 2011, se lanzó el framework Akka, que introdujo el modelo de actor para gestionar el acceso concurrente y facilitar la creación de aplicaciones reactivas escalables....
Conceptos clave de la programación reactiva
Los conceptos clave de la programación reactiva son los siguientes:
-
Reactividad: la capacidad de respuesta es el concepto principal de la programación reactiva. Significa que el sistema es capaz de responder rápidamente a los eventos y peticiones, manteniendo una baja latencia y evitando tiempos de espera excesivos.
-
Resiliencia: la resiliencia se refiere a la capacidad del sistema para permanecer estable y funcional ante condiciones adversas, como errores, fallos de hardware o picos de carga. Las aplicaciones resilientes están diseñadas para gestionar los errores con elegancia y recuperarse rápidamente en caso de fallo.
-
Flexibilidad (elasticity): la flexibilidad es la capacidad de un sistema para adaptarse dinámicamente a la demanda ajustando sus recursos en función de la carga de trabajo. Las aplicaciones reactivas pueden escalar o reducirse de manera transparente para responder a las fluctuaciones de la demanda.
-
Orientado a mensajes (message-driven): la programación reactiva se basa en un modelo de comunicación asíncrono basado en el intercambio de mensajes entre los distintos componentes del sistema. Esto permite una comunicación flexible y descentralizada entre las entidades del sistema.
-
Programación funcional: la programación reactiva favorece la utilización de conceptos de programación funcional, tales como...
Reactive Streams
1. Orígenes
ReactiveX (también conocida como Reactive Extensions) es una biblioteca de software creada originalmente por Microsoft, que permite a los lenguajes de programación imperativos trabajar sobre secuencias de datos de forma síncrona o asíncrona. Proporciona un conjunto de operadores de secuencia que actúan sobre cada elemento de la secuencia. Esta implementación de la programación reactiva proporciona un modelo para crear herramientas compatibles con varios lenguajes de programación. En otras palabras, ReactiveX es una API de programación asíncrona basada en flujos de observaciones. Esto permite a los programadores llamar a funciones y esperar su ejecución mediante callbacks. Los flujos de observaciones son similares a los emisores de eventos, emitiendo eventos de next, error y complete. Una vez que un flujo emite un evento de error o complete, deja de emitir eventos a menos que se vuelva a suscribir.
Los observadores se suscriben a flujos de observaciones y reciben los elementos de manera asíncrona. ReactiveX combina las ideas de los motivos "observador" e "iterador" con la programación funcional. Los operadores de ReactiveX permiten crear flujos de observaciones, combinar los elementos emitidos por flujos internos y realizar operaciones, tales como transformar, reducir o agrupar datos. La biblioteca ReactiveX fue creada por el equipo...
Aplicaciones reactivas sin Reactor
Ya existían soluciones para crear aplicaciones Spring antes de la publicación del marco Reactor, con bibliotecas como:
-
Akka/Akka Stream
-
RxJava versiones 1, 2 y 3 con Vert.x
1. Akka
Aunque estos ecosistemas se pueden utilizar con Spring, tienen su propio ecosistema y se pueden utilizar por sí solos, sin Spring. Es la misma situación que ocurre con ecosistemas como AWS y Quarkus. RxJava y Spring pueden utilizarse juntos, pero la integración es parcial. RxJava ofrece funcionalidades que pueden utilizarse en Spring, pero la integración no es completa. Reactor, en cambio, ofrece una integración completa con Spring, desde la capa de exposición REST hasta la capa de almacenamiento Akka.
Para implementar una aplicación reactiva que haga, por ejemplo, event sourcing, con Akka, numerosos bloques de construcción y conceptos pueden ser utilizados:
-
Actores (actors): Akka se basa en el modelo de actores, que son entidades concurrentes y autónomas. Cada actor procesa los mensajes que se le envían de manera secuencial, lo que significa que los eventos pueden modelarse atómicamente.
-
Eventos (events): los eventos son mensajes que se envían a los actores para representar cambios de estado en el sistema. En el contexto del event sourcing, estos eventos representan eventos pasados en lugar de comandos para cambiar el estado actual.
-
Registro de Eventos...
Funcionamiento de Reactor
Hoy en día, para desarrollar aplicaciones reactivas con Spring, recomendamos utilizar Reactor. Reactor es una biblioteca de programación funcional que ofrece una integración total con el ecosistema Spring.
Las fuentes pueden consultarse en GitHub aquí: https://github.com/reactor
1. En interno
Internamente, Reactor Core utiliza un motor de ejecución basado en el modelo de máquina de estados finitos para gestionar el flujo de datos y las operaciones de transformación. Esto optimiza la utilización de recursos y garantiza una ejecución eficiente de las operaciones asíncronas.
Su motor de ejecución interno utiliza el modelo de máquina de estados finitos (FiniteStateMachine,FSM) para gestionar de forma optimizada el flujo de datos y las operaciones de transformación. El flujo de datos se representa como una secuencia de estados y las operaciones de transformación se representan como transiciones entre estos estados. Cada operación aplicada a un Flujo o a un Mono puede considerarse como una transición de un estado a otro.
Además, gracias a este modelo, las operaciones asíncronas pueden ejecutarse de forma eficiente y sin bloqueos. El motor de ejecución gestiona las transiciones entre los estados de forma asíncrona, lo que permite procesar los flujos de datos de manera reactiva, sin bloquear el hilo de ejecución principal.
Reactor Core utiliza una combinación de listeners de mensajes y schedulers internos para crear un entorno multitarea simulado utilizando un bucle de mensajes. Cuando una operación asíncrona se ejecuta, emite un mensaje que es recogido por un listener dedicado. Este listener procesa el mensaje y decide la siguiente acción a realizar en función del tipo de mensaje recibido. Este enfoque permite gestionar eficazmente los eventos de forma no bloqueante....