Актеры полностью иерархичны. Независимо от актеров, которых вы создаете, ДОЛЖНО быть ребенком какого-то другого актера.
Давайте проанализируем это немного:
Путь
Скажем, мы создаем ActorRef с помощью ActorSystem.actorOf
и пытаемся распечатать его path
.
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
имя вашего актера, которое система сгенерировала для вас. Как бы вы хотели, чтобы ваша операционная система генерировала случайные имена файлов для ваших файлов? Вы, очевидно, ненавидели бы это, потому что вы хотели бы сослаться на это имя в будущем. Итак, давайте дадим ему правильное осмысленное имя:
val actorRef=actorSystem.actorOf(Props[BasicLifecycleLoggingTeacherActor], "teacherActor") println (actorRef.path) // (prints) akka://SupervisionActorSystem/user/teacherActor
Вот и все. Теперь путь действительно имеет смысл.
Актеры
Подобно актерам верхнего уровня, которые мы создаем из ActorSystem, мы также можем создавать дочерних акторов из ActorContext
. Фактически, сила отказоустойчивости актеров в первую очередь заключается в использовании иерархии акторов и способности родителей управлять жизнью дочерних актеров.
Предположим, у вас есть TeacherSupervisor
и вы хотите создать TeacherActor
дочернего элемента Supervisor, ActorContext.actorOf
вместо ActorSystem.actorOf
:
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 — с /
корневой папкой и все тех /etc
, /usr
, /bin
и различными другими папками.
ActorSystem очень похожи на это. Он создает несколько Актеров высшего уровня — наиболее важными из них являются корневой Актор с путем /
, пользовательский Актер с путем /user
и системный Актер с путем /system
. (есть также, /deadLetters
которые представляют DeadLetterActorRef
. Мы видели это в нашем предыдущем посте )
В коде ActorSystem состоит из трех акторов (через ActorRefProvider ). Это корень для ВСЕХ Актеров, которые создаются в ActorSystem.
systemGuardian
актер — корень всех актеров под/system
guardian
актер — корень всех актеров/user
иrootGuardian
Актер — кореньsystemGuardian
иuserGuardian
актеров.
/** * 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
Любой актер , который вы создаете в своей программе , таких как StudentActor
или с TeacherActor
помощью ActorSystem
S» actorOf
метод будет непосредственно подпадать под /user
. Вот почему у вас teacherActor
в первой части этой статьи был слаг-путь /user/teacherActor
.
/ system (aka) системный хранитель
Системный хранитель отключается, когда замечает, что userGuardian
он мертв. Имеет смысл подумать, если userGuardian
не работает, то все бизнес-субъекты под ним также не работают, и поэтому все административные субъекты тоже должны быть уволены.
Мы могли видеть два разных места, где создаются системные акторы — я имею в виду актеров в /system
иерархии.
-
Как мы видели ранее , любое сообщение, которое вы отправляете действующему субъекту, перенаправляется в почтовый ящик внутреннего вызываемого субъекта
DeadLetterActor
. DeadLetter Actor упаковывает каждое сообщение как aDeadLetter
и публикует его в EventStream. Другой вызванный ActorDeadLetterListener
потребляет все DeadLetters и публикует это как сообщение журнала. Теперь DeadLetterListener — системный актер с путем/system/deadLetterListener
. -
Помните ,
TestEventListener
что мы создали в предыдущей записи-до подписки на журнал сообщений в EventStream? Они тоже системные игроки. Фактически, всеakka.loggers
они созданы как субъекты Системы.
class TeacherTest extends TestKit(ActorSystem("UniversityMessageSystem", ConfigFactory.parseString("""akka.loggers = ["akka.testkit.TestEventListener"]"""))) ... ...
Документация здесь говорит, что любой Actor, который настроен в файлах конфигурации и создан и развернут в ActorSystem во время его запуска, попадает под /system
зонтик. Позвольте мне обновить этот пост, когда я найду что-то интересное вокруг этого
/ (иначе) хранитель корней
Как мы видели ранее, /
Актер является родителем пользователя и опекунов системы.
TRIVIA
Технически, у корневого субъекта тоже есть лишний родитель. Единственная задача этого актера — отключить всю систему ActorSystem в случае сбоя корневого субъекта. Так как это строго не учитывается в иерархии Actor, команда Akka называет это так:
private[akka] val theOneWhoWalksTheBubblesOfSpaceTime: InternalActorRef = new MinimalActorRef { ...