2

I am trying to implement a basic broadcast router in which the routees are on remote machines.

The code is as follows :

localApp.conf

akka {

    log-dead-letters = 10
    log-dead-letters-during-shutdown = off

    actor {
        provider = "akka.remote.RemoteActorRefProvider"
        serialize-messages = on

        serializers {
            java = "akka.serialization.JavaSerializer"
        }

        serialization-bindings {
            "java.lang.String" = java
            "test.akkaLocal.LocalWrapper" = java
        }

        deployment {
            /LocalMaster/broadcastRouter {
                router = "broadcast"
                nr-of-instances = 1
                target {
                    nodes = ["akka.tcp://RemoteApp@127.0.0.1:10175"]
                }
            }
        }
    }
    remote {
        enabled-transports = ["akka.remote.netty.tcp"]
        netty {
            tcp {
                hostname = "127.0.0.1"
                port = 10174
            }
        }
    }
}

LocalApp.java

public class LocalApp
{
    public static void main(String[] args)
    {
        LocalApp app = new LocalApp();
        app.executeLocal();
    }

    private void executeLocal() {
        ActorSystem system = ActorSystem.create("LocalApp", ConfigFactory.load("localApp"));
        final ActorRef master = system.actorOf(Props.create(LocalMaster.class), "LocalMaster");
        master.tell(new LocalWrapper.Execute(), ActorRef.noSender());
    }

    public static class LocalMaster extends UntypedActor {

        @Override
        public void onReceive(Object message) throws Exception {
            if (message instanceof LocalWrapper.Execute) {

                ActorSelection remoteActor =
                        getContext().actorSelection("akka.tcp://RemoteApp@127.0.0.1:10175/user/RemoteMaster");

                ActorRef remoteRouter = getContext().actorOf(
                        Props.create(RemoteActor.class).withRouter(new FromConfig()), "broadcastRouter");

                String msg = "Hello";
                // remoteActor.tell(msg, getSelf());
                remoteRouter.tell(msg, getSelf());
            } else if (message instanceof String) {
                String response = (String) message;
                System.out.println(response);
            }
        }

    }

    public static class RemoteActor extends UntypedActor {
        @Override
        public void onReceive(Object message) throws Exception {
            if (message instanceof String) {
                String msg = (String) message;
                System.out.println(msg);

                String resp = "World";
                getSender().tell(resp, getSelf());

            }
        }
    }
}

In the remoteApp.conf, the port is given as 10175

RemoteApp.java

public class RemoteApp
{
    public static void main(String[] args)
    {
        RemoteApp app = new RemoteApp();
        app.executeRemote();
    }

    private void executeRemote() {
        ActorSystem system = ActorSystem.create("RemoteApp", ConfigFactory.load("remoteApp"));
        system.actorOf(Props.create(RemoteMaster.class), "RemoteMaster");
    }

    public static class RemoteMaster extends UntypedActor {

        @Override
        public void onReceive(Object message) throws Exception {
            if (message instanceof String) {
                String msg = (String) message;
                System.out.println(msg);
                String response = "World";
                getSender().tell(response, getSelf());
            }
        }
    }

}

Now I am not able to understand concept of remote routing. Does it deploy a local actor on remote machines and then send messages to them, or connect to remote actors on remote machines and then send messages to them ?

Using my code, I am able to send simple messages to the remote machine ( using actor selection ) the remoteActor.tell(msg, getSelf()) ( commented code ) in the LocalApp sends and receives messages and doesn't give any error.

But When I create the router using local Actor, I get dead letter errors.

[INFO] [02/04/2014 16:34:58.408] [RemoteApp-akka.actor.default-dispatcher-4] [akka://RemoteApp/system/endpointManager/reliableEndpointWriter-akka.tcp%3A%2F%2FLocalApp%40127.0.0.1%3A10174-0/endpointWriter/endpointReader-akka.tcp%3A%2F%2FLocalApp%40127.0.0.1%3A10174-0] 
Message [akka.remote.transport.AssociationHandle$InboundPayload] from Actor[akka://RemoteApp/deadLetters] to Actor[akka://RemoteApp/system/endpointManager/reliableEndpointWriter-akka.tcp%3A%2F%2FLocalApp%40127.0.0.1%3A10174-0/endpointWriter/endpointReader-akka.tcp%3A%2F%2FLocalApp%40127.0.0.1%3A10174-0#-288427524] was not delivered.
[1] dead letters encountered. This logging can be turned off or adjusted with configuration settings 'akka.log-dead-letters' and 'akka.log-dead-letters-during-shutdown'.

Can someone tell me what I am doing wrong ?

---------UPDATE----------

I Found out the problem. The remote and local classes were in different projects. During basic communication between the local and remote project, String was the type of the object transferred, that why it was successful. Is there a way to transfer objects of custom classes between two different projects ? I tried implementing Serializable and adding it to the conf file but it doesn't make a difference

4

1 回答 1

6

默认情况下,akka 将为自定义消息类使用 java 序列化。如果类定义在系统的两端(发送端和接收端)都可用(即在类路径中),那么您应该能够使用它进行远程通信。我的建议是有一个 jar 文件来表示系统两侧的类路径中可用的消息类。

Akka 还允许您为不同的消息类类型使用不同的序列化程序,因此您不会被 java 序列化所困,但如果您愿意,我建议先让它以这种方式工作,然后再尝试其他序列化程序。

于 2014-02-04T18:43:41.907 回答