質問

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

役に立ちましたか?

解決

By default, akka will use java serialization for custom message classes. If the class definition is available (i.e. in the class path) on both sides of the system (sending and receiving side), then you should be able to use it for remote communication. My suggestion would be to have a jar file representing the message classes that is available in the classpath on both sides of the system.

Akka will also let you use different serializers for different message class types, so you're not stuck with java serialization, but I suggest getting it to work that way first before experimenting with other serializers if you feel so inclined.

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top