«Tercer y último artículo sobre Akka explicado mediante ejemplos.
En los dos anteriores se basó en como funcionan la cola de mensajes de un actor, que es un router, como se envían mensajes entre actores. Después se trató temas como la supervisión y el bus de eventos.
Ahora me centraré en los actores tipados.«
Entrada anterior: Akka por ejemplos. Sobre supervisión, bus de eventos, …
Todo el código fuente relacionado con esta serie de posts está disponible en mi repositorio de GitHub
AkkaActorsAndFutures
Actores tipados
Los actores tipados son una funcionalidad que ofrece Akka recubriendo un actor no tipado en un interfaz java. Con un actor tipado el programador realiza llamadas a un método de una clase normal ‘sin preocuparse‘ (y pongo esto entre comillas por lo que veremos más adelante) de lo que está detrás es un actor de Akka.
[Actor tipado]
Permite unir los dos mundos, código java estándar con el mundo de los actores. En la documentación de Akka puedes leer que tienen su nicho, pero hay que ‘usarlos con moderación‘. Recomiendan que si lo que buscas es una arquitectura de alta escalabilidad utilizar estos actores no es la solución más sencilla. Por ejemplo en este caso, aunque se puede, no es tan natural la supervisión y la monitorización padre-hijo.
Para los actores tipados, Akka utiliza el patrón de Objetos Activos y proxys de Java. Para levantar un actor tipado es necesario una interfaz y una implementación. Simplificando, en los actores tipados no existe el método ‘onReceive()‘ y se utilizan como un clase más de Java haciendo llamadas a los métodos que exporta la interfaz.
En realidad lo que hay detrás es un actor no tipado. Akka monta un proxy en el que el interfaz será la fachada y el ‘contrato público‘ que podrá utilizar el resto del código java. Los atributos de los métodos de ese interfaz serán los mensajes que se enviarán al actor y la implementación será la que dicte el comportamiento. Por lo demás se cumple con el modelo de actores que asegurá que no habrá más de un hilo ejecutando el actor.
Todo esto, que haya un actor detrás de este interfaz, hace que tenga un comportamiento diferente al esperado en una clase java, y hay que tenerlo en mente cuando se utilizan actores tipados.
Para los ejemplos se ha utilizado una clase TypedActorDummyImp que implementa el interfaz TypedActorDummy con una serie de métodos sencillos que permitirán ver con facilidad el funcionamiento de los actores tipados.
He creado dos test, uno TypedActorDummyImpTest.java que comprueba el comportamiento en una llamada normal a un método con diferentes tipos de retorno y otro TypedActorDummyImpExceptionsTest.java para ver cual será su comportamiento si se produce una excepción.
Comportamiento según el tipo de retorno.
Un método puede devolver tres tipos de respuesta: o bien es un método que no devuelve nada (void), o devuelve un objeto, o bien devuelve un futuro de objeto.
Cuando un método devuelve no devuelve nada: void
Cuando un actor tipado el tipo de respuesta es ‘void‘, lo que está ocurriendo es que se está mandando un mensaje del tipo dispara y olvida (‘fire-forget‘). En realidad se está enviado un mensaje ‘tell‘ al actor que hay por detrás, y no se espera respuesta.
Esto hace que tenga un comportamiento un poco ‘diferente‘ del esperado y es algo que se puede comprobar en los dos ejemplos.
Test 1: Llamada normal
Comando maven
mvn -Dtest=com.logicaalternativa.examples.akka.typed.TypedActorDummyImpTest#testReturnVoidWithSleep test
En este test se levanta un actor tipado que tiene un método que devuelve
void. Se simula una operación costosa con un “
Thread.sleep”.
Se comprueba que no se espera a la ejecución del método, sino que se continua inmediatamente con la siguiente orden. El mensaje se ha encolado al actor y este ejecutará la implementación en segundo plano, sin ningún tipo de espera en el hilo principal.
Test 2: Cuando se produce una excepción
Comando maven
mvn -Dtest=com.logicaalternativa.examples.akka.typed.TypedActorDummyImpExceptionsTest#testRuntimeExceptionVoid test
Como consecuencia de que el mensaje es enviado al actor, ejecutándose en un segundo plano, el hilo principal no es capaz de saber si ha ocurrido un error en la ejecución. Si se produce una excepción no será recogida desde la llamada al método.
El test anterior permite hacer esta comprobación y es bastante didáctico.
Cuando un método devuelve un futuro
Test 1: Llamada normal
Comando maven
mvn -Dtest=com.logicaalternativa.examples.akka.typed.TypedActorDummyImpTest#testFutureEcho test
Cuando se llama a un método de un actor tipado que devuelve un futuro, el comportamiento sería el mismo que si se enviara un mensaje de
petición y respuesta no bloqueante. Es el equivalente al envío de un mensaje con ‘
Patterns.ask(…)’ de un actor no tipado.
Por lo tanto la respuesta se recogerá cuando se resuelve el futuro y no desde la llamada al método. El hilo principal continuaría su ejecución sin esperar.
Test 2: Cuando se produce una excepción
Comando maven
mvn -Dtest=com.logicaalternativa.examples.akka.typed.TypedActorDummyImpExceptionsTest#testRuntimeExceptionFuture test
Lo mismo pasaría si se produjera una
excepción, sería
devuelta en la resolución del futuro y no sería recogida en la llamada al método tipado. Esto entra dentro de lo lógico si pensamos que cuando se produce el error es en el momento en el que se procesa el mensaje por parte del actor.
Cuando un método devuelve un objeto
Test 1: Llamada normal
Comando maven
mvn -Dtest=com.logicaalternativa.examples.akka.typed.TypedActorDummyImpTest#testEcho test
Test 2: Cuando se produce una excepción
Comando maven
mvn -Dtest=com.logicaalternativa.examples.akka.typed.TypedActorDummyImpExceptionsTest#testRuntimeExceptionString test
Cuando se llama a un método de un actor tipado que devuelve un objeto, el comportamiento es ‘
parecido‘ al esperado. Y digo ‘
parecido‘ porque en realidad lo que se está haciendo es enviando el mensaje al actor y esperando la respuesta (siguiendo un patrón de p
etición-respuesta bloqueante)
Por lo tanto desde la llamada al método de un actor tipado hace que hilo de ejecución principal espere la respuesta (aunque por detrás se esté enviando un mensaje ejecutándose en otro ‘hilo’). Por lo tanto el comportamiento es ‘el mismo’ al acostumbrado (ver el ejemplo 1). En este caso si se produce una excepción si será recogida en la llamada al método (Ver test 2)
Como conclusión final de esta serie de posts decir que aunque el modelo de actores y Akka presentan nuevos conceptos, estos una vez aprendidos son sencillos de asimilar.
A cambio ofrece un modo elegante y sencillo de codificar aplicaciones que soporten programación paralela que sean escalables, robustas y de alta disponibilidad.
Espero que os sirva.
M.E.