Подтвердить что ты не робот

Можно ли использовать планировщик Akka внутри актера?

Я хочу иметь возможность заставить актеров спать некоторое время. Актеры должны сами решить, как долго они будут спать. Поскольку Thread.sleep() не рекомендуется для этого, я думал об использовании планировщика в akka. Поэтому я определил, что актер может зарегистрироваться для того, чтобы его проснулись.

class Scheduler extends Actor {

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

Но передающий актер никогда не получает сообщение "Кольцо". Поэтому мои вопросы:

  • Планируется ли планировщик, рекомендуемый внутри актера?
  • Почему передающий актер никогда не получает сообщение Ring?
  • Если это невозможно, то какой рекомендуемый способ решения проблемы?
4b9b3361

Ответ 1

Позвольте мне сначала ответить на вопрос заголовка: да, можно использовать планировщик внутри актера.

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

Теперь на вопрос, стоящий за вопросом

Вы не сказали то, что вы на самом деле хотите достичь, поэтому я делаю обоснованное предположение, что вы хотите, чтобы актер, который обычно делает что-то под названием "X", некоторое время называл "Y", X ". Полные решения этого были бы

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)
  }
}

То же самое можно было бы реализовать с использованием признака FSM и переключения между нормальным и спящим состоянием. И, конечно же, вы можете делать все, что хотите, во время сна, например. смешайте в Stash в Akka 2.1 и вызовите stash() для всех (или некоторых) сообщений во время сна, unstashAll() при получении сообщения WakeUp; или вы могли бы сделать что-то еще совсем. Актеры очень гибкие.

Какие актеры не делают

Актеры никогда не спят, они всегда обрабатывают входящие сообщения. Как показано выше, вы можете определить, что это значит, но основным принципом является то, что вы не можете приостановить действие актера, чтобы он не обрабатывал сообщения в своем почтовом ящике.

Ответ 2

Вы закрываете "отправителя" в своем закрытии, который передается планировщику. Это означает, что сообщение "Кольцо", скорее всего, отправляется не тому актеру. Вы должны сделать это вместо этого:

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

Ответ 3

Ответ Roland Kuhn охватывает тему, я просто хотел добавить, что существует другой общий вариант использования планировщика: при отправке сообщения другому актеру и ожидании ответа этого актера довольно часто, чтобы подождать ожидания с тайм-аутом.

otherActor ! Request(...)
context.system.scheduler.scheduleOnce(duration, self, WakeUp)
...
case Response(...) => ...
case WakeUp => context stop self