Akka es un toolkit y runtime para construir aplicaciones concurrentes, distribuidas y resilientes en la JVM (Java Virtual Machine). Akka se basa en el modelo de actores, que proporciona una abstracción de alto nivel para la concurrencia y la paralelización.
Objetivos de Aprendizaje
Al final de esta sección, deberías ser capaz de:
- Comprender los conceptos básicos del modelo de actores.
- Crear y gestionar actores en Scala utilizando Akka.
- Enviar y recibir mensajes entre actores.
- Manejar el ciclo de vida de los actores.
- Implementar patrones comunes de concurrencia y paralelización con Akka.
- Conceptos Básicos del Modelo de Actores
¿Qué es un Actor?
Un actor es una entidad que:
- Tiene un estado privado.
- Puede recibir mensajes.
- Puede enviar mensajes a otros actores.
- Puede crear nuevos actores.
Ventajas del Modelo de Actores
- Encapsulamiento de Estado: Cada actor tiene su propio estado privado, lo que evita problemas de concurrencia.
- Escalabilidad: Los actores pueden ser distribuidos en múltiples nodos.
- Resiliencia: Los actores pueden supervisar a otros actores y reiniciarlos en caso de fallo.
- Configuración del Proyecto
Para empezar a trabajar con Akka en Scala, necesitas configurar tu proyecto. Aquí te mostramos cómo hacerlo utilizando SBT (Scala Build Tool).
build.sbt
name := "AkkaIntroduction" version := "0.1" scalaVersion := "2.13.6" libraryDependencies += "com.typesafe.akka" %% "akka-actor-typed" % "2.6.16"
- Creación de Actores
Definición de un Actor
Para definir un actor en Akka, necesitas extender la clase AbstractBehavior y definir cómo manejar los mensajes.
import akka.actor.typed.Behavior
import akka.actor.typed.scaladsl.Behaviors
object HelloWorldActor {
final case class Greet(whom: String)
def apply(): Behavior[Greet] = Behaviors.receive { (context, message) =>
context.log.info("Hello, {}!", message.whom)
Behaviors.same
}
}Creación y Ejecución de un Actor
Para crear y ejecutar un actor, necesitas un ActorSystem.
import akka.actor.typed.ActorSystem
object HelloWorldApp extends App {
val system: ActorSystem[HelloWorldActor.Greet] = ActorSystem(HelloWorldActor(), "hello")
system ! HelloWorldActor.Greet("World")
}
- Comunicación entre Actores
Envío de Mensajes
Los actores se comunican enviando mensajes. Puedes enviar un mensaje a un actor utilizando el operador !.
Recepción de Mensajes
La recepción de mensajes se maneja en el método Behaviors.receive.
def apply(): Behavior[Greet] = Behaviors.receive { (context, message) =>
context.log.info("Hello, {}!", message.whom)
Behaviors.same
}
- Ciclo de Vida de los Actores
Creación y Terminación
Los actores pueden crear otros actores y también pueden ser terminados.
Supervisión
Los actores pueden supervisar a otros actores y tomar acciones en caso de fallo.
val supervisor = Behaviors.supervise(HelloWorldActor()).onFailure[Exception](SupervisorStrategy.restart)
- Patrones Comunes
Patrón de Mensajería
Un patrón común es el uso de mensajes para coordinar tareas entre actores.
object Counter {
sealed trait Command
case object Increment extends Command
case object Decrement extends Command
case class GetCount(replyTo: ActorRef[Count]) extends Command
case class Count(value: Int)
def apply(): Behavior[Command] = counter(0)
private def counter(count: Int): Behavior[Command] = Behaviors.receiveMessage {
case Increment =>
counter(count + 1)
case Decrement =>
counter(count - 1)
case GetCount(replyTo) =>
replyTo ! Count(count)
Behaviors.same
}
}Ejemplo de Uso
val counter: ActorRef[Counter.Command] = system counter ! Counter.Increment counter ! Counter.GetCount(replyTo = system)
Ejercicio Práctico
Ejercicio
Crea un sistema de actores que simule un sistema de chat simple. Debe haber un actor ChatRoom que maneje múltiples actores User. Los usuarios pueden enviar mensajes al ChatRoom, y el ChatRoom debe reenviar estos mensajes a todos los usuarios conectados.
Solución
object ChatRoom {
sealed trait Command
case class Join(user: ActorRef[User.Command]) extends Command
case class Leave(user: ActorRef[User.Command]) extends Command
case class SendMessage(message: String) extends Command
def apply(): Behavior[Command] = Behaviors.setup { context =>
var users = Set.empty[ActorRef[User.Command]]
Behaviors.receiveMessage {
case Join(user) =>
users += user
Behaviors.same
case Leave(user) =>
users -= user
Behaviors.same
case SendMessage(message) =>
users.foreach(_ ! User.ReceiveMessage(message))
Behaviors.same
}
}
}
object User {
sealed trait Command
case class ReceiveMessage(message: String) extends Command
def apply(name: String): Behavior[Command] = Behaviors.receive { (context, message) =>
message match {
case ReceiveMessage(msg) =>
context.log.info(s"[$name] received message: $msg")
Behaviors.same
}
}
}
object ChatApp extends App {
val system: ActorSystem[ChatRoom.Command] = ActorSystem(ChatRoom(), "chatRoom")
val user1 = system.systemActorOf(User("Alice"), "user1")
val user2 = system.systemActorOf(User("Bob"), "user2")
system ! ChatRoom.Join(user1)
system ! ChatRoom.Join(user2)
system ! ChatRoom.SendMessage("Hello everyone!")
}Conclusión
En esta sección, hemos cubierto los conceptos básicos de Akka y el modelo de actores. Aprendiste a crear y gestionar actores, enviar y recibir mensajes, y manejar el ciclo de vida de los actores. También implementaste un patrón común de mensajería y un ejercicio práctico para reforzar los conceptos aprendidos. Con estos conocimientos, estás preparado para explorar más a fondo las capacidades de Akka y construir aplicaciones concurrentes y distribuidas robustas.
Curso de Programación en Scala
Módulo 1: Introducción a Scala
- Introducción a Scala
- Configuración del Entorno de Desarrollo
- Conceptos Básicos de Scala: Sintaxis y Estructura
- Variables y Tipos de Datos
- Operaciones Básicas y Expresiones
Módulo 2: Estructuras de Control y Funciones
- Sentencias Condicionales
- Bucles e Iteraciones
- Funciones y Métodos
- Funciones de Orden Superior
- Funciones Anónimas
Módulo 3: Colecciones y Estructuras de Datos
- Introducción a las Colecciones
- Listas y Arreglos
- Conjuntos y Mapas
- Tuplas y Opciones
- Coincidencia de Patrones
Módulo 4: Programación Orientada a Objetos en Scala
- Clases y Objetos
- Herencia y Rasgos
- Clases Abstractas y Clases Caso
- Objetos Compañeros
- Objetos Singleton
Módulo 5: Programación Funcional en Scala
- Inmutabilidad y Funciones Puras
- Estructuras de Datos Funcionales
- Mónadas y Funtores
- Comprensiones For
- Manejo de Errores en Programación Funcional
Módulo 6: Conceptos Avanzados de Scala
- Conversiones y Parámetros Implícitos
- Clases de Tipo y Polimorfismo
- Macros y Reflexión
- Concurrencia en Scala
- Introducción a Akka
