简体   繁体   中英

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

I'm using the Play 2.5. I'm using a Websocket actor to send the message to Routes Actor. However, when the msg get received on Routes the sender() method returns Routes itself instead of that Websocket actor.

The application is as below

@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))
  }

...
}

The 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)
    }
  }

The Routes Actor

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

The log.info printed the following line:

[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]

As you can see, the sender() is pointed to itself instead of the flowActor. Thus, I can't use the sender() to reply the message. It confuses me a lot. Does anyone have some ideas what goes wrong here?

The signature of tell is def !(message: Any)(implicit sender: ActorRef): Unit , so the sender of a message gets picked up via an implicit parameter. When you send a message from within the UserActor , this is the implicit val RoutesActor: ActorRef that is defined as a class parameter.

If you want to use the UserActor as a sender, either remove the implicit keyword from the parameter list or provide self explicitly as the sender: cachesActor.tell((parsedQuery, self), self) .

If you want to use the original sender, the one that is also the sender() in the UserActor , you can use forward instead: cachesActor.forward((parsedQuery, self)) . This will explicitly use context.sender() instead of the implicit RoutesActor as the sender of the message.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM