首页 > 解决方案 > 如何在 Akka.Net 中组合两个异步服务响应数据的响应

问题描述

我正在通过两个参与者进行两个异步服务调用

Actor 1 -> Fetch Data -> 这将返回一些响应

Actor 2 -> Fetch Data -> 这将返回一些响应。

如何在 Akka.Net 中结合这两个结果。在 Akka.net 中我们需要遵循什么模式吗?

标签: akka.net

解决方案


最简单的方法是使用询问模式:

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. 它将阻止一个actor处理任何其他消息,直到整个方法完成执行(包括完成两个t1and t2)。
  2. 它利用了Ask它有自己的性能影响 - 与例如相比并不大。数据库 I/O,但在许多情况下它可能太多(如果你担心性能)。

解决第 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));

这将不需要参与者等待两个任务完成,同时可以自由处理其他消息。然而,这仍然使用任务和询问。

最后,可以只使用核心 akka 原语并简单地自己聚合部分响应。这通常可以使用所谓的聚合器模式来完成。有多种实现方式,但基本上它们都在相似的模型上运行:

  • 继续计算需要多少参与者才能做出完整的响应。
  • 将部分响应保存在缓冲区(列表)中,该缓冲区将填充来自其他参与者的传入响应。当演员响应时,减少等待的演员数量。一旦该数字达到 0,您就已经组装了一个完整的响应。
  • 保留有关请求完整响应的原始参与者的信息Sender,以便在组装完整响应后向其发送结果(如有必要)。
  • Context.ReceiveTimeout如果某些响应可能因任何原因无法到达,请使用防止无限等待。

推荐阅读