简体   繁体   English

该实例的Akka Actor Path

[英]Akka Actor Path for that instance

I am using Java Play Framework. 我正在使用Java Play Framework。 I am using web sockets for client server interaction. 我正在使用Web套接字进行客户端服务器交互。 On the server side we have aka actors which respond to the client request. 在服务器端,我们还有响应客户端请求的actor。 The problem i am facing : I want ,that when the client opens a web socket connection with the Hakka actor on the server, it actually opens a pool for that actor, and then i need to trace the actor client path for that instance ,so that whenever some other action takes place in some other class, that class informs this actor (using the instance path which was traced) that the action has occurred and then this actor informs the user (client) that this action has occurred. 我面临的问题:我想,当客户端打开与服务器上的Hakka actor的Web套接字连接时,它实际上为该actor打开了一个池,然后我需要跟踪该实例的actor客户端路径,所以每当某个其他动作发生在某个其他类中时,该类通知该actor(使用被跟踪的实例路径)该动作已经发生,然后该actor通知用户(客户端)该动作已经发生。 I am actually using 我其实在用

String ClientPushActorPath = akka.serialization.Serialization.serializedActorPath(self());

the above to keep get the path for that instance of client user. 以上是为了获取客户端用户实例的路径。 But the next time when i try to hit this actor using this path , I am unable to find this actor. 但是下次当我尝试用这条路径击中这个演员时,我无法找到这个演员。 The way i am trying to hit the actor from another actor is : 我试图从另一个演员那里击中演员的方式是:

PushCacheManager cache = PushCacheManager.getInstance();
cache.load(qiid);
String ActorPath = cache.get("ClientPushActorPath");
ActorSelection ClientPushActor = system.actorSelection(ActorPath);
ClientPushActor.tell(m4, getSelf());

So the above code simply says that first i go and get the scots path from the cache (it was cached in memory for future use) and then i try to pass that path to actor selection .Once i get the object for actor selection i use that to tell the other actor the message i need to pass which is m4. 所以上面的代码简单地说,首先我去从缓存中获取scots路径(它被缓存在内存中供将来使用)然后我尝试将该路径传递给actor选择。一旦我得到了演员选择的对象我使用告诉其他演员我需要传递的消息是m4。 Please correct me where i am going wrong. 请纠正我出错的地方。 I am not able to see the actor using this path. 我无法看到演员使用此路径。 I feel , the way i am tracking the path is wrong. 我觉得,我跟踪路径的方式是错误的。 Please correct me . 请指正。 Than

Please bear with me, it will take some time to go through this but it should give you a good idea of what to do. 请耐心等待,这需要一些时间来完成,但它应该让你知道该怎么做。 Note: I am assuming that you still use Play 2.4.x and have not updated to Play 2.5.x yet. 注意:我假设您仍然使用Play 2.4.x并且还没有更新到Play 2.5.x. And also that you use Java (although if you are able to switch, I would recommend the Akka Scala API). 而且你使用Java(虽然如果你能够切换,我会推荐Akka Scala API)。


Step 1: defining the actor which is handling the WebSocket connection 第1步:定义处理WebSocket连接的actor

In your controller you would write this: 在你的控制器中你会写这个:

public static WebSocket<String> socket() {
    return WebSocket.withActor(MyWebSocketActor::props);
}

This means that every WebSocket connection will be handled by an actor instance of type MyWebSocketActor . 这意味着每个WebSocket连接都将由MyWebSocketActor类型的actor实例处理。 You will then have to implement the actor like this: 然后你必须像这样实现这个actor:

import akka.actor.*;

public class MyWebSocketActor extends UntypedActor {

    public static Props props(ActorRef out) {
        return Props.create(MyWebSocketActor.class, out);
    }

    private final ActorRef out;

    public MyWebSocketActor(ActorRef out) {
        this.out = out;
    }

    public void onReceive(Object message) throws Exception {
        if (message instanceof String) {
            out.tell("I received your message: " + message, self());
        }
    }
}

The ActorRef out parameter that you see is actually the underlying actor (generated from Play). 您看到的ActorRef out参数实际上是底层actor(从Play生成)。 You don't need to do anything with it, just remember that once you send something to this out actor, he will handle it to the client. 你不需要用它做任何事情,只记得有一次你送东西给这个out的演员,他将它处理到客户端。

You also have to define a proper route in your routes file: 您还必须在routes文件中定义正确的路径:

GET /ws controllers.Application.socket()

Step 2: defining how to manage all the WebSocket actors 第2步:定义如何管理所有WebSocket actor

In general you have two options - either you "look up" the actors created above or you provide some kind of mechanism to manage them (kind of registry) 通常,您有两个选项 - 要么“查找”上面创建的actor,要么提供某种管理它们的机制(注册表类型)

  • Step 2.1: looking up the WebSocket actors 步骤2.1:查找WebSocket演员

    The advantage here is that you don't need an extra registry/manager or similar. 这里的优点是您不需要额外的注册表/经理或类似的。 The disadvantage is that it is really hard to know which actor serves which WebSocket connection. 缺点是很难知道哪个actor服务于哪个WebSocket连接。

    You would use actorSelection for this: 你可以使用actorSelection

    system.actorSelection("system/websockets/*/handler");

    This works because as I mentioned earlier there are connection handler actors generated by Play - so their addresses are like this: akka://application/system/websockets/42/handler . 这是有效的,因为正如我之前提到的,Play有生成的连接处理程序actor - 所以它们的地址是这样的: akka://application/system/websockets/42/handler Again, this way you can get all the actors but not single ones (because you don't know their handler number). 同样,这样你就可以获得所有演员而不是单演员(因为你不知道他们的经纪人号码)。

  • Step 2b: managing the WebSocket actors The advantage here is that you can totally manage the actors and assign various information to them. 步骤2b:管理WebSocket演员这里的优点是你可以完全管理演员并为他们分配各种信息。 The disadvantage is that you have one more actor to take care of (although not really a problem, Akka is pretty good at this) 缺点是你还有一个演员可以照顾(虽然不是真正的问题,Akka很擅长这个)

You would create a new actor like: 你会创建一个新的演员,如:

 public class ManagerActor extends UntypedActor {

    List<ActorRef> slaves;

    public MyWebSocketActor() {
        this.slaves = new ArrayList<>();
    }

    public void onReceive(Object message) throws Exception {
        if (message instanceof RegisterMe) {
            // a new WebSocket was created so we can register him
            slaves.add(sender());

            // also register a DeathWatch so that we know when the WebSocket actor dies 
            context.watch(sender());
        } else if (message instanceof Terminated) {
            // remove from the list
            ...
        }
    }
 }

Step 3: putting all together 第3步:将所有内容放在一起

Now, remember our WebSocket actor from above? 现在,还记得上面的WebSocket演员吗? He should somehow register itself with the Manager. 他应该以某种方式向经理注册。 Again, you can do this in two ways: you can "look up" the Manager with context.system.actorSelection("user/manager") or if you already have a reference (an ActorRef ) to the Manager, you can provide it as a constructor parameter when creating the WebSocket actor 同样,您可以通过两种方式执行此操作:您可以使用context.system.actorSelection("user/manager") “查找”Manager,或者如果您已经拥有对Manager的引用( ActorRef ),则可以提供它作为创建WebSocket actor时的构造函数参数

You could make use of the preStart method which is available to every actor and do your registration: 您可以使用每个演员都可以使用的preStart方法并进行注册:

public class MyWebSocketActor extends UntypedActor {

   ....

   @Override
   public void preStart() throws Exception {
       context().system().actorSelection("user/manager").tell(RegisterMe, self());
       super.preStart();
   }
}

Now that you have all the WebSocket actors managed by the ... Manager, you can define new messages which he can handle and tell him that he has to forward the m4 to the clients. 现在您拥有了由...管理的所有WebSocket演员,您可以定义他可以处理的新消息并告诉他必须将m4转发给客户端。 Note that you can use something like a Map inside the Manager - where the ActorRef is the key and the value is some user-specific property or whatever you want. 请注意,您可以在Manager中使用类似Map的内容 - 其中ActorRef是键,值是某些特定于用户的属性或您想要的任何内容。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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