Scala/Akka/ReactiveMongo: process does not terminate after system.shutdown() - scala

I just started learning Scala and Akka and now I am trying to develop an application that uses ReactiveMongo framework to connect to a MongoDb server.
The problem is that when I call system.shutdown() in the end of my App object, the process does not terminate and just hangs forever.
I am now testing the case when there is no connection available, so my MongoDB server is not running. I have the following actor class for querying the database:
class MongoDb(val db: String, val nodes: Seq[String], val authentications: Seq[Authenticate] = Seq.empty, val nbChannelsPerNode: Int = 10) extends Actor with ActorLogging {
def this(config: Config) = this(config.getString("db"), config.getStringList("nodes").asScala.toSeq,
config.getList("authenticate").asScala.toSeq.map(c => {
val l = c.unwrapped().asInstanceOf[java.util.HashMap[String, String]]; Authenticate(l.get("db"), l.get("user"), l.get("password"))
}),
config.getInt("nbChannelsPerNode"))
implicit val ec = context.system.dispatcher
val driver = new MongoDriver(context.system)
val connection = driver.connection(nodes, authentications, nbChannelsPerNode)
connection.monitor.ask(WaitForPrimary)(Timeout(30.seconds)).onFailure {
case reason =>
log.error("Waiting for MongoDB primary connection timed out: {}", reason)
log.error("MongoDb actor kills itself as there is no connection available")
self ! PoisonPill
}
val dbConnection = connection(db)
val tasksCollection = dbConnection("tasks")
val taskTargetsCollection = dbConnection("taskTargets")
import Protocol._
override def receive: Receive = {
case GetPendingTask =>
sender ! NoPendingTask
}
}
My app class looks like this:
object HelloAkkaScala extends App with LazyLogging {
import scala.concurrent.duration._
// Create the 'helloakka' actor system
val system = ActorSystem("helloakka")
implicit val ec = system.dispatcher
//val config = ConfigFactory.load(ConfigFactory.load.getString("my.helloakka.app.environment"))
val config = ConfigFactory.load
logger.info("Creating MongoDb actor")
val db = system.actorOf(Props(new MongoDb(config.getConfig("my.helloakka.db.MongoDb"))))
system.scheduler.scheduleOnce(Duration.create(60, TimeUnit.SECONDS), new Runnable() { def run() = {
logger.info("Shutting down the system")
system.shutdown()
logger.info("System has been shut down!")
}})
}
And the log output in my terminal looks like this:
[DEBUG] [08/07/2014 00:32:06.358] [run-main-0] [EventStream(akka://helloakka)] logger log1-Logging$DefaultLogger started
[DEBUG] [08/07/2014 00:32:06.358] [run-main-0] [EventStream(akka://helloakka)] Default Loggers started
00:32:06.443 INFO [run-main-0] [HelloAkkaScala$] - Creating MongoDb actor
00:32:06.518 DEBUG [helloakka-akka.actor.default-dispatcher-3] [reactivemongo.core.actors.MonitorActor] - Actor[akka://helloakka/temp/$a] is waiting for a primary... not available, warning as soon a primary is available.
00:32:06.595 DEBUG [helloakka-akka.actor.default-dispatcher-2] [reactivemongo.core.actors.MongoDBSystem] - Channel #-774976050 unavailable (ChannelClosed(-774976050)).
00:32:06.599 DEBUG [helloakka-akka.actor.default-dispatcher-2] [reactivemongo.core.actors.MongoDBSystem] - The entire node set is still unreachable, is there a network problem?
00:32:06.599 DEBUG [helloakka-akka.actor.default-dispatcher-2] [reactivemongo.core.actors.MongoDBSystem] - -774976050 is disconnected
00:32:08.573 DEBUG [helloakka-akka.actor.default-dispatcher-3] [reactivemongo.core.actors.MongoDBSystem] - ConnectAll Job running... Status: Node[localhost: Unknown (0/10 available connections), latency=0], auth=Set()
00:32:08.574 DEBUG [helloakka-akka.actor.default-dispatcher-3] [reactivemongo.core.actors.MongoDBSystem] - Channel #-73322193 unavailable (ChannelClosed(-73322193)).
00:32:08.575 DEBUG [helloakka-akka.actor.default-dispatcher-3] [reactivemongo.core.actors.MongoDBSystem] - The entire node set is still unreachable, is there a network problem?
00:32:08.575 DEBUG [helloakka-akka.actor.default-dispatcher-3] [reactivemongo.core.actors.MongoDBSystem] - -73322193 is disconnected
... (the last 3 messages repeated many times as per documentation the MongoDriver tries to re-connect with 2 seconds interval)
[ERROR] [08/07/2014 00:32:36.474] [helloakka-akka.actor.default-dispatcher-3] [akka://helloakka/user/$a] Waiting for MongoDB primary connection timed out: akka.pattern.AskTimeoutException: Ask timed out on [Actor[akka://helloakka/user/$c#1684233695]] after [30000 ms]
[ERROR] [08/07/2014 00:32:36.475] [helloakka-akka.actor.default-dispatcher-3] [akka://helloakka/user/$a] MongoDb actor kills itself as there is no connection available
... (the same 3 messages repeated again)
00:32:46.461 INFO [helloakka-akka.actor.default-dispatcher-4] [HelloAkkaScala$] - Shutting down the system
00:32:46.461 INFO [helloakka-akka.actor.default-dispatcher-4] [HelloAkkaScala$] - Awaiting system termination...
00:32:46.465 WARN [helloakka-akka.actor.default-dispatcher-2] [reactivemongo.core.actors.MongoDBSystem] - MongoDBSystem Actor[akka://helloakka/user/$b#537715233] stopped.
00:32:46.465 DEBUG [helloakka-akka.actor.default-dispatcher-5] [reactivemongo.core.actors.MonitorActor] - Monitor Actor[akka://helloakka/user/$c#1684233695] stopped.
[DEBUG] [08/07/2014 00:32:46.468] [helloakka-akka.actor.default-dispatcher-2] [EventStream] shutting down: StandardOutLogger started
00:32:46.483 INFO [helloakka-akka.actor.default-dispatcher-4] [HelloAkkaScala$] - System has been terminated!
And after that the process hands forever and does never terminate. What am I doing wrong?

You aren't doing anything incorrect. This is a known issue.
https://github.com/ReactiveMongo/ReactiveMongo/issues/148

Related

How to terminate Akka actor system from a main method?

I've this application using Akka Streams and ReactiveMongo. There are no user defined actors. The application is launched from a main method.
Problem is the JVM continues to run forever after the main method has completed. This is what I'm doing now:
val g = (file: String) => RunnableGraph.fromGraph(GraphDSL.create(Sink.ignore) {
implicit builder =>
sink =>
import GraphDSL.Implicits._
// Source
val A: Outlet[(String, String)] = builder.add(Source.fromIterator(() => parseMovies(file).iterator)).out
// Flow
val B: FlowShape[(String, String), Either[String, Movie]] = builder.add(findMovie)
// Flow
val C: FlowShape[Either[String, Movie], Option[String]] = builder.add(persistMovie)
A ~> B ~> C ~> sink.in
ClosedShape
})
def main(args: Array[String]): Unit = {
require(args.size >= 1, "Path to file is required.")
g(args(0)).run
.onComplete(_ => Await.result(system.terminate(), 5.seconds))
}
I've read this thread, and this, none of which work. system.shutdown is deprecated and I don't have any explicit actors to watch for. I can call system.exit but that's hardly graceful.
From the logs, it appears that Akka is trying to shut down but then I see a bunch of Mongo messages.
2017-01-13 11:35:57.320 [DEBUG] a.e.EventStream.$anonfun$applyOrElse$4 - shutting down: StandardOutLogger started
2017-01-13 11:36:05.397 [DEBUG] r.c.a.MongoDBSystem.debug - [Supervisor-1/Connection-2] ConnectAll Job running... Status: {{NodeSet None Node[localhost:27017: Primary (10/10 available connections), latency=6], auth=Set() }}
2017-01-13 11:36:05.420 [DEBUG] r.c.a.MongoDBSystem.debug - [Supervisor-1/Connection-2] RefreshAll Job running... Status: {{NodeSet None Node[localhost:27017: Primary (10/10 available connections), latency=6], auth=Set() }}
// more of MongoDBSystem.debug messages
Why won't it.just.die?
I think you want to add a shutdown hook or call actorSystem.registerOnTermination(driver.close()):
def main(args: Array[String]): Unit = {
import akka.actor.CoordinatedShutdown
require(args.size >= 1, "Path to file is required.")
CoordinatedShutdown(system).addTask(CooordinatedShutdown.PhaseBeforeActorSystemTerminate, "shutdownMongoDriver") { () => driver.close(5.seconds); Future.successful(Done) }
g(args(0)).run.onComplete(_ => CoordinatedShutdown(system).run())
}

TestProbe missing akka message

I'm trying to test a simple actor which is connecting to another remote on tcp. Here is my actor
/**
* Created by chris on 6/6/16.
*/
class Client(listener : ActorRef, actorSystem: ActorSystem) extends Actor with BitcoinSLogger {
/**
* The manager is an actor that handles the underlying low level I/O resources (selectors, channels)
* and instantiates workers for specific tasks, such as listening to incoming connections.
*/
def manager = IO(Tcp)(actorSystem)
def receive = {
case Tcp.Connect(remote,_,_,_,_) => manager ! Tcp.Connect(remote)
case Tcp.CommandFailed(_: Tcp.Connect) =>
logger.debug("Connection failed")
listener ! "connect failed"
context stop self
case c # Tcp.Connected(remote, local) =>
logger.debug("Tcp connection to: " + remote)
logger.debug("Local: " + local)
listener ! c
val connection = sender()
connection ! Tcp.Register(self)
context become {
case data: ByteString =>
connection ! Tcp.Write(data)
case Tcp.CommandFailed(w: Tcp.Write) =>
// O/S buffer was full
listener ! "write failed"
case Tcp.Received(data) =>
listener ! data
case "close" =>
connection ! Tcp.Close
case _: Tcp.ConnectionClosed =>
listener ! "connection closed"
context stop self
}
}
def sendMessage(msg : NetworkRequest, peer : NetworkIpAddress) : Future[NetworkResponse] = ???
}
object Client {
//private case class ClientImpl(remote: InetSocketAddress, listener: ActorRef, actorSystem : ActorSystem) extends Client
def apply(listener : ActorRef, actorSystem : ActorSystem) : Props = {
Props(classOf[Client], listener, actorSystem)
}
}
here is my test case
class ClientTest extends TestKit(ActorSystem("ClientTest")) with FlatSpecLike with MustMatchers with BeforeAndAfterAll {
"Client" must "connect to a node on the bitcoin network" in {
val probe = TestProbe()
val hostName = "testnet-seed.bitcoin.schildbach.de"
val socket = new InetSocketAddress(hostName, TestNet3.port)
val peerMessageHandler = PeerMessageHandler(system)
val client = system.actorOf(Client(peerMessageHandler, system))
probe.send(client, Tcp.Connect(socket))
probe.expectMsgType[Tcp.Connected](10.seconds)
}
override def afterAll: Unit = {
TestKit.shutdownActorSystem(system)
}
}
finally, I can tell the connection is successful because my log messages are being hit:
2016-06-08 09:58:21,548 - [DEBUG] - from class
org.bitcoins.spvnode.networking.Client in
ClientTest-akka.actor.default-dispatcher-4 Tcp connection to:
testnet-seed.bitcoin.schildbach.de:18333
2016-06-08 09:58:21,550 - [DEBUG] - from class
org.bitcoins.spvnode.networking.Client in
ClientTest-akka.actor.default-dispatcher-4 Local:
/192.168.1.107:43782
however my test case is failing with this error
[info] ClientTest:
[info] Client
[info] - must connect to a node on the bitcoin network *** FAILED ***
[info] java.lang.AssertionError: assertion failed: timeout (10 seconds) during expectMsgClass waiting for class akka.io.Tcp$Connected
[info] at scala.Predef$.assert(Predef.scala:170)
[info] at akka.testkit.TestKitBase$class.expectMsgClass_internal(TestKit.scala:435)
[info] at akka.testkit.TestKitBase$class.expectMsgType(TestKit.scala:417)
[info] at akka.testkit.TestKit.expectMsgType(TestKit.scala:737)
[info] at org.bitcoins.spvnode.networking.ClientTest$$anonfun$1.apply$mcV$sp(ClientTest.scala:25)
[info] at org.bitcoins.spvnode.networking.ClientTest$$anonfun$1.apply(ClientTest.scala:17)
[info] at org.bitcoins.spvnode.networking.ClientTest$$anonfun$1.apply(ClientTest.scala:17)
[info] at org.scalatest.Transformer$$anonfun$apply$1.apply$mcV$sp(Transformer.scala:22)
[info] at org.scalatest.OutcomeOf$class.outcomeOf(OutcomeOf.scala:85)
[info] at org.scalatest.OutcomeOf$.outcomeOf(OutcomeOf.scala:104)
[info] ...
Seems like I am missing something simple, but I can't figure out exactly what it is.
To answer my own question, I just made probe the listener isntead of trying to listen on the Client actor itself.
"Client" must "connect to a node on the bitcoin network" in {
val probe = TestProbe()
val hostName = "testnet-seed.bitcoin.schildbach.de"
val socket = new InetSocketAddress(hostName, TestNet3.port)
val peerMessageHandler = PeerMessageHandler(system)
val client = TestActorRef(Client(probe.ref,system))
//probe.send(client, Tcp.Connect(socket))
client ! Tcp.Connect(socket)
probe.expectMsgType[Tcp.Connected](10.seconds)
}

Not able to invoke Remote Actor

I wrote this code to create a remote actor
object Main extends App {
val system = ActorSystem("keyvalue")
system.actorOf(Props[KeyValueActor], name = "keyvalue-db")
}
class KeyValueActor extends Actor {
val map = new util.HashMap[String, Object]
val log = Logging(context.system, this)
override def receive = {
case SetRequest(key, value) => {
log.info(s"received set request key ${key} value ${value}")
map.put(key, value)
sender() ! Status.Success
}
case GetRequest(key) => log.info(s"recieved get request ${key}")
sender() ! KeyValue(map.get(key))
case _=> log.info("unknown message")
}
}
I started my server using activator run and this printed the message
[info] Running com.abhi.akka.Main
[INFO] [01/10/2016 20:21:52.461] [run-main-0] [Remoting] Starting remoting
[INFO] [01/10/2016 20:21:52.617] [run-main-0] [Remoting] Remoting started;
listening on addresses :[akka.tcp://keyvalue#127.0.0.1:2552]
[INFO] [01/10/2016 20:21:52.619] [run-main-0] [Remoting]
Remoting now listens on addresses: [akka.tcp://keyvalue#127.0.0.1:2552]
but now when i try to call my remote actor using this client code
object KeyValueClient {
def main(args: Array[String]) : Unit = {
implicit val system = ActorSystem("LocalFileSystem")
implicit val timeout = Timeout(2 seconds)
val keyValueActorRef = system.actorSelection("akka.tcp://keyvalue#127.0.0.1:2552/user/keyvalue-db")
keyValueActorRef ! SetRequest("foo", "bar")
(keyValueActorRef ? GetRequest("foo")).onSuccess({
case x : KeyValue => println(s"got value ${x.value}")
})
}
}
it throws an error message
[INFO] [01/10/2016 20:25:33.345] [LocalFileSystem-akka.actor.default-dispatcher-2] [akka://LocalFileSystem/deadLetters] Message [com.abhi.akka.messages.SetRequest] from Actor[akka://LocalFileSystem/deadLetters] to Actor[akka://LocalFileSystem/deadLetters] 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'.
[INFO] [01/10/2016 20:25:33.346] [LocalFileSystem-akka.actor.default-dispatcher-2] [akka://LocalFileSystem/deadLetters] Message [com.abhi.akka.messages.GetRequest] from Actor[akka://LocalFileSystem/temp/$a] to Actor[akka://LocalFileSystem/deadLetters] was not delivered. [2] 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'.
My Full code is available at
https://github.com/abhitechdojo/keyvaluedb.git
https://github.com/abhitechdojo/keyvalueclient.git
EDIT: I solved the problem based on the suggestion given by Mustafa Simov. The client side needed this configuration file
akka {
actor {
provider = "akka.remote.RemoteActorRefProvider"
deployment {
/keyvalue-db {
remote = "akka.tcp://keyvalue#127.0.0.1:2552"
}
}
}
}
Then you create the actor using
val actor = system.actorOf(Props[KeyValueActor], "keyvalue-db")
I have looked at your client code and I think it is just a configuration problem. In order to use akka-remoting, you must configure your client too. So you must create an application.conf for client ActorSystem as you created for server.
Akka remoting is peer-to-peer and not really a good fit for client-server
Because of this both sides in remoting must be able to connect to the other side, as either of them can initiate communication. Both of your applications therefore needs to configure a remoting actor-ref provider and host+port pair that the other node can connect through. You can read details about how to do this in the akka docs here.

How to send message from Supervisor to Actor once Actor restarts?

Requirement?
- There has to be a long running process(daemon) that should run forever
- In case of any exceptions, it should be restarted, but if it fails again twice, no restart efforts should be taken
Problem I face?
- The actor is restarted but no message sent again
What I have?
Main Class
package com.learner.ahka.runforever
import akka.actor.ActorSystem
import com.typesafe.config.ConfigFactory
object RaceEvent extends App {
val config = ConfigFactory.parseString( """
akka.loglevel = "DEBUG"
akka.actor.debug {
receive = on
lifecycle = on
}
""")
val system = ActorSystem.create("race", config)
val coach = system.actorOf(Coach.props(), "coach")
coach ! GetSetGo
}
Supervisor
package com.learner.ahka.runforever
import akka.actor.SupervisorStrategy.{Escalate, Restart}
import akka.actor._
import akka.event.LoggingReceive
import scala.concurrent.duration._
case object GetSetGo
object Coach {
def props(): Props = Props[Coach];
}
class Coach() extends Actor with ActorLogging {
val runner = context.actorOf(Runner.props(new Marathon), "runner")
override def supervisorStrategy: SupervisorStrategy = OneForOneStrategy(maxNrOfRetries = 2, withinTimeRange = 5 seconds) {
case _: RuntimeException => Restart
}
override def receive = LoggingReceive {
case GetSetGo => runner ! GoForIt
}
}
Actor
package com.learner.ahka.runforever
import akka.actor.Status.Failure
import akka.actor.{Actor, ActorLogging, Props}
import akka.event.LoggingReceive
import akka.pattern.pipe
object Runner {
def props(race: Race) = Props(classOf[Runner], race)
}
class Runner(race: Race) extends Actor with ActorLogging {
import context.dispatcher
override def receive: Receive = LoggingReceive {
case GoForIt => race.start pipeTo self
case Failure(throwable) => throw throwable
}
}
Actual work
package com.learner.ahka.runforever
import scala.concurrent.Future
case object GoForIt
trait Race {
def start: Future[Any]
}
class Marathon extends Race {
import scala.concurrent.ExecutionContext.Implicits.global
override def start: Future[Any] = future
val future = Future {
for (i <- 1 to 3) {
println("I am a Marathon Runner!")
Thread.sleep(1000)
}
throw new RuntimeException("MarathonRunner is tired")
}
}
Logs
[DEBUG] [05/30/2015 16:03:35.696] [main] [EventStream(akka://race)] logger log1-Logging$DefaultLogger started
[DEBUG] [05/30/2015 16:03:35.698] [main] [EventStream(akka://race)] Default Loggers started
[DEBUG] [05/30/2015 16:03:35.704] [race-akka.actor.default-dispatcher-4] [akka://race/system] now supervising Actor[akka://race/system/deadLetterListener#-1391310385]
[DEBUG] [05/30/2015 16:03:35.706] [race-akka.actor.default-dispatcher-3] [akka://race/system/deadLetterListener] started (akka.event.DeadLetterListener#191ba186)
[DEBUG] [05/30/2015 16:03:35.710] [race-akka.actor.default-dispatcher-2] [akka://race/user] now supervising Actor[akka://race/user/coach#-1161587711]
I am a Marathon Runner!
[DEBUG] [05/30/2015 16:03:35.722] [race-akka.actor.default-dispatcher-3] [akka://race/user/coach] started (com.learner.ahka.runforever.Coach#66f0f319)
[DEBUG] [05/30/2015 16:03:35.722] [race-akka.actor.default-dispatcher-4] [akka://race/user/coach/runner] started (com.learner.ahka.runforever.Runner#72f67980)
[DEBUG] [05/30/2015 16:03:35.723] [race-akka.actor.default-dispatcher-3] [akka://race/user/coach] now supervising Actor[akka://race/user/coach/runner#755574648]
[DEBUG] [05/30/2015 16:03:35.723] [race-akka.actor.default-dispatcher-3] [akka://race/user/coach] received handled message GetSetGo
[DEBUG] [05/30/2015 16:03:35.725] [race-akka.actor.default-dispatcher-4] [akka://race/user/coach/runner] received handled message GoForIt
I am a Marathon Runner!
I am a Marathon Runner!
[DEBUG] [05/30/2015 16:03:38.739] [race-akka.actor.default-dispatcher-3] [akka://race/user/coach/runner] received handled message Failure(java.lang.RuntimeException: MarathonRunner is tired)
[ERROR] [05/30/2015 16:03:38.752] [race-akka.actor.default-dispatcher-4] [akka://race/user/coach/runner] MarathonRunner is tired
java.lang.RuntimeException: MarathonRunner is tired
at com.learner.ahka.runforever.Marathon$$anonfun$1.apply(Race.scala:22)
at com.learner.ahka.runforever.Marathon$$anonfun$1.apply(Race.scala:17)
at scala.concurrent.impl.Future$PromiseCompletingRunnable.liftedTree1$1(Future.scala:24)
at scala.concurrent.impl.Future$PromiseCompletingRunnable.run(Future.scala:24)
at scala.concurrent.impl.ExecutionContextImpl$AdaptedForkJoinTask.exec(ExecutionContextImpl.scala:121)
at scala.concurrent.forkjoin.ForkJoinTask.doExec(ForkJoinTask.java:260)
at scala.concurrent.forkjoin.ForkJoinPool$WorkQueue.runTask(ForkJoinPool.java:1339)
at scala.concurrent.forkjoin.ForkJoinPool.runWorker(ForkJoinPool.java:1979)
at scala.concurrent.forkjoin.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:107)
[DEBUG] [05/30/2015 16:03:38.753] [race-akka.actor.default-dispatcher-2] [akka://race/user/coach/runner] restarting
[DEBUG] [05/30/2015 16:03:38.755] [race-akka.actor.default-dispatcher-2] [akka://race/user/coach/runner] restarted
UPDATE
If I don't delegate to Future, everything works as expected, even in case of restart, but when delegated to Future, Future does not get executed in case of actor restart. See here
You could override the postRestart method to send a message back to the parent to notify it of the restart, then watch for that new message type in the parent and respond accordingly. If context.parent won't work happily for that purpose (I tend not to rely on it), then have the Coach actor pass it's self actor reference as a new constructor parameter when instantiating the Runner.
It is not well known, but you can access sender() from the supervisorStrategy. This means that you can easily identify the actor that you are going to restart (sender() will point to the ActorRef that is currently being decided on). This is completely safe.

"Dead Letters encountered" error while running AKKA remote actors

I am trying to run remote actors using AKKA, on my localhost, but each time I get this error. It says dead letters encountered. I searched on internet and found out that this error comes when actors receive a message after its thread is stopped. So I am looking for a way to keep the actors alive on remote machines. I am using akka actors and not the scala actors.
[INFO] [09/16/2013 18:44:51.426] [run-main] [Remoting] Starting remoting
[INFO] [09/16/2013 18:44:51.688] [run-main] [Remoting] Remoting started; listening on addresses :[akka.tcp://actorSystem1#localhost:2209]
[INFO] [09/16/2013 18:44:51.759] [actorSystem2-akka.actor.default-dispatcher-5] [akka://actorSystem2/deadLetters] Message [java.lang.String] from
Actor[akka://actorSystem2/deadLetters] to Actor[akka://actorSystem2/deadLetters] 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'.
Following is the code.
import akka.actor.{Actor, Props, ActorSystem}
import com.typesafe.config.ConfigFactory
import akka.remote._
object MyApp extends App {
val actorSystem1 = ActorSystem("actorSystem1", ConfigFactory.parseString("""
akka {
actor {
provider = "akka.remote.RemoteActorRefProvider"
}
remote {
transport = ["akka.remote.netty.tcp"]
netty.tcp {
hostname = "localhost"
port = 2209
}
}
}
"""))
val actorSystem2 = ActorSystem("actorSystem2")
actorSystem1.actorOf(Props(new Actor {
def receive = {
case x: String =>
Thread.sleep(1000)
println("RECEIVED MESSAGE: " + x)
} }), "simplisticActor")
val remoteActor = actorSystem2.actorFor("akka://actorSystem1#localhost:2209/user/simplisticActor")
remoteActor ! "TEST 1"
remoteActor ! "TEST 2"
Thread.sleep(1000)
actorSystem1.shutdown()
actorSystem2.shutdown()
}
Thanks in advance.
I think I see a few issues with your code that might be leading to deadletters. First, if your intention is to lookup an actor on a remote system from actorSystem2 into actorSystem1, then you will still need to set up remoting properties for actorSystem1, most specifically, you need to make sure it's using the RemoteActorRefProvider. If you don't do this, system 2 will not be able to lookup a remote actor in system 1. Once you make this change, I would also change your remote actor lookup from:
val remoteActor = actorSystem2.actorFor("akka://actorSystem1#localhost:2209/user/simplisticActor")
to:
val remoteActor = actorSystem2.actorSelection("akka.tcp://actorSystem1#localhost:2209/user/simplisticActor")
The actorFor method has been deprecated and also I think you left off the .tcp part of the akka protocol for looking up the remote actor.
Make these changes and then see if things work for you.