¿Es posible usar el programador Akka dentro de un actor?


Quiero tener la posibilidad de poner a los actores a dormir por un tiempo. Los actores deben decidir por sí mismos cuánto tiempo van a dormir. Como Hilo.sleep() no es una forma recomendada de hacer esto Pensé en usar el programador en akka. Por lo tanto, definí un actor donde otro actor puede registrarse para ser despertado.

class Scheduler extends Actor {

  def receive = {
    case Sleep(duration) => context.system.scheduler.scheduleOnce(duration) {
      sender ! Ring
    }
  }
}

Pero el actor que envía nunca recibe el mensaje del Anillo. Así que mis preguntas son

  • Está programando con el scheduler recomendado dentro de un ¿actor?
  • ¿Por qué el actor que envía nunca recibe el mensaje del Anillo?
  • Si esto no es posible, ¿cuál es la forma recomendada de resolver el problema?
Author: Felix Reckers, 2012-12-16

3 answers

Permítanme responder primero a la pregunta del título: sí, es posible usar el scheduler dentro de un actor.

case Sleep(duration) =>
  context.system.scheduler.scheduleOnce(duration, self, Ring)

Ahora a la pregunta detrás de la pregunta

No dijiste lo que realmente quieres lograr, así que estoy haciendo una suposición educada aquí de que quieres que el actor-que normalmente hace algo llamado "X"-haga algo llamado "Y" por un tiempo, suspendiendo la actividad "X". Las soluciones completas a esto serían

class Sleepy extends Actor {
  def receive = {

    ... // cases doing “X”

    case Sleep(duration) =>
      case object WakeUp
      context.system.scheduler.scheduleOnce(duration, self, WakeUp)
      context.become({
        case WakeUp => context.unbecome()
        // drop the rest
      }, discardOld = false)
  }
}

Lo mismo también podría implementarse utilizando el Rasgo de FSM y cambio entre el estado normal y el estado de sueño. Y, por supuesto, puedes hacer lo que quieras mientras duermes, por ejemplo, mezclar el rasgo Stash en Akka 2.1 y llamar stash() para todos (o algunos) mensajes mientras duermes, unstashAll() cuando recibas el mensaje WakeUp; o podrías hacer algo más. Los actores son muy flexibles.

Lo que los actores no hacen

Los actores nunca duermen realmente, siempre manejan los mensajes entrantes. Como se muestra arriba, puede definir lo que eso significa, pero el el principio básico es que no se puede suspender a un actor de tal manera que no procese los mensajes en su buzón.

 43
Author: Roland Kuhn,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-12-16 07:47:01

Está cerrando sobre "remitente" en su cierre que se pasa al programador. Esto significa que lo más probable es que el mensaje del Anillo se envíe al actor equivocado. Usted debe hacer esto en su lugar:

case Sleep(duration) => 
  val s = sender
  context.system.scheduler.scheduleOnce(duration) {
    s ! Ring
  }
}
 16
Author: Ryan LeCompte,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-12-15 22:21:20

La respuesta de Roland Kuhn cubre el tema, solo quería agregar que hay otro caso de uso común para usar el scheduler: al enviar un mensaje a un actor diferente y esperar a que este actor responda, es bastante común limitar la espera con un tiempo de espera.

otherActor ! Request(...)
context.system.scheduler.scheduleOnce(duration, self, WakeUp)
...
case Response(...) => ...
case WakeUp => context stop self
 0
Author: Eyal Farago,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-05-04 19:14:27