Harmeet Singh Taara
Harmeet Singh Taara

Reputation: 6611

Akka Actor: Remote actor exception "Futures timed out after"

i am new for Akka, i am using Akka 2.3.3 version for creating actors. I am going to create remote actor and trying to access with client. Whenever i am going to run test-case, the following exception will throw:

[INFO] [04/27/2016 07:51:23.727] [Localsystem-akka.actor.default-dispatcher-3] [akka://Localsystem/deadLetters] Message [com.harmeetsingh13.chapter2.messages.SetRequest] from Actor[akka://Localsystem/temp/$a] to Actor[akka://Localsystem/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] [04/27/2016 07:51:23.745] [Localsystem-akka.actor.default-dispatcher-3] [akka://Localsystem/deadLetters] Message [com.harmeetsingh13.chapter2.messages.GetRequest] from Actor[akka://Localsystem/temp/$b] to Actor[akka://Localsystem/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'.

Futures timed out after [10 seconds]
java.util.concurrent.TimeoutException: Futures timed out after [10 seconds]
at scala.concurrent.impl.Promise$DefaultPromise.ready(Promise.scala:219)
at scala.concurrent.impl.Promise$DefaultPromise.result(Promise.scala:223)
at scala.concurrent.Await$$anonfun$result$1.apply(package.scala:190)
at scala.concurrent.BlockContext$DefaultBlockContext$.blockOn(BlockContext.scala:53)
at scala.concurrent.Await$.result(package.scala:190)
at com.harmeetsingh13.chapter2.SClientIntegrationSpec$$anonfun$1$$anonfun$apply$mcV$sp$1.apply$mcV$sp(SClientIntegrationSpec.scala:18)
at com.harmeetsingh13.chapter2.SClientIntegrationSpec$$anonfun$1$$anonfun$apply$mcV$sp$1.apply(SClientIntegrationSpec.scala:15)
at com.harmeetsingh13.chapter2.SClientIntegrationSpec$$anonfun$1$$anonfun$apply$mcV$sp$1.apply(SClientIntegrationSpec.scala:15)
at org.scalatest.Transformer$$anonfun$apply$1.apply$mcV$sp(Transformer.scala:22)
at org.scalatest.OutcomeOf$class.outcomeOf(OutcomeOf.scala:85)
at org.scalatest.OutcomeOf$.outcomeOf(OutcomeOf.scala:104)
at org.scalatest.Transformer.apply(Transformer.scala:22)
at org.scalatest.Transformer.apply(Transformer.scala:20)
at org.scalatest.FunSpecLike$$anon$1.apply(FunSpecLike.scala:422)
at org.scalatest.Suite$class.withFixture(Suite.scala:1122)
at com.harmeetsingh13.chapter2.SClientIntegrationSpec.withFixture(SClientIntegrationSpec.scala:11)
at org.scalatest.FunSpecLike$class.invokeWithFixture$1(FunSpecLike.scala:419)
at org.scalatest.FunSpecLike$$anonfun$runTest$1.apply(FunSpecLike.scala:431)
at org.scalatest.FunSpecLike$$anonfun$runTest$1.apply(FunSpecLike.scala:431)
at org.scalatest.SuperEngine.runTestImpl(Engine.scala:306)
at org.scalatest.FunSpecLike$class.runTest(FunSpecLike.scala:431)
at com.harmeetsingh13.chapter2.SClientIntegrationSpec.runTest(SClientIntegrationSpec.scala:11)
at org.scalatest.FunSpecLike$$anonfun$runTests$1.apply(FunSpecLike.scala:464)
at org.scalatest.FunSpecLike$$anonfun$runTests$1.apply(FunSpecLike.scala:464)
at org.scalatest.SuperEngine$$anonfun$traverseSubNodes$1$1.apply(Engine.scala:413)
at org.scalatest.SuperEngine$$anonfun$traverseSubNodes$1$1.apply(Engine.scala:401)
............

My Server code as below: Main.scala

object Main extends App{


 private val configFile = getClass.getClassLoader.getResource("application.conf").getFile;
 private val config = ConfigFactory.parseFile(new File(configFile ))

 val system = ActorSystem("SimpleClientServer", config)
 system.actorOf(Props[AkkadmeyDB], name = "akkademy-db")
}

application.conf:

akka{
 actor{
  provider = "akka.remote.RemoteActorRefProvider"
 }
remote{
 enabled-transports = ["akka.remote.netty.tcp"]
  netty.tcp {
   hostname = "127.0.0.1"
   port = 2552
  }
  log-sent-messages = on
  log-received-messages = on
 }
}

AkkadmeyDB.scala Actor class:

class AkkadmeyDB extends Actor{

 val map = new HashMap[String, Object]
 val log = Logging(context.system, this)

 override def receive: Receive = {
  case SetRequest(key, value) =>
   log.info("received SetRequest - key: {} value: {}", key, value)
   map.put(key, value)
   sender() ! Status.Success
  case GetRequest(key) =>
   log.info("received GetRequest - key: {}", key)
   val response = map.get(key)
   response match{
     case Some(x) => sender() ! x
     case None => Status.Failure(new KeyNotFoundException(key))
   }
   case o => Status.Failure(new ClassNotFoundException())
  }
 }

Client Code as below: SClient.scala

class SClient(remoteIp: String) {

  private implicit val timeout = Timeout(10 seconds)
  private implicit val system = ActorSystem("Localsystem")
  private val remoteAddress = s"akka.tcp://SimpleClientServer@$remoteIp/user/akkademy-db";
  private val remoteDb = system.actorSelection(remoteAddress)

  def set(key: String, value: Object) = {
   remoteDb ? SetRequest(key, value)
  }

  def get(key: String) = {
    remoteDb ? GetRequest(key)
  }
}

SClientIntegrationSpec.scala Test case:

class SClientIntegrationSpec extends FunSpecLike with Matchers {

  val client = new SClient("127.0.0.1:2552")
  describe("akkadment-db-client"){
    it("should set a value"){
      client.set("jame", new Integer(1313))
      val futureResult = client.get("james")
      val result = Await.result(futureResult, 10 seconds)
      result should equal (1313)
    }
  }
}

When i see the logs of my remote application, this seems like, the request hit doesn't go to the server. what is the problem in my sample code running?

Upvotes: 2

Views: 2075

Answers (2)

Harmeet Singh Taara
Harmeet Singh Taara

Reputation: 6611

For solving above problem, we need to follow two steps that are metnion below:

  1. When i am creating a server code, i am excluding application.conf from my server application, that's why, client application not able to connect with server. The code are using in built.sbt is as below:

    mappings in (Compile, packageBin) ~= { _.filterNot { case (_, name) =>
     Seq("application.conf").contains(name)
    }}
    

After commenting above code, the client see the server successfully.

  1. In Learning Scala chapter 2 jasongoodwin explain the code of client and server actor system. But there are some Errata in book and missing application.conf configuration for client. Because when we run both code in same PC, we are facing already port bind exception because by default actors are using 2552 port for accessing and we already define this port for our server application. So, application.conf also need for client as below:

    akka {
      actor {
        provider = "akka.remote.RemoteActorRefProvider"
      }
      remote {
        enabled-transports = ["akka.remote.netty.tcp"]
        netty.tcp {
          hostname = "127.0.0.1"
          port = 0
        }
        log-sent-messages = on
        log-received-messages = on
      }
    }
    

Here Port 0 means any free port.

After that, above code are running successfully.

Upvotes: 4

khlumzeemee
khlumzeemee

Reputation: 11

There is an application.conf file in the client project as well which is not mentioned in the book. Make sure you create that file under the resources folder with the following content:

akka {
  actor {
    provider = "akka.remote.RemoteActorRefProvider"
  }
}

See the official github repo

Upvotes: 1

Related Questions