Актеры полностью иерархичны. Независимо от актеров, которых вы создаете, ДОЛЖНО быть ребенком какого-то другого актера.
Давайте проанализируем это немного:
Путь
Скажем, мы создаем ActorRef с помощью ActorSystem.actorOf
и пытаемся распечатать его path
.
1
2
3
|
val actorSystem=ActorSystem( "SupervisionActorSystem" ) val actorRef=actorSystem.actorOf(Props[BasicLifecycleLoggingTeacherActor]) println (actorRef.path) // (prints) akka://SupervisionActorSystem/user/$a |
Как видите, путь очень похож на путь к файлу в файловой системе.
-
akka
здесь исправлена, потому что все это адреса Akka Actors — больше похоже на префиксfile://
илиhttp://
(хотя протокол не имеет ничего общего). -
SupervisionActorSystem
— это просто имя вашей ActorSystem, которую вы создали. - Мы поговорим о
user
в следующем разделе. -
$a
A — это имя вашего актера, которое система сгенерировала для вас. Как бы вы хотели, чтобы ваша операционная система генерировала случайные имена файлов для ваших файлов? Вы, очевидно, ненавидели бы это, потому что вы хотели бы сослаться на это имя в будущем. Итак, давайте дадим ему правильное осмысленное имя:
1
2
|
val actorRef=actorSystem.actorOf(Props[BasicLifecycleLoggingTeacherActor], "teacherActor" ) println (actorRef.path) // (prints) akka://SupervisionActorSystem/user/teacherActor |
Вот и все. Теперь путь действительно имеет смысл.
Актеры
Подобно актерам верхнего уровня, которые мы создаем из ActorSystem, мы также можем создавать дочерних акторов из ActorContext
. Фактически, сила отказоустойчивости актеров в первую очередь заключается в использовании иерархии акторов и способности родителей управлять жизнью дочерних актеров.
Предположим, у вас есть TeacherSupervisor
и вы хотите создать ActorContext.actorOf
как ActorContext.actorOf
элемент ActorContext.actorOf
вместо ActorContext.actorOf
вы делаете ActorSystem.actorOf
:
1
2
3
4
|
class TeacherSupervisor extends Actor with ActorLogging { val teacherActor=context.actorOf(Props[TeacherActor], "teacherActor" ) ... ... |
Честно говоря, в любом приложении вы будете создавать больше дочерних акторов, чем актеров верхнего уровня — это означает, что вы будете вызывать намного больше actorContext.actorOf
чем actorSystem.actorOf
.
Вы заметите, что путь дочернего актера akka://SupervisionActorSystem/user/teacherSupervisor/teacherActor
, который очень похож на путь, который вы получаете при создании дочерней папки в родительской папке.
Когда вы создаете детей актеров?
Обычно вы создаете дочерних акторов, когда определенная задача состоит из подзадачи или нескольких подзадач. Вы также создаете дочерний актер, когда определенная задача, которая будет выполняться родителем, подвержена ошибкам, и вы захотите изолировать ее (чтобы в случае сбоя вы могли ее восстановить). Если между задачами нет родительских и дочерних отношений, вы НЕ создаете дочерних акторов.
Кроме того, ничто не мешает дочернему актеру создавать детей для делегирования его подзадач. Актеры и их творчество действительно дешевы, но сила, которая приходит с ними, удивительна (мы увидим это, пока будем говорить о наблюдении)
Теперь, что это за user
?
Из-за отсутствия креативности позвольте мне сравнить ActorSystem
с файловой системой Unix — с папкой /
root и всеми этими /etc
, /usr
, /bin
и различными другими папками.
ActorSystem очень похожи на это. Он создает несколько Актеров высшего уровня — наиболее важными из них являются корневой Актор с путем /
, пользовательский Актер с путем /user
и системный Актер с путем /system
. (есть также /deadLetters
, представляющий DeadLetterActorRef
. Мы видели это в нашем предыдущем посте )
В коде ActorSystem состоит из трех акторов (через ActorRefProvider ). Это корень для ВСЕХ Актеров, которые создаются в ActorSystem.
-
systemGuardian
actor — корень всех актеров в/system
- актер-
guardian
— корень всех актеров в/user
и -
rootGuardian
Actor — корень какsystemGuardian
и пользовательскихuserGuardian
.
01
02
03
04
05
06
07
08
09
10
11
12
13
14
|
/** * Reference to the supervisor of guardian and systemGuardian; .... */ def rootGuardian: InternalActorRef /** * Reference to the supervisor used for all top-level user actors. */ def guardian: LocalActorRef /** * Reference to the supervisor used for all top-level system actors. */ def systemGuardian: LocalActorRef |
/ user (aka) user guardian
Любой Actor, который вы создаете в своей программе, например StudentActor
или StudentActor
используя метод ActorSystem
actorOf
будет напрямую попадать в /user
. Это причина, по которой ваш teacherActor
в первой части этой статьи имел путь slug /user/teacherActor
.
/ system (aka) системный хранитель
Системный хранитель отключается, когда замечает, что userGuardian
мертв. Имеет смысл учитывать, что если userGuardian
не работает, то все бизнес-субъекты в нем также не userGuardian
, и поэтому все административные субъекты также должны быть удалены.
Мы могли видеть два разных места, где создаются субъекты системы — я имею в виду актеров в иерархии /system
.
- Как мы уже видели ранее , любое сообщение, которое вы отправляете
DeadLetterActor
перенаправляется в почтовый ящик внутреннегоDeadLetterActor
именемDeadLetterActor
. Актер DeadLetter упаковывает каждое сообщение какDeadLetter
и публикует его в EventStream. Еще один Actor под названиемDeadLetterListener
потребляет все DeadLetters и публикует это как сообщение журнала. Теперь DeadLetterListener — это системный субъект с путем/system/deadLetterListener
. - Помните
TestEventListener
который мы создали в нашей предыдущейTestEventListener
для подписки на сообщения журнала в EventStream? Они тоже системные игроки. На самом деле всеakka.loggers
создаются как субъекты системы.
1
2
3
|
class TeacherTest extends TestKit(ActorSystem( "UniversityMessageSystem" , ConfigFactory.parseString( "" "akka.loggers = [" akka.testkit.TestEventListener "]" "" ))) ... ... |
Документация здесь говорит, что любой Actor, который сконфигурирован в файлах конфигурации и создан и развернут в ActorSystem во время его запуска, попадает под зонтик /system
. Позвольте мне обновить этот пост, когда я найду что-то интересное вокруг этого
/ (иначе) хранитель корней
Как мы видели ранее, /
Actor является родителем пользователя и системных опекунов.
TRIVIA
Технически, у корневого субъекта тоже есть лишний родитель. Единственная задача этого актера — отключить всю систему ActorSystem в случае сбоя корневого агента. Так как это строго не учитывается в иерархии Actor, команда Akka называет это так:
1
2
|
private [akka] val theOneWhoWalksTheBubblesOfSpaceTime: InternalActorRef = new MinimalActorRef { ... |
Ссылка: | Заметки Акки — Детские актеры и ActorPath — 6 от нашего партнера JCG Аруна Маниваннана в блоге Rerun.me . |