(Обратите внимание, что эта запись жизненного цикла не распространяется на preRestart
или postRestart
. Мы поговорим о них, когда будем обсуждать надзор)
Основной жизненный цикл актера очень интуитивно понятен. Фактически вы можете сравнить базовый жизненный цикл Actor с жизненным циклом Java-сервлета с одним специальным отличием.
- Как и в любом другом обычном классе, у нас есть конструктор
- Метод
preStart
снова. Здесь вы можете инициализировать ресурсы, которые вы хотите очистить вpostStop
- «Обслуживание» или обработка сообщений методом
receive
занимает большую часть времени, и это происходит между ними.
Давайте посмотрим на простого актера, который печатает жизненный цикл.
Тупой актер жизненного цикла
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
|
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
просто инициирует, отправляет сообщение Actor и завершает работу ActorSystem.
01
02
03
04
05
06
07
08
09
10
11
12
13
14
|
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() } |
Выход
1
2
3
4
5
6
7
8
9
|
Inside BasicLifecycleLoggingActor Constructor Actor[akka: //LifecycleActorSystem/user/lifecycleActor#-2018741361] Inside the preStart method of BasicLifecycleLoggingActor hello Inside postStop method of BasicLifecycleLoggingActor |
В чем особая разница между сервлетами и базовым жизненным циклом актера?
Нет никакой разницы между конструктором и предварительным запуском в жизненном цикле Actor — более или менее.
Причина, по которой я напечатал context.self
в конструкторе, заключается в следующем — в отличие от сервлетов, Actors имеют доступ к ActorContext
даже внутри конструктора. Разница между preStart и конструктором становится очень тонкой. Мы еще вернемся к разнице, пока будем говорить о надзоре, но если вам любопытно, можно вызвать предварительный preStart
когда перезапуск актера (в случае сбоя) можно контролировать. С конструктором это невозможно.
Когда вызывается postStop?
Как мы видели из программы, postStop
когда ActorSystem выключается. Есть несколько других случаев, когда обратный вызов тоже вызывается.
1. ActorSystem.stop ()
Мы могли бы остановить Actor, используя метод stop
ActorSystem
и ActorContext
01
02
03
04
05
06
07
08
09
10
11
|
object LifecycleApp extends App{ val actorSystem=ActorSystem( "LifecycleActorSystem" ) val lifecycleActor=actorSystem.actorOf(Props[BasicLifecycleLoggingActor], "lifecycleActor" ) actorSystem.stop(lifecycleActor); ... ... } |
2. ActorContext.stop
1) Либо посредством сообщения (извне или передачи сообщения себе)
1
2
3
4
5
6
7
|
class BasicLifecycleLoggingActor extends Actor with ActorLogging{ ... ... def receive = LoggingReceive{ case "hello" => log.info ( "hello" ) case "stop" => context.stop(self) } |
и
1
2
3
4
5
6
7
8
9
|
object LifecycleApp extends App{ val actorSystem=ActorSystem( "LifecycleActorSystem" ) val lifecycleActor=actorSystem.actorOf(Props[BasicLifecycleLoggingActor], "lifecycleActor" ) lifecycleActor! "stop" ... ... |
2) ИЛИ убить себя без причины
(это просто для развлечения. Ни один актер с амбициями не сделает этого)
1
2
3
4
5
6
7
|
class BasicLifecycleLoggingActor extends Actor with ActorLogging{ log.info ( "Inside BasicLifecycleLoggingActor Constructor" ) log.info (context.self.toString()) context.stop(self) ... ... |
3. PoisonPill
В предыдущем примере мы передали сообщение с именем stop из LifecycleApp в Actor. Актер получил это сообщение и покончил с собой, используя context.stop
. Мы могли бы достичь того же, передав сообщение PoisonPill целевому субъекту . Обратите внимание, что сообщение PoisonPill
, как и предыдущее сообщение об остановке, ставится в очередь в обычном почтовом ящике и будет обрабатываться при его появлении.
1
2
3
4
5
6
7
8
|
object LifecycleApp extends App{ val actorSystem=ActorSystem( "LifecycleActorSystem" ) val lifecycleActor=actorSystem.actorOf(Props[BasicLifecycleLoggingActor], "lifecycleActor" ) lifecycleActor!PoisonPill ... ... |
TRIVIA
Что я имею в виду обычный почтовый ящик? Также есть «специальный» почтовый ящик? Ага. Там есть. И мы поговорим об этом, когда будем говорить об этом, когда будем обсуждать надзор и system
сообщения.
прекращение
Как только Актер остановлен, говорят, что он входит в Terminated
состояние. Непосредственный вопрос, который возникнет у вас на уме: что произойдет с сообщениями, которые отправляются действующему субъекту?
Давайте посмотрим, что:
Приложение
01
02
03
04
05
06
07
08
09
10
|
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 } |
Актер — Как и прежде
1
2
3
4
5
6
7
8
|
class BasicLifecycleLoggingActor extends Actor with ActorLogging{ def receive = LoggingReceive{ case "hello" => log.info ( "hello" ) case "stop" => context.stop(self) } } |
Выход
1
2
3
|
BasicLifecycleLoggingActor - hello akka.actor.RepointableActorRef - Message 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
и публикует это как сообщение журнала. Проверьте это.
Помните, когда мы говорили о ведении журнала , мы видели, что все сообщения журнала публикуются в EventStream и что мы можем подписаться на это EventStream — просто подписчик также должен быть актером. Давайте попробуем это сейчас.
В нашем примере мы подпишемся на EventStream, следим за всеми сообщениями DeadLetter и будем печатать на консоль (так много для творчества ?? !!). Честно говоря, мы можем делать что угодно, генерируя оповещения, сохраняя их в базе данных или даже добавляя аналитику.
ПОДПИСКА НА DEADLETTERS В EVENTSTREAM
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
|
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[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" ) } } |
Выход
1
2
3
4
5
|
164 [LifecycleActorSystem-akka.actor. default -dispatcher- 4 ] INFO BasicLifecycleLoggingActor - hello 167 [LifecycleActorSystem-akka.actor. default -dispatcher- 4 ] INFO akka.actor.RepointableActorRef - Message 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]) |
Ссылка: | Akka Notes — Actor Lifecycle — Basic — 5 от нашего партнера JCG Аруна Маниваннана в блоге Rerun.me . |