Модель акторов с Akka.NET: как предотвратить отправку сообщений мертвым акторам

Я использую Akka.NET для реализации системы акторов, в которой некоторые акторы создаются по запросу и удаляются после настраиваемого периода простоя (для этого я использую механизм Akka "ReceiveTimeout"). Каждый из этих субъектов идентифицируется ключом, и не должно существовать двух субъектов с одним и тем же ключом.

Эти субъекты в настоящее время создаются и удаляются общим супервизором. Супервизора можно попросить вернуть ссылку на актера, соответствующего данному ключу, либо путем возврата существующего, либо создания нового, если актор с этим ключом еще не существует. Когда субъект получает сообщение «ReceiveTimeout», он уведомляет супервизора, который, в свою очередь, убивает его с помощью «PoisonPill».

У меня проблема при отправке сообщения одному из этих субъектов сразу после его удаления. Я заметил, что отправка сообщения мертвому актеру не создает исключения. Хуже того, при отправке сообщения «Спросить» отправитель остается заблокированным, ожидая неопределенное время (или до истечения времени ожидания) ответа, который он никогда не получит.

Сначала я подумал о механизме Akka "Deatchwatch" для отслеживания жизненного цикла актера. Но, если я не ошибаюсь, сообщение «Прервано», отправленное умирающим актором, будет получено контролирующим актером асинхронно, как и любое другое сообщение, поэтому проблема все еще может возникать между смертью целевого актора и получением его Сообщение «Прервано».

Чтобы решить эту проблему, я сделал так, что любой, кто запрашивает у супервизора ссылку на такого актера, должен послать супервизору сообщение «закрыть сеанс», чтобы освободить актера, когда он ему больше не нужен (это делается прозрачно. одноразовым объектом "ActorSession"). Пока с актером есть открытые сеансы, супервизор не удалит его.

Я полагаю, что эта ситуация довольно распространена, и поэтому мне интересно, нет ли более простого шаблона для решения этой проблемы. Любое предложение будет оценено.


person Odsh    schedule 22.12.2014    source источник


Ответы (2)


У меня проблема при отправке сообщения одному из этих субъектов сразу после его удаления. Я заметил, что отправка сообщения мертвому актеру не создает исключения.

Это сделано намеренно. Вы никогда не получите исключение при попытке отправить сообщение - оно будет просто перенаправлено на Deadletters и зарегистрировано. Для этого есть много причин, о которых я не буду здесь рассказывать, но суть в том, что это предполагаемое поведение.

DeathWatch - правильный инструмент для этой работы, но, как вы отметили, вы можете получить Terminated сообщение после того, как уже отправили сообщение этому актеру.

Более простой шаблон, чем отслеживание открытых / закрытых сеансов, - это просто использовать сообщения подтверждения / ответа от получателя с использованием Ask + Wait + жесткого тайм-аута. Обратной стороной, конечно же, является то, что если ваш субъект-получатель выполняет много длительных операций, вы можете заблокировать на длительный период времени внутри отправителя.

Другой вариант, который вы можете использовать, - это перепроектировать своего актора-получателя, чтобы он действовал как конечный автомат и имел состояние с мягким завершением или завершением, которое он использует для истощения соединений / ссылок. с потенциальными отправителями. Таким образом, исходный субъект по-прежнему может отвечать и принимать сообщения, но сообщать вызывающим абонентам, что он больше не может выполнять работу.

person Aaronontheweb    schedule 23.12.2014
comment
Спасибо за ответ Аарон. - person Odsh; 23.12.2014
comment
Я думал о решении с помощью Ask + timeout, но мне не нравится идея, что мои актеры ничего не делают, потому что они ждут тайм-аута. Я понимаю, что это произойдет рано или поздно из-за в лучшем случае надежности доставки в Akka, но, по крайней мере, в этом случае это будет проблема передачи сообщений между участниками, а не конструктивное ограничение. Мне нравится идея конечного состояния, я подумаю над ней еще раз. Однако актер все еще не знает, в какой момент он больше не получит никаких сообщений и, следовательно, когда он сможет удалить себя. - person Odsh; 23.12.2014
comment
@Odsh Однако актер все еще не знает, в какой момент он больше не получит никаких сообщений и, следовательно, когда он сможет удалить себя. - если принимающий субъект не знает, когда он перестанет получать сообщения, а отправляющий субъект не знает, когда он должен прекратить отправлять сообщения, то это проблема вашего дизайна. Один из этих двух действующих лиц должен иметь возможность сделать это определение или отчитаться перед каким-либо другим действующим лицом, которое может. - person Aaronontheweb; 25.12.2014
comment
Аарон, отправляющие и принимающие акторы знают, когда они перестанут обмениваться сообщениями. Однако принимающий актер не знает, когда новый актер захочет начать с ним общение. - person Odsh; 29.12.2014
comment
Отличный ответ, но я бы добавил, что вы также можете проверить Actor с помощью Actorselection: вы также можете получить ActorRef для ActorSelection с помощью метода resolveOne для ActorSelection. Он возвращает Future соответствующего ActorRef, если такой субъект существует. Он завершается ошибкой akka.actor.ActorNotFound, если такой субъект не существует или идентификация не завершилась в течение предоставленного тайм-аута. - person Chanan Braunstein; 19.03.2015

Я решил эту проблему с помощью субъектов-сущностей, созданных с помощью Cluster Sharding механизм:

Если состояние объектов является постоянным, вы можете остановить объекты, которые не используются, для уменьшения потребления памяти. Это выполняется конкретной реализацией субъектов сущности в приложении, например, путем определения тайм-аута приема (context.setReceiveTimeout). Если сообщение уже помещено в очередь к объекту, когда он останавливается, помещенное в очередь сообщение в почтовом ящике будет удалено. Чтобы поддерживать плавную пассивацию без потери таких сообщений, субъект-субъект может отправить ShardRegion.Passivate своему родительскому Shard. Указанное в оболочке сообщение в Passivate будет отправлено обратно объекту, который затем должен остановить себя. Входящие сообщения будут буферизироваться Shard между получением Passivate и завершением объекта. После этого такие буферизованные сообщения доставляются новому воплощению объекта.

person Odsh    schedule 14.11.2017