(Обратите внимание, что эта рецензия на жизненный цикл не охватывает preRestart
ни postRestart
методы, ни методы. Мы поговорим о них, когда будем обсуждать надзор)
Основной жизненный цикл актера очень интуитивно понятен. Фактически вы можете сравнить базовый жизненный цикл Actor с жизненным циклом Java-сервлета с одним специальным отличием.
- Как и в любом другом обычном классе, у нас есть конструктор
preStart
Метод вызывается обратно в следующем. Здесь вы можете инициализировать ресурсы, которые вы хотите очистить вpostStop
- «Обслуживание» или обработка сообщений
receive
методом занимает большую часть времени, и это происходит между ними.
Давайте посмотрим на простого актера, который печатает жизненный цикл.
DUMB LIFECYCLE ACTOR
package me.rerun.akkanotes.lifecycle import akka.actor.{ActorLogging, Actor} import akka.event.LoggingReceive class BasicLifecycleLoggingActor extends Actor with ActorLogging{ log.info ("Inside BasicLifecycleLoggingActor Constructor") log.info (context.self.toString()) override def preStart() ={ log.info("Inside the preStart method of BasicLifecycleLoggingActor") } def receive = LoggingReceive{ case "hello" => log.info ("hello") } override def postStop()={ log.info ("Inside postStop method of BasicLifecycleLoggingActor") } }
ПРИЛОЖЕНИЕ
В LifecycleApp
только посвящённые, посылает сообщение Актера и выключит ActorSystem.
import akka.actor.{ActorSystem, Props} object LifecycleApp extends App{ val actorSystem=ActorSystem("LifecycleActorSystem") val lifecycleActor=actorSystem.actorOf(Props[BasicLifecycleLoggingActor],"lifecycleActor") lifecycleActor!"hello" //wait for a couple of seconds before shutdown Thread.sleep(2000) actorSystem.shutdown() }
ВЫХОД
Inside BasicLifecycleLoggingActor Constructor Actor[akka://LifecycleActorSystem/user/lifecycleActor#-2018741361] Inside the preStart method of BasicLifecycleLoggingActor hello Inside postStop method of BasicLifecycleLoggingActor
В чем особая разница между сервлетами и базовым жизненным циклом актера?
Нет никакой разницы между конструктором и предварительным запуском в жизненном цикле Actor — более или менее.
Причина, по которой я напечатал context.self
в конструкторе, заключается в следующем — в отличие от сервлетов, актеры имеют доступ к ActorContext
четным внутри конструктора. Разница между preStart и конструктором становится очень тонкой. Мы еще вернемся к разнице, пока будем говорить о надзоре, но, если вам интересно, preStart
можно контролировать вызов, когда перезапускается Актер (в случае сбоя). С конструктором это невозможно.
КОГДА ВЫЗЫВАЕТСЯ ПОСТПОСТ?
Как мы видели из программы, postStop
вызывается, когда ActorSystem выключается. Есть несколько других случаев, когда обратный вызов тоже вызывается.
1. ACTORSYSTEM.STOP ()
Мы могли бы остановить актера, используя stop
метод ActorSystem
и ActorContext
object LifecycleApp extends App{ val actorSystem=ActorSystem("LifecycleActorSystem") val lifecycleActor=actorSystem.actorOf(Props[BasicLifecycleLoggingActor],"lifecycleActor") actorSystem.stop(lifecycleActor); ... ... }
2. ACTORCONTEXT.STOP
1) Либо посредством сообщения (извне или передачи сообщения себе)
class BasicLifecycleLoggingActor extends Actor with ActorLogging{ ... ... def receive = LoggingReceive{ case "hello" => log.info ("hello") case "stop" => context.stop(self) }
и
object LifecycleApp extends App{ val actorSystem=ActorSystem("LifecycleActorSystem") val lifecycleActor=actorSystem.actorOf(Props[BasicLifecycleLoggingActor],"lifecycleActor") lifecycleActor!"stop" ... ...
2) ИЛИ убивать себя без причины (это просто для развлечения. Ни один актер с амбициями не сделает этого)
class BasicLifecycleLoggingActor extends Actor with ActorLogging{ log.info ("Inside BasicLifecycleLoggingActor Constructor") log.info (context.self.toString()) context.stop(self) ... ...
3. Пуазон
В предыдущем примере мы передали сообщение с именем stop из LifecycleApp в Actor. Актер получил это сообщение и убил себя, используя context.stop
. Мы могли бы достичь того же, передав сообщение PoisonPill целевому субъекту . Обратите внимание, что PoisonPill
сообщение, как и предыдущее сообщение об остановке, помещается в обычный почтовый ящик и будет обработано при его появлении.
object LifecycleApp extends App{ val actorSystem=ActorSystem("LifecycleActorSystem") val lifecycleActor=actorSystem.actorOf(Props[BasicLifecycleLoggingActor],"lifecycleActor") lifecycleActor!PoisonPill ... ...
TRIVIA
Что я имею в виду обычный почтовый ящик? Есть ли «специальный» почтовый ящик тоже? Ага. Есть. И мы поговорим об этом, когда будем говорить об этом, когда будем обсуждать вопросы надзора и system
сообщений.
ПРЕКРАЩЕНИЕ
Как только Актер остановлен, говорят, что он входит в Terminated
состояние. Непосредственный вопрос, который возникнет у вас на уме: что произойдет с сообщениями, которые отправляются действующему субъекту?
Давайте посмотрим, что:
ПРИЛОЖЕНИЕ
object LifecycleApp extends App{ val actorSystem=ActorSystem("LifecycleActorSystem") val lifecycleActor=actorSystem.actorOf(Props[BasicLifecycleLoggingActor],"lifecycleActor") lifecycleActor!"hello" lifecycleActor!"stop" lifecycleActor!"hello" //Sending message to an Actor which is already stopped }
ACTOR — ПРОСТО КАК ДО
class BasicLifecycleLoggingActor extends Actor with ActorLogging{ def receive = LoggingReceive{ case "hello" => log.info ("hello") case "stop" => context.stop(self) } }
ВЫХОД
BasicLifecycleLoggingActor - hello akka.actor.RepointableActorRef - Message [java.lang.String] from Actor[akka://LifecycleActorSystem/deadLetters] to Actor[akka://LifecycleActorSystem/user/lifecycleActor#-569230546] was not delivered. [1] dead letters encountered. This logging can be turned off or adjusted with configuration settings 'akka.log-dead-letters' and 'akka.log-dead-letters-during-shutdown'.
Из журналов вы видите, что есть некоторые ссылки на deadletters
. Любое сообщение, которое вы отправляете прекращенному действующему субъекту, пересылается в почтовый ящик внутреннего действующего субъекта с именем DeadLetterActor .
Любопытно, что произойдет дальше?
DeadLetter Actor обрабатывает сообщения в своем почтовом ящике, упаковывает каждое сообщение как DeadLetter и публикует его в EventStream
.
Еще один Actor под названием DeadLetterListener потребляет все DeadLetter
s и публикует это как сообщение журнала. Проверьте аут .
Помните, когда мы говорили о ведении журнала , мы видели, что все сообщения журнала публикуются в EventStream и что мы можем подписаться на это EventStream — просто подписчик также должен быть актером. Давайте попробуем это сейчас.
В нашем примере мы подпишемся на EventStream, следим за всеми сообщениями DeadLetter и будем печатать на консоль (так много для творчества ?? !!). Честно говоря, мы можем делать что угодно, генерируя оповещения, сохраняя их в базе данных или даже добавляя аналитику.
ПОДПИСКА НА DEADLETTERS В EVENTSTREAM
import akka.actor.ActorSystem import akka.actor.Props import akka.actor.PoisonPill import akka.actor.DeadLetter import akka.actor.Actor object LifecycleApp extends App { val actorSystem = ActorSystem("LifecycleActorSystem") val lifecycleActor = actorSystem.actorOf(Props[BasicLifecycleLoggingActor], "lifecycleActor") val deadLetterListener = actorSystem.actorOf(Props(classOf[MyCustomDeadLetterListener])) actorSystem.eventStream.subscribe(deadLetterListener, classOf[DeadLetter]) lifecycleActor ! "hello" lifecycleActor ! "stop" lifecycleActor ! "hello" } class MyCustomDeadLetterListener extends Actor { def receive = { case deadLetter: DeadLetter => println(s"FROM CUSTOM LISTENER $deadLetter") } }
Выход
164 [LifecycleActorSystem-akka.actor.default-dispatcher-4] INFO BasicLifecycleLoggingActor - hello 167 [LifecycleActorSystem-akka.actor.default-dispatcher-4] INFO akka.actor.RepointableActorRef - Message [java.lang.String] from Actor[akka://LifecycleActorSystem/deadLetters] to Actor[akka://LifecycleActorSystem/user/lifecycleActor#-782937925] was not delivered. [1] dead letters encountered. This logging can be turned off or adjusted with configuration settings 'akka.log-dead-letters' and 'akka.log-dead-letters-during-shutdown'. FROM CUSTOM LISTENER DeadLetter(hello,Actor[akka://LifecycleActorSystem/deadLetters],Actor[akka://LifecycleActorSystem/user/lifecycleActor#-782937925])