Как объединить данные ответов двух асинхронных сервисов в Akka.Net - PullRequest
1 голос
/ 23 сентября 2019

Я делаю два асинхронных вызова службы через двух акторов

Актер 1 -> Извлечение данных -> Это вернет некоторый ответ

Актер 2 -> Извлечение данных -> Это вернет некотороеответ.

Как объединить оба результата в Akka.Net.Есть ли какой-то шаблон, которому мы должны следовать в Akka.net?

1 Ответ

1 голос
/ 25 сентября 2019

Самый простой способ - использовать шаблон запроса:

ReceiveAsync<Message>(async msg => {
    var t1 = actor1.Ask<Response>(new Request(), cancellationToken);
    var t2 = actor2.Ask<Response>(new Request(), cancellationToken);
    await Task.WhenAll(t1, t2);
    DoSomething(t1.Result, t2.Result);
});

Этот подход будет работать, но у него есть несколько недостатков:

  1. Он заблокирует актера от обработкилюбые другие сообщения, пока весь метод не завершит выполнение (включая завершение как t1, так и t2).
  2. Используется Ask, который имеет свое собственное влияние на производительность - невелик по сравнению, например, с.Ввод / вывод в базу данных, но во многих случаях это может быть слишком много (если вы беспокоитесь о производительности).

Способ решения пункта 1 - перейти с await:

Receive<Message>(msg => {
    var t1 = actor1.Ask<Response>(new Request(), cancellationToken);
    var t2 = actor2.Ask<Response>(new Request(), cancellationToken);
    Task.WhenAll(t1, t2).ContinueWith(t => {
        var t1 = t.Result[0];
        var t2 = t.Result[1];
        return new CombinedResponse(t1.Result, t2.Result);
    }).PipeTo(Self, sender: Sender);
});
Receive<CombinedResponse>(resp => DoSomething(resp.Result1, resp.Result2));

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

Наконец, возможно использовать только основные примитивы akka и просто объединить частичные ответы самостоятельно.Это часто можно сделать с помощью так называемого Aggregator pattern .Есть несколько способов достижения этого, но в основном все они работают по схожей модели:

  • Держите в уме, сколько актеров должно ответить для полного ответа.
  • Сохраните частичные ответы вбуфер (список), который будет заполнен входящими ответами от других участников.Когда актер ответил, уменьшите количество актеров, которых нужно ждать.Как только это число достигнет 0, вы собрали полный ответ.
  • Сохраните информацию об оригинальном Sender актере, который запросил полный ответ, чтобы вы могли отправить его результат (при необходимости), один разполный ответ был собран.
  • Использование Context.ReceiveTimeout предотвращает бесконечное ожидание в случае, если некоторые ответы могут не прийти по какой-либо причине.
...