Hello World en Akka (Parte I)

Hoy vamos a cambiar un poco de tercio. Aprovechando el curso de programación reactiva que se está dando actualmente en Coursera, vamos a dar el primer paso para empezar a trabajar con Akka.

Akka es un toolkit del ecosistema Typesafe. Permite construir sistemas reactivos utilizando el modelo de actores. Existen dos versiones de Akka, una para Java y otra para Scala. Aquí nos centraremos, obviamente, en la segunda.

¿Qué es un actor?

Un actor es una entidad a la que se le pueden enviar mensajes. El actor reaccionará a los mensajes que le lleguen realizando acciones. Además, tiene dos peculiaridades:

  • No se puede acceder al interior del actor desde fuera de él. Para interactuar con el actor solo se pueden enviar mensajes.
  • Los mensajes que lleguen al actor se procesarán de uno en uno

Para construir un actor en Akka, haciendo un esfuerzo histórico de comprensión, simplemente hay que extender del trait Actor.

Si queremos tener el actor completamente definido tendremos que concretar su comportamiento. Para ello hay que implementar el método receive del actor. En él definiremos cual será la reacción del actor a los distintos mensajes que le vayan llegando.

Pero antes de continuar toca dar paso a Íñigo con un briconsejo

briconsejo

Briconsejo: Funciones parciales

Las PartialFunction (o funciones parciales), son funciones que solo están definidas para un conjunto limitado de argumentos. Desde el punto de vista matemático, podríamos decir que su dominio está acotado. Pero realmente como se entiende este concepto es viendo un ejemplo sencillo:

def getCountry: PartialFunction[String, String] = {
  case "Madrid" => "Spain"
  case "Paris" => "France"
  case "Roma" => "Italy"
}

En este caso, la función getCountry solo devolverá el país de las capitales definidas en la función parcial. En caso de utilizar otra capital como parámetro de entrada, la función devolverá un MatchError.

getCountry("Madrid") //returns "Spain";
getCountry("Berlin") //throws MatchError

Además, las funciones parciales tienen un método llamado isDefinedAt que nos permite saber si un parámetro de entrada está contemplado en su cuerpo. En nuestro caso:

getCountry.isDefinedAt("Madrid") //returns true
getCountry.isDefinedAt("Berlin") //returns false

Otro truco importante es componer varias funciones parciales para crear una nueva. Para ello usaremos el método orElse:

def getCountryEurope: PartialFunction[String, String] = {
  case "Madrid" => "Spain"
  case "Paris" => "France"
  case "Roma" => "Italy"
}

def getCountryAmerica: PartialFunction[String, String] = {
  case "Brasilia" => "Brazil"
  case "Buenos Aires" => "Argentina"
}

def getCountry = 
  getCountryEurope orElse getCountryAmerica

getCountry.isDefinedAt("Madrid") //returns true
getCountry.isDefinedAt("Brasilia") //returns true

Y para finalizar la master class de PartialFunction, es importante conocer el método applyOrElse, con el que podremos evaluar una función parcial con un valor de entrada e incluir una función auxiliar que será utilizada en caso de que el valor de entrada no esté en el dominio. ¿Lo qué? Con un ejemplo se ve mucho mejor:

def unhandled(capital: String) = s"$capital is not defined"
getCountry.applyOrElse("Foo", unhandled) //Foo is not defined

Actor Hello World

¡Bien! Ahora que sabemos lo que son las funciones parciales, ya podríamos definir nuestro método receive en el actor, que es el que indicará el comportamiento de un actor. Dicho método receive, como habréis podido deducir, realmente es una función parcial.

type Receive = PartialFunction[Any, Unit]

def receive: Receive

Dicha función parcial espera cualquier tipo como parámetro de entrada y devuelve Unit. Por lo tanto, gracias al tipo de argumento Any, podemos enviar como mensaje a un actor cualquier cosa: un string, un entero, un objeto …

def receive {
  case num: Int => println(s"Num $num received")
  case words: String => println(s"String $words received")
  case _ => println("I've received other thing")
}

Además, es importante saber que cuando llega un mensaje a un actor primero se intenta aplicar a la función parcial que hemos definido en el método receive y, en caso de no estar definido en el dominio, se ejecutará el método unhandled:

def unhandled(msg: Any): Unit

Dicho método, por defecto, imprimirá los mensajes que no han sido manejados en un log. De esta manera, si un mensaje no está contemplado en el método receive, en vez de causar un MatchError y hacer que nuestro programa explote por los aires, imprimirá una traza en el log de Akka. Utilizando los conocimientos de nivel supremo que ya tenemos de PartialFuncion podemos adivinar que el comportamiento de un actor para un mensaje llamado msg estará definido de esta forma:

receive.applyOrElse(msg, unhandled)

Solo queda definir el actor, que en nuestro caso, independientemente del mensaje que le llegue, imprimiremos un Hello World bello y apasionado:

class HelloWorldActor extends Actor {
  
  def receive {
    case _ => println("Hello World!")
  }
}

¡Voila! En el siguiente post veremos como podemos utilizar este actor y como ponerlo en funcionamiento.

Anuncios

One thought on “Hello World en Akka (Parte I)

Responder

Introduce tus datos o haz clic en un icono para iniciar sesión:

Logo de WordPress.com

Estás comentando usando tu cuenta de WordPress.com. Cerrar sesión / Cambiar )

Imagen de Twitter

Estás comentando usando tu cuenta de Twitter. Cerrar sesión / Cambiar )

Foto de Facebook

Estás comentando usando tu cuenta de Facebook. Cerrar sesión / Cambiar )

Google+ photo

Estás comentando usando tu cuenta de Google+. Cerrar sesión / Cambiar )

Conectando a %s