当前位置: 首页 > 知识库问答 >
问题:

Akka-保留对客户的引用

融泓
2023-03-14

全部的

我正在处理一个看似简单的案例,但它提出了一些设计挑战:

  1. 有一个带有客户端的本地参与者系统,它可以连接到运行大部分业务逻辑的远程系统。
  2. 远程系统将有一个固定的IP地址、端口等-因此,可以使用context.actorSelection(uri)策略来获取ActorRef,以获取当前参与者(或路由器后面的一组路由器)的化身。
  3. 作为服务器的远程系统不应该知道客户端的位置。

鉴于此,将消息从客户端传播到服务器,处理它们并将消息发送回客户端非常简单。即使有几个步骤,也可以通过层次结构传播响应,直到到达客户端调用的顶级远程执行组件,这将知道客户端上的发送方是谁。

假设在服务器端,我们有一个主参与者,它有一个由工作参与者组成的路由器。您可以让工作人员直接响应客户端,因为主机从客户端接收到的消息可以通过路由器作为“router.tell(message,sender)”而不是“router!message”发送给工作人员。当然,您也可以将工作人员的响应传播到主机,然后再传播到客户端。

但是,假设Worker抛出了一个异常。如果它的父级(Master)是它的主管,并且它处理Worker的故障,Master可以执行通常的重新启动/恢复/停止。但是假设我们也想将故障通知客户端,例如用于UI更新目的。即使我们通过Master的SupervisorStrategy处理Worker的故障,我们也不会知道在Master拦截Worker的故障时拥有处理请求有效负载的原始调用者(Client)是谁。

这是一张图表

客户端(本地)-

Worker抛出异常,Master处理它。现在,主服务器可以重新启动工作进程,但是它不知道通知哪个客户端,以防有几个客户端、它们的IP地址改变等等。

如果有一个客户端,并且该客户端有一个主机/端口/等等。为服务器所知,则可以使用context.actorSelection(uri)来查找客户端并向其发送消息。然而,由于服务器不知道客户端来自哪里(#3),这不应该是一个要求。

一个显而易见的解决方案是将消息从客户机传播到Worker,在有效负载中包含客户机的ActorRef,在这种情况下,主节点将知道向谁发送失败通知。虽然看起来很丑。有没有更好的办法?

我想客户端可以让Workers在DeathWatch上工作,但客户端不必知道服务器上actor DAG的详细信息。因此,我想我要回到从客户端发送的消息是否不仅应该包含最初预期的有效负载,还应该包含客户端的ActorRef的问题。

同样,这也带来了另一点。阿卡的“让它崩溃”哲学建议演员的主管应该处理演员的失败。然而,如果我们有一个客户机、一个主机(带有一个路由器)和一个工作机,如果工作机出现故障,主机可以重启它——但是它必须告诉客户机出了问题。在这种情况下,主服务器必须将来自客户机的消息关联到工作器,以便让客户机知道故障。另一种方法是将客户端的ActorRef与有效负载一起发送到Worker,这将允许客户端使用标准的try/catch方法来拦截失败,在失败之前向客户端发送消息,然后抛出将由主服务器处理的异常。然而,这似乎违背了Akka的一般哲学。既然处理器跟踪消息id,那么Akka持久性在这种情况下会有帮助吗?

提前感谢您的帮助!

最好

马雷克

共有2个答案

隆礼骞
2023-03-14

一种可能性是通过改变你的方法来避开大部分的复杂性。这对于您的用例可能可行,也可能不可行。

例如,如果可以预期异常,并且它不是需要重新启动工作参与者的,则不要让主主管处理它。只需为该异常(可能是异常本身,或包含异常的内容)构建适当的响应,并将其作为正常响应消息发送到客户端。例如,您可以发送 scala Try 消息,或者创建任何有意义的消息。

当然,也有非预期的异常,但在这种情况下,处理UI的参与者可以简单地超时并返回一个一般错误。由于异常是意外的,因此无论如何,您可能无法比一般的UI错误做得更好(例如,如果UI是基于HTTP的,则为500个错误),即使异常已传播到该层。当然,一个缺点是超时将问题报告给UI的时间比错误显式传播的时间更长。

最后,我认为将ActorRef作为有效负载的一部分发送,以便按照您的建议从主参与者内部处理这种情况,一点也不错误。我相信ActorRef的设计初衷是在参与者(包括远程参与者)之间发送它们。来自ActorRef的ScalaDoc:

actor的不可变且可序列化的句柄,它可能驻留在本地主机上,也可能不在同一个ActorSystem中。...

ActorRefs可以通过消息传递在参与者之间自由共享。

曹涵润
2023-03-14

快速回答,请使用这个:

def preRestart(reason: Throwable, message: Option[Any]): Unit

更详细的回答,没有简单的答案(因为我自己也在努力):

关于如何实现你需要的有几个想法。

你问的问题应该由工人回答客户还是主人。这取决于情况。

让我们假设客户发送给你一些工作W1,你把它传递给工人。工人失败了。现在的问题是,这项工作是否重要?如果是这样,主设备应该仍然保持对W1的引用,因为它可能会在不久的将来重试该尝试。也许是一些应该被持久化的数据和数据库的连接丢失了一秒钟?

如果工作不重要,你可以在客户端设置一个超时,即操作不成功,你就完成了。这样你就会丢失异常详细信息。但是也许没关系?你只想事后检查html" target="_blank">日志,然后你只需要给出一个“500服务器错误”的响应。

这并不像一开始看起来那么容易回答。

 类似资料:
  • 我从使用go的GRPC开始。我阅读了官方文档,并举了几个例子。 在大多数示例中,您不识别客户端,而是使用流读取/写入数据。我看到上下文中有用于检索身份验证信息的应用编程接口,并且可以为聊天请求识别客户端。但是,如果我想根据客户端标识保留流的引用/索引呢? 例如, 假设我在聊天室有3个用户。我将rpc表示为(也可能是服务器流) 例如,一个用户向该组发送一条消息,该组需要向另两个用户发送。因此,如果我

  • 问题内容: 我从javascript对象内部进行了一些Ajax调用。 在onreadystatechange函数内部,它不再引用主对象,因此我无法访问this.foo。我如何在XMLHttpRequest事件中保留对主对象的引用? 问题答案: 最简单的方法通常是将的值存储在局部变量中: 我也怀疑您的标识符确实是构造函数(您正在分配属性)。 如果是这种情况,请不要忘记添加正确的属性(因为您正在替换整

  • 我需要阻止用户访问Keycloak帐户客户机(/auth/realms/[MYREALM]/Account),但我需要这个客户机提供的Rest API。 我用的是Keycloak 4.1.0。我试图通过keycloak管理面板(/auth/admin/master/console/#/realms/[MYREALM]/clients)禁用account client,但是如果禁用此客户端,acco

  • 问题内容: 我刚刚开始使用原型JavaScript,并且在弄清楚范围更改时如何从原型函数内部保留对主对象的引用时遇到了麻烦。让我说明一下我的意思(我在这里使用jQuery): 我知道我可以通过在以下内容的开头保留对主对象的引用: 然后用于访问主要对象的属性。但是,当我拥有一大堆原型函数时会发生什么?我是否必须在每个文件的开头都保存对它的引用?似乎应该有一种更清洁的方法。那么这样的情况呢: 在那种情

  • 这是我认为我应该用于这种方法的布局:并且为了适应404路由,还可以使用。现在,如果我的Akka流知识对我有用的话,我需要使用来处理这样的事情,然而,这就是我被困住的地方。 在中,我可以为不同的endpoint进行简单的映射和flatMap,但在流中,这意味着将流划分为多个流,我不太确定该如何进行。我想过使用UnzipWith和Options或通用广播。 如能在这方面提供任何帮助,将不胜感激。 如果

  • 我们尝试在host-connection-pool下调整池、actor实例和所有其他参数的大小,但没有更好的效果。 欢迎任何建议!