2017-01-06 2 views
4

Как я знаю, все операции в Akka.Net являются асинхронными, и Context.Stop() просто посылает сообщение Stop актеру. Это означает, что актер будет жив в течение некоторого времени, прежде чем он полностью отключится.Есть ли способ подождать, пока актер полностью остановится?

И если я позвоню Context.Child() сразу после Context.Stop() с именем актера, я просто остановился, я получу тот же самый актер.

Вот пример код

var actor = context.Child(actorName); 

if (actor.Equals(ActorRefs.Nobody)) 
{ 
    actor = CreateNewActor(); 
} 

Context.Stop(actor) 
actor = context.Child(actorName); 
// what do we get here, same actor or ActorRefs.Nobody ? 

Мое приложение создает актер для обработки событий от терминалов. Каждый раз, когда подключается новый терминал, я создаю нового актера, вызывая Context.Child() с использованием имени терминала. Когда терминал отключается, я останавливаю актера.

Проблема в том, что несколько раз я получаю сообщение Connect сразу после разъединения для того же терминала, и в результате я получаю действие, которое будет остановлено. Есть ли способ проверить, что актер получил сообщение «Стоп» и скоро будет остановлен?

+0

Вы должны прочитать о: * Жизненный цикл мониторинга ака Deathwatch * Shutdown с подтверждением: GracefulStop –

+0

Одно из предложений, которое приходит на мой взгляд, является также [FSM] (http://getakka.net/docs/FSM).После этого актер получает сообщение Disconnect, вы переключаетесь на новое состояние и изменяете поведение. Поэтому сообщение Connect не будет обрабатываться обычным способом. И вы также можете определить, что должен делать актер, когда сообщение Connect не обрабатывается. –

ответ

0

Я решил закончить обработку Terminated сообщений.

После получения Disconnect сообщения и остановок актера, я держу это имя в ActorsToBeStopped HashSet, и перед созданием нового актера на получение Connect сообщения, я проверить, если он там существует. Если это так, я сохраняю это сообщение Connect в словаре с именем актера в качестве ключа и Connect в качестве значения и обрабатывать его после получения завершенного сообщения для соответствующего участника.

Что-то вроде этого:

private readonly Dictionary<string, Connect> postponedConnectMessages = new Dictionary<string, Connect>(); 
private readonly HashSet<string> actorsToBeStopped = new HashSet<string>(); 

// ... 

Receive<Disconnected>(t => 
{ 
    var actor = GetActorByName(t.Name); 
    Context.Stop(actor); 
    actorsToBeStopped.Add(actor.Path.Name); 
}); 

Receive<Connected>(t => 
{ 
    var actor = GetActorByName(t.Name); 

    if (actorsToBeStopped.Contains(actor.Path.Name)) 
    { 
     postponedConnectMessages[actor.Path.Name] = t; 
     return; 
    } 
    // work with actor 
} 

Receive<Terminated>(t => 
{ 
    var deadActorName = t.ActorRef.Path.Name; 
    actorsToBeStopped.Remove(deadActorName); 
    if (postponedConnectMessages.ContainsKey(deadActorName)) 
    { 
     var connectMessage = postponedConnectMessages[deadActorName]; 
     postponedConnectMessages.Remove(deadActorName); 
     var actor = GetActorByName(connectMessage.Name); 
     // we sure we have new actor here 
     // work with actor 
    } 
} 

EDIT

Печально то здесь в том, что я не могу написать тест для него, потому что Akka.TestKit не позволяет мне создавать TestActor с таким же именем даже после его прекращения:

public void StopTest() 
{ 
    var t = CreateTestActor("AAAA"); 
    Watch(t); 
    Sys.Stop(t); 
    ExpectTerminated(t, TimeSpan.FromSeconds(10)); 
    var t2 = CreateTestActor("AAAA"); // test fails here 
} 

Возможно, это была не остановка педаль после ExpectTerminated, но в любом случае я не знаю, как подождать окончания.

0

Вы можете использовать

уаг выключение = actor.GracefulStop (TimeSpan.FromSeconds (42));

Он возвращает задачу, результат подтверждает завершение работы в течение 42 секунд

UPDATE

Но, в случае, если вы хотите, чтобы воссоздать актер позже с тем же именем, вы должны слушать Отменено сообщение внутри руководителя актера.

+1

Как я понимаю примечание [здесь] (http://getakka.net/docs/Working%20with%20actors#graceful-stop), он не поможет мне: ** Предупреждение ** _ Помните, что актер остановка и ее имя, которое отменяется регистрацией, представляют собой отдельные события, которые происходят асинхронно друг от друга. Поэтому, возможно, вы найдете имя, которое все еще используется после возвращения GracefulStop(). Чтобы гарантировать правильную отмену регистрации, используйте только имена повторного использования внутри контролирующего органа, и только в ответ на сообщение о завершении, то есть не для игроков верхнего уровня. – bonzaster

+0

О, извините. Я неправильно понял ваш первоначальный вопрос. Да, Grasfull top не гарантирует вам, что имя актера отменено. В вашем случае вы должны прослушать прекращенные сообщения, в актере, который контролирует ваших актеров с именами терминалов. –

Смежные вопросы