【发布时间】:2021-07-25 21:02:00
【问题描述】:
我正在尝试存储某条消息的发件人,以便将来检查它是否是与以前一样发送操作的同一发件人。现在这不起作用,我读到它是因为 Akka 询问忽略了实际的发件人并制作了自己的临时演员,该演员用作发件人,直到解决未来。有没有办法解决这个问题,这样您就可以在不使用 tell 操作的情况下访问消息的真实发件人?
【问题讨论】:
我正在尝试存储某条消息的发件人,以便将来检查它是否是与以前一样发送操作的同一发件人。现在这不起作用,我读到它是因为 Akka 询问忽略了实际的发件人并制作了自己的临时演员,该演员用作发件人,直到解决未来。有没有办法解决这个问题,这样您就可以在不使用 tell 操作的情况下访问消息的真实发件人?
【问题讨论】:
将发送参与者的ActorRef 放入消息中。当您迁移到 Akka Typed 时,您必须这样做,因此即使在使用 Akka Classic 时,也不要依赖 sender() 是一个好习惯。
【讨论】:
没有不使用tell 的解决方法,因为Akka 中没有任何东西不使用tell(Akka 提供的询问模式是基于tells 的模式)。
ask 模式实现必须使用临时 actor 来封装超时逻辑,并且不会将该功能泄漏给请求 ask 的 actor。
这留下了两个选项让接收者访问“真正的”发送者:
您可以将onBehalfOf ActorRef 字段添加到您作为询问发送的消息中(如果询问来自您控制receive 的演员之外的情况,您可能希望将其设为可选),并让接收者使用它而不是 sender。
您可以在发送参与者中自己实现询问模式:这只是一个tell,在超时到期后向发送参与者安排一条消息,然后在您的消息协议中使用一些方法(请求和响应)来确定给定的响应是针对哪个问题的)。
【讨论】:
这是一个有趣的问题,正如 Tim 和 Levi 指出的那样,没有干净的方法可以做到这一点。即使在 akka 类型中,也不是直截了当的方法。因为虽然发送者是明确的,但要求适配器在不同参与者的协议之间进行映射是很常见的。
如果你想在 Actor 中跟踪消息的来源,我建议你在 Actor 的协议中明确说明,并使用 opaque 类型来表示消息中跟踪它的来源。然后,对客户来说,你在做什么是显而易见的。当一个 ActorRef 回复和一个用作源混在一起时,这也使得 bug 变得更加困难。
为此重载 ActorRef 可能会导致混乱,尤其是在移动到 akka 类型之后,您需要一个 ActorRef 作为发送者,另一个作为源/身份。
这是一个演员类型的例子(我手头没有经典的 akka 项目)。
/** Opaque value to represent a unique actor as the source of messages */
final case class ActorSource private (ref: ActorRef[_])
object ActorSource {
/** Constructing ActorSource from the context ensures actor is who it says it is */
def apply[T](context: ActorContext[T]): ActorSource = new ActorSource(context.self)
}
final case class TrackedMessage(data: String, source: ActorSource, sender[ActorRef[ReplyProtocol]])
【讨论】: