嵌套请求的正确模式

本文关键字:模式 请求 嵌套 | 更新日期: 2023-09-27 18:11:37

我有一个actor,它有许多个子节点,我正在查询它以获得其子节点中的数据聚合。此操作可能需要几秒钟。

我正准备这么做,感觉完全错了。句柄方法由Ask<>调用。

public void Handle(Message message)
{
    var children = Context.GetChildren();
    var tasks = new List<Task<Result>>();
    foreach (var child in children)
    {
        var t = child.Ask<Result>(new Query);
        tasks.Add(t);
    }
    Task.WaitAll(tasks.ToArray()); // Gah!
    // do some work
    Sender.Tell(new Response(new Results()));
}

我有一些想法,但我想得到一些输入,因为我真的不想重新发明一个20边轮。

我很担心对Sender的引用,以及当我最终调用Tell时它将指向什么,因为它是一个静态调用。

我最终使用了Task.WhenAll延续,但仍然不相信它是正确的Akka方式-这是这里的重点。我可以让它工作,我只是想知道最佳实践选项

嵌套请求的正确模式

一般来说,Ask应该只用于与来自外部服务的参与者的通信,几乎从不用于两个参与者之间的通信。这比使用Tell要贵得多。另一个问题是使用Task.WaitAll,它实际上阻塞了当前线程,直到所有响应都到达,这也对性能不利,并可能导致死锁。

类似的话题已经在github上讨论过了。

聚合问题的一般解为:

  • 为聚合过程创建一个单独的参与者
  • 用actor列表初始化它,它应该从actor中收集数据并记住actor,收集到的结果将通知actor。
  • 为每个角色发送请求/查询
  • 处理每个请求/查询响应,将其聚合在单独的数据结构中,并从等待参与者列表中删除发送者。
  • 一旦没有actor等待-发送结果并停止当前actor(负责数据聚合的actor)。
  • 附加ReceiveTimeout机制,当由于某种原因不是所有参与者都能在合理的时间内响应时-当超时将达到时,您可能返回失败或迄今为止收集的响应列表。

PS:不要使用TypedActor——它对性能也不好,而且会被淘汰。