akka.net Сохранение сообщений во время определенного состояния актера

У меня есть актер (человек), которому я хочу иметь возможность хранить сообщения во время состояния. Проблема в том, что я не уверен, как лучше всего это сделать.

Допустим, у меня есть несколько команд.

ChangeAddress
ChangePhoneNumber
BeginMove
FinishMove

Пока я нахожусь в середине перемещения (после начала BeginMove и до FinishMove), я хочу предотвратить обновления адреса и номера телефона и просто воспроизвести любые события после завершения перемещения. Я использую ReceivePersistentActor, и каждая команда представляет собой отдельный класс.

Прямо сейчас я думал о флаге состояния на актере, но хотя функциональность стать/не стать была бы более естественной, я не вижу, как применить ее к различным командам.

Также в качестве побочного вопроса существует ли хороший шаблон для разбивки количества команд и восстановления, которые должны быть написаны, поскольку актор должен обрабатывать больше команд/событий?


person Josh    schedule 20.08.2016    source источник
comment
Я обновил свой ответ потоком, который, как мне кажется, вам нужен   -  person tomliversidge    schedule 22.08.2016


Ответы (2)


В Akka это уже встроено:

http://getakka.net/docs/working-with-actors/Stashing%20Messages

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

В вашем примере вы получите команду BeginMove и перейдете в состояние Moving, вызвав Become(Moving). В следующий раз, когда сообщение будет обработано, вы окажетесь в этом новом состоянии. Внутри вашего метода Moving вы должны настроить обработчики Receive<ChangeAddress>message, чтобы спрятать сообщение, и все остальные обработчики, чтобы иметь любое поведение, которое вы хотите во время перемещения. В какой-то момент в будущем вам понадобится команда FinishMove, которая вернет ваше поведение к тому, что было до того, как вы начали перемещение, и удалит все сообщения. В этот момент все спрятанные сообщения начнут обрабатываться в исходном состоянии вашего поведения. Это все без блокировки.

void OriginalState()
    {
        Receive<ChangeAddress>(s =>
        {
             // change address logic
        });

        Receive<BeginMove>(msg =>
        {
            Become(Moving);
        }
    }

void Moving()
    {
        Receive<ChangeAddress>(s =>
        {
            Stash.Stash();
        });

        Receive<FinishMove>(msg =>
        {
            Become(OriginalState);
            Stash.UnstashAll();
        }
    }

См. переключаемые поведения для получения дополнительных примеров кода о том, как чтобы настроить ваши состояния для обработки ваших типов сообщений.

Одним из способов разделения является делегирование поведения дочерним акторам, если это уместно, но на этом этапе это становится больше проблемой дизайна.

person tomliversidge    schedule 21.08.2016

обо всем по порядку: пока нет вызовов PipeTo() - менять нечего.

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

Чтобы избежать прерывания при обработке длительного вызова (например, при использовании db) — я складываю своего актера — см. пример с принимающим актером. Это позволяет:

  1. остановить обработку входящих сообщений
  2. предотвращает метод остановки диспетчером (тайм-аут)
  3. избегает использования тайника, так как он не нужен

    public class ProcessActor : ReceiveActor{
    
     public ProcessActor() {
    
        Receive < ChangeAddress > (
            message =  > {
                BecomeStacked(ProcessingOrDoNothing);
                //{do the job here}
                UnbecomeStacked();
            });
     }
    
      public void ProcessingOrDoNothing(){}
    
    }
    
person profesor79    schedule 22.08.2016
comment
Не могли бы вы рассказать о том, что делают BecomeStacked и UnbecomeStacked? Можете ли вы опубликовать код? - person tomliversidge; 22.08.2016
comment
это внутренние элементы akka, которые используются для изменения состояния актера. Когда состояние изменяется и нет Receive, обработка почтового ящика останавливается, unbecomeStacked отменяет предыдущую команду стека. - person profesor79; 22.08.2016
comment
Хорошо, спасибо, я забыл о них, так как всегда использовал Become. - person tomliversidge; 22.08.2016
comment
Я думаю, что часть, которую мне не хватает, заключается в том, что это заставляет ChangeAddress хранить элементы в почтовом ящике, в то же время позволяя проходить другим сообщениям ChangePhoneNumber. Также я хочу, чтобы поведение ChangeAddress изменялось, когда я получаю команду BeginMove, и переставало работать, когда я получаю команду FinishedMove. Я могу привести более полный пример, если это поможет тому, чего я пытаюсь достичь. - person Josh; 22.08.2016
comment
Кроме того, я думал, что вызовы Become и Unbecome в рамках обработки одного сообщения на самом деле ничего не сделают, поскольку только следующее обработанное сообщение получает новое поведение? т.е. в этом примере единственным кодом, который что-то делает, является часть {do the job here}, так как вы становитесь и не подходите в одном и том же сообщении, это отменяет друг друга - person tomliversidge; 22.08.2016
comment
в этом сценарии be/unbecome используются в качестве мер безопасности, чтобы предотвратить убийство актера из-за тайм-аута при обработке сообщения. как я упоминал в начале, актор сам обрабатывает одно сообщение за раз, так что ваше требование выполнено. - person profesor79; 22.08.2016