Событие здесь, событие там, события, летящие повсюду. Сообщение о проверке того, что каждое событие Akka, наконец, найдет свой дом.
Акка и реактивные, основанные на событиях приложения являются новым подходом к созданию программного обеспечения. Мы активно используем Akka в нашем текущем Scala-проекте. События особенно подходят для наших сценариев использования, поскольку мы взаимодействуем с внешним API, который может быть медленным. Это может повредить пользовательский опыт при использовании традиционного синхронного подхода. Но, к счастью, наши запросы могут выполняться асинхронно, поэтому их передача актеру казалась хорошей идеей.
Когда вещи выходят из-под контроля
Но, будучи крутым и очень полезным, события могут все же навредить проекту, когда обрабатываются неопытными руками. Асинхронный характер затрудняет понимание потока приложений на первый взгляд. И каждый раз, когда вы добавляете нового актера или тип события в вашу систему, вероятность того, что вы забудете правильно что-то обработать, увеличивается.
Давайте посмотрим на пример класса, это актер, обрабатывающий события, связанные с тегами изображения и комментариями:
01
02
03
04
05
06
07
08
09
10
11
12
|
class YourActor extends Actor { override def receive = { case event: ImageTagged => doSomething() case event: OtherImageTaggedByFriend => doSomething2() case event: MostMotedUserImage => doSomething3() case event: MostCommentedFriendImageChosen => doSomething4() } } |
и когда вы добавляете следующее событие, скажем, MostLikedFriendImage, вы можете легко забыть добавить секцию обработчика в акторе, особенно если есть несколько акторов, слушающих этот тип события.
СУХОЙ раствор, нарушающий
Есть одно простое решение, которое позволит обнаружить забытые обработчики. Мы можем добавить case _ к каждому актеру:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
|
class YourActor extends Actor { override def receive = { case event: ImageTagged => doSomething() case event: OtherImageTaggedByFriend => doSomething2() case event: MostMotedUserImage => doSomething3() case event: MostCommentedFriendImageChosen => doSomething4() case event: _ : logger.error( "Received unknown event " + event.getClass.toString) } } |
И хотя это выглядит довольно хорошо для одного или двух акторов, добавление одного и того же фрагмента кода к нескольким акторам проблематично и нарушает принцип DRY. Но, что самое опасное, кто-то в вашей команде может забыть добавить его (как кто-то сказал: «Каждое ручное задание, которое можно забыть, будет забыто» ). Так, может быть, мы должны искать лучшее решение?
Реагируйте на ЛЮБОЕ необработанное событие
К счастью, мы не застряли в нашем подверженном ошибкам подходе. Когда актер не может обработать событие, которое было ему передано, UnhandledMessage вызывается и публикуется в EventStream ActorSystem.
Таким образом, для обработки каждого забытого события мы могли бы создать слушателя и подписать его на EventStream:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
|
class UnhandledMessageListener extends Actor { val logger = LoggerFactory.getLogger(getClass) override def receive = { case message: UnhandledMessage => logger.error(s "CRITICAL! No actors found for message ${message.getMessage}" )) if (!Environment.isProduction) { // Fail fast, fail LOUD logger.error( "Shutting application down" ) System.exit(- 1 ) } } } |
И подписывающийся фрагмент кода:
1
2
3
4
|
val actorSystem = ActorSystem.create( "projectActorSystem" ) val listener = actorSystem.actorOf(Props( new UnhandledMessageListener())) actorSystem.eventStream.subscribe(listener, classOf[UnhandledMessage]) |
вот и все. Теперь каждый раз, когда происходит событие, которое не было обработано актером, мы будем знать о нем, особенно когда приложение развернуто в непроизводственной среде!
Ссылка: | Обрабатывайте каждое событие в вашем приложении Akka от нашего партнера JCG Томаша Дзюрко в блоге Code Hard Go Pro . |