从 websocket actor 接收时播放 actor sender() return 本身

Play actor sender() return itself when receive from the websocket actor

我正在使用 Play 2.5。我正在使用 Websocket actor 将消息发送到 Routes Actor。但是,当在路由上收到消息时,sender() 方法 returns 路由本身而不是那个 Websocket actor。

申请如下

@Singleton
class Application @Inject()(implicit val system: ActorSystem,
                            implicit val wsClient: WSClient,
                            implicit val config: Configuration,
                            implicit val materializer: Materializer) extends Controller {
...
  lazy val routesActor = system.actorOf(Props(classOf[RoutesActor]), "routes")

  def ws = WebSocket.accept[JsValue, JsValue] { request =>
    ActorFlow.actorRef(out => UserActor.props(out)(routesActor))
  }

...
}

UserActor:

class UserActor(out: ActorRef)(implicit val RoutesActor: ActorRef) extends Actor with ActorLogging {

  def receive() = {
    case json: JsValue => {
      val parsedQuery = parseQuery(json)
      cachesActor ! (parsedQuery, self)
      log.info("this user is:" + self)
    }
  }

路线演员

class RoutesActor extends Actor with ActorLogging {
  def receive = {
    case (q: ParsedQuery, out: ActorRef) => {
      log.info("Routes:" + self + " get query from : " + sender() + " actually is:" + out)
    }
  }
}

log.info 打印了以下行:

[info] a.RoutesActor - Routes:Actor[akka://application/user/routes#854844162] get query from : Actor[akka://application/user/routes#854844162] actually is:Actor[akka://application/user/$b/flowActor#-75193340]

如您所见,sender() 指向它自己而不是 flowActor。因此,我不能使用 sender() 来回复消息。这让我很困惑。有人知道这里出了什么问题吗?

tell 的签名是 def !(message: Any)(implicit sender: ActorRef): Unit,因此消息的发送者通过隐式参数获取。当您从 UserActor 中发送消息时,这是定义为 class 参数的 implicit val RoutesActor: ActorRef

如果您想使用 UserActor 作为发件人,请从参数列表中删除隐式关键字或明确提供 self 作为发件人:cachesActor.tell((parsedQuery, self), self).

如果您想使用原始发件人,也就是UserActor中的sender(),您可以使用forward代替:cachesActor.forward((parsedQuery, self))。这将显式使用 context.sender() 而不是隐式的 RoutesActor 作为消息的发送者。