0

I'm new to akka remoting and I'm trying to simply send a message to a remote actor and get a response in return. I have 2 actor systems on localhost - different ports: MasterSystem and WorkerSystem. I have created an actor in WorkerSystem and tried sending a message to its remote address. But I keep on getting a 'dead letters encountered' message! Would appreciate any help. Thanks!

MainMaster.java

package pi_swarm_approx;

import akka.actor.ActorRef;
import akka.actor.ActorSelection;
import akka.actor.ActorSystem;
import akka.actor.UntypedActor;
import com.typesafe.config.ConfigFactory;

public class MainMaster extends UntypedActor{
    ActorSystem system;
    ActorRef actor;
    ActorSelection remoteActor;
    
    public MainMaster() {
        system = ActorSystem.create("MasterSystem", ConfigFactory.load("master"));
        System.out.println("MasterSystem created");
        MainWorker mw = new MainWorker();
        System.out.println("MainWorker obj created");
        remoteActor = mw.system.actorSelection("akka://WorkerSystem@localhost:2552/user/workerActor");
        
        System.out.println("Remote actor created");    
        remoteActor.tell("hello", getSelf());
        System.out.println("Message sent to remote actor");
    }
    
    public void onReceive(Object msg) {
        if (msg != null) {
            System.out.println("Got it back");
        }
         else {
            unhandled(msg);
            getContext().stop(getSelf());
         }
    }
}

MainWorker.java

package pi_swarm_approx;

import akka.actor.ActorSystem;
import akka.actor.ActorRef;
import com.typesafe.config.ConfigFactory;
import akka.actor.Props;

public class MainWorker {
    ActorSystem system;
    ActorRef actor;
    public MainWorker() {
        this.system = ActorSystem.create("WorkerSystem", ConfigFactory.load("worker"));
        actor = system.actorOf(Props.create(Worker.class), "workerActor");
    }
}

Worker.java

package pi_swarm_approx;

import akka.actor.UntypedActor;

public class Worker extends UntypedActor {  
    public void onReceive(Object msg) {
        System.out.println("Worker actor got message");
        if (msg != null) {
            getSender().tell("Request processed", getSelf());
        }
         else {
            unhandled(msg);
         }
        getContext().stop(getSelf());
    }
}

master.conf

akka {
  actor {
    provider = "cluster"
  }
  remote {
  transport = ["akka.remote.netty.tcp"]
    netty.tcp {
      hostname = "localhost"
      port = 2551
    }
  }
  
  clustering {
    cluster.name = "MasterSystem"
    role = "master"
  }
 }

worker.conf

akka {
  actor {
    provider = "cluster"
    deployment {
        /workerActor {
          remote = "akka.tcp://WorkerSystem@localhost:2552"
        }
  }
}

Output

In main
MasterSystem created
MainWorker obj created
Remote actor created
Message sent to remote actor
[INFO] [11/22/2021 16:01:34.531] [WorkerSystem-akka.actor.default-dispatcher-5] [akka://WorkerSystem/deadLetters] Message [java.lang.String] from Actor[akka://Main/user/app#402333018] to Actor[akka://WorkerSystem/deadLetters] was not delivered. [1] dead letters encountered. If this is not an expected behavior, then [Actor[akka://WorkerSystem/deadLetters]] may have terminated unexpectedly, This logging can be turned off or adjusted with configuration settings 'akka.log-dead-letters' and 'akka.log-dead-letters-during-shutdown'.
<=========----> 75% EXECUTING [18s]
  • Can you post minimal code to reproduce the error? The Github repo is cluttered and is not helpful in reproducing the error. – Johny T Koshy Nov 22 '21 at 12:11

1 Answers1

1

There are multiple problems with the code that you have posted. I am posting a minimal working code.

First, you are using a deprecated version of akka.actor.UntypedActor. This was deprecated in 2.4.0. If you are using maven change dependencies accordingly. Code was compiled and run on java 11.

build.sbt

libraryDependencies ++=
  Seq(
    "com.typesafe.akka" %% "akka-actor" % "2.6.17",
    "com.typesafe.akka" %% "akka-remote" % "2.6.17",
  )

For provider I have used remote instead of cluster. You can use cluster, but make sure you add the necessary dependencies. Configuration can be further simplified by removing repetitions, but you can do that as you explore.

master.conf

akka {
  actor {
    provider = "remote"
  }
  remote {
    artery {
      enabled = on
      transport = tcp
      canonical {
        hostname = "127.0.0.1"
        port = 2552
      }
    }
  }
}

worker.conf

akka {
  actor {
    provider = "remote"
  }
  remote {
    artery {
      enabled = on
      transport = tcp
      canonical {
        hostname = "127.0.0.1"
        port = 2551
      }
    }
  }
}

MainMaster.java

import akka.actor.AbstractActor;

public class MainMaster extends AbstractActor {
    @Override
    public Receive createReceive() {
        return receiveBuilder()
            .match(
                    String.class,
                    System.out::println)
            .matchAny(o -> System.out.println("received unknown message"))
            .build();
    }
}

Worker.java

public class Worker extends AbstractActor {

    @Override
    public Receive createReceive() {
        return receiveBuilder()
            .match(
                    String.class,
                    msg -> {
                        System.out.println(msg);
                        getSender().tell("Request processed", getSelf());
                    })
            .matchAny(o -> System.out.println("received unknown message"))
            .build();
    }
}

MainWorker.java

public class MainWorker {

    public static void main(String[] args) {
        ActorSystem system = ActorSystem.create("WorkerSystem", ConfigFactory.load("worker.conf"));
        ActorRef actor = system.actorOf(Props.create(Worker.class), "workerActor");
        System.out.println("worker started");
    }
}

Main.java

public class Main {
    public static void main(String[] args) {
        System.out.println("In main");
        ActorSystem system = ActorSystem.create("MasterSystem", ConfigFactory.load("master.conf"));
        ActorRef master = system.actorOf(Props.create(MainMaster.class), "master");

        ActorSelection remoteActor = system.actorSelection("akka://WorkerSystem@127.0.0.1:2551/user/workerActor");
        remoteActor.tell("Hello Worker", master);
    }
}
Johny T Koshy
  • 3,857
  • 2
  • 23
  • 40
  • Thanks for the reply. One question though; when is the WorkerSystem created? I don't see a MainWorker object getting created anywhere. – Deepika Vemuri Nov 23 '21 at 05:40
  • Being remote systems, you should consider `MainWorker` and `Main` as separate applications and run as such. In this particular case, run `MainWorker` first followed by `Main` so that an instance of `Worker` is initialized and is available for lookup from `Main`. – Johny T Koshy Nov 23 '21 at 05:53
  • Unfortunately, I'm still getting the 'dead letters encountered' message. I tried creating the workerActor in `Main.java` and `ActorSelection remoteActor = system1.actorSelection("akka://WorkerSystem/user/workerActor");` works. But, `ActorSelection remoteActor = system.actorSelection("akka://WorkerSystem@127.0.0.1:2551/user/workerActor");` doesn't. – Deepika Vemuri Nov 23 '21 at 07:37
  • If `MainWorker` is not already running when you start `Main`, you will get that message. Check if that's the case. – Johny T Koshy Nov 23 '21 at 08:19
  • Also, this `ActorRef actor = system1.actorOf(Props.create(Worker.class), "workerActor"); System.out.println(actor.path().address().host());` returns None. – Deepika Vemuri Nov 23 '21 at 08:23
  • Can you show the updated file structure and files in github? – Johny T Koshy Nov 23 '21 at 08:24
  • [Akka-remoting-repo](https://github.com/deepikavemuri/akka_remoting_exp) – Deepika Vemuri Nov 23 '21 at 08:36
  • `worker.conf` and `master.conf` are placed under `resources/configs`. They are accessed for `ActorSystem` creation using `ActorSystem.create("MasterSystem", ConfigFactory.load("master.conf"));`. Put the `conf` files in `resources` folder, it should work – Johny T Koshy Nov 23 '21 at 08:40
  • Yes, it's working now. Thank you! – Deepika Vemuri Nov 23 '21 at 09:23