Hi,
I have an issue related to ports when trying to remote (Scala 2.10.4, Akka 2.3.1). This is stripped down code that doesn't actually do anything remotely itself. When I set the port to 0 in the application.conf file, it finds a free port and works without throwing an exception, shown here as the result of running lsof -i -n -P
com.apple 3205 username 10u IPv4 0xdcc81blahblah 0t0 UDP *:*
java 4739 username 61u IPv6 0xdcc81blahblah 0t0 TCP 127.0.0.1:57230 (LISTEN)
java 4739 username 63u IPv6 0xdcc81blahblah 0t0 TCP [::1]:57229->[::1]:57228 (FIN_WAIT_1)
java 4739 username 81u IPv6 0xdcc81blahblah 0t0 TCP 127.0.0.1:57231 (LISTEN)
If I then manually code the assigned port into my worker code (not included), I can send a message to the master and receive it no problem. However, when I set the port to 2552, it throws a java.net.BindException: Address already in use. My question is, why is it throwing this exception when the port wasn't bound prior to running the app? It appears that the process itself is what's binding the port, as shown in the following.
com.apple 3205 username 10u IPv4 0xdcc81blahblah 0t0 UDP *:*
java 4772 username 61u IPv6 0xdcc81blahblah 0t0 TCP 127.0.0.1:2552 (LISTEN)
java 4772 username 63u IPv6 0xdcc81blahblah 0t0 TCP [::1]:57237->[::1]:57236 (FIN_WAIT_1)
If I try to set the port in the application.conf file to what was previously assigned when setting the port to 0, I get the same behaviour as when I try to set it to 2552. I get exactly the same behaviour regardless of whether I run this on my MacBook Pro Retina or Linux Server.
The code:
import akka.actor._
import akka.actor.SupervisorStrategy._
import scala.concurrent.duration._
import com.typesafe.config._
import scala.util._
import akka.event.Logging
class RemoteMaster() extends Actor {
import context.dispatcher
def receive = {
case str:String => println("Message is " + str)
case msg => println("RemoteMaster: Unhandled Message" + msg)
}
}
object RemoteMaster {
val config = ConfigFactory.load()
val system = ActorSystem("system", config)
val log = Logging(system.eventStream, "blah.remote.main")
def main(args:Array[String]) {
val config = ConfigFactory.load()
val system = ActorSystem("system", config)
val listener = system.actorOf(Props(new RemoteMaster),"rm")
system.eventStream.subscribe(listener, classOf[DeadLetter])
system.actorSelection("akka://system/user/rm") ! "Test"
}
}
The application.conf:
akka {
# Akka version, checked against the runtime version of Akka.
version = "2.3.1" # for regular use
# Event handlers to register at boot time (Logging$DefaultLogger logs to STDOUT)
event-handlers = ["akka.event.slf4j.Slf4jLogger"]
# Log level used by the configured loggers (see "event-handlers") as soon
# Options: ERROR, WARNING, INFO, DEBUG
loglevel = "INFO"
# Log level for the very basic logger activated during AkkaApplication startup
# Options: ERROR, WARNING, INFO, DEBUG
stdout-loglevel = "ERROR"
actor {
provider = "akka.remote.RemoteActorRefProvider"
}
remote {
enabled-transports = ["akka.remote.netty.tcp"]
netty.tcp {
hostname = "127.0.0.1"
port = 2552
# port = 0
}
}
}
Build.scala (ugly as hell):
import sbt._
import sbt.Keys._
import sbtassembly.Plugin._
import AssemblyKeys._
object ProjectBuild extends Build {
val useConsole = SettingKey[Boolean]("use-console")
val jvmOptions = Seq("-server","-Xms2g","-Xmx4g")
lazy val root = Project(
id = "Remote",
base = file("."),
settings = Project.defaultSettings ++ assemblySettings ++ Seq(
name := "Remote",
organization := "com.epoch6",
scalaVersion := "2.10.4",
scalacOptions ++= Seq( "-deprecation","-feature"),
// run fork settings
fork in run := true,
javaOptions in run := jvmOptions,
mainClass in (Compile, run) := Some("com.epoch6.remote.RemoteMaster"),
testOptions += Tests.Setup( cl =>
cl.loadClass("org.slf4j.LoggerFactory").
getMethod("getLogger",cl.loadClass("java.lang.String")).
invoke(null,"ROOT")
),
// akka and atmos settings
useConsole := false,
credentials += Credentials(Path.userHome / "atmos.credentials"),
resolvers += "Typesafe Repo" at "http://repo.typesafe.com/typesafe/releases/",
resolvers += "Sonatype shapshot repo" at "https://oss.sonatype.org/content/repositories/snapshots/",
libraryDependencies <++= useConsole { Dependencies.akka },
ivyXML <<= useConsole { Dependencies.excludes },
// library dependencies
libraryDependencies ++= Dependencies.dependencies,
// Fat jar settings
jarName in assembly := "Remote.jar",
test in assembly := {},
mainClass in assembly := Some("com.epoch6.remote.RemoteMaster")
)
)
}
object Dependencies {
object V {
val Akka = "2.3.1"
}
val akkaSlf4j = "com.typesafe.akka" %% "akka-slf4j" % V.Akka
val akkaTestkit = "com.typesafe.akka" %% "akka-testkit" % V.Akka
val akkaActor = "com.typesafe.akka" %% "akka-actor" % V.Akka
val akkaRemote = "com.typesafe.akka" %% "akka-remote" % V.Akka
val akkaCluster = "com.typesafe.akka" %% "akka-cluster" % V.Akka
val originalAkka = Seq(akkaSlf4j, akkaTestkit, akkaActor, akkaRemote, akkaCluster)
val dependencies = Seq(
"joda-time" % "joda-time" % "1.6.2",
"org.scalatest" % "scalatest_2.10" % "2.0.M8",
"org.scalacheck" %% "scalacheck" % "1.10.1" % "test",
"ch.qos.logback" % "logback-classic" % "1.0.7"
)
val normalExcludes = {
<dependencies>
</dependencies>
}
def akka(atmos: Boolean) = originalAkka
def excludes(atmos: Boolean) = normalExcludes
}
The output when port set to 0:
sbt run
[info] Loading project definition from /Users/username/projects/Remote/project/project
[info] Loading project definition from /Users/username/projects/Remote/project
[info] Set current project to Remote (in build file:/Users/username/projects/Remote/)
[info] Running com.epoch6.remote.RemoteMaster
[info] [INFO] [04/10/2014 14:18:51.535] [main] [Remoting] Starting remoting
[info] [INFO] [04/10/2014 14:18:51.691] [main] [Remoting] Remoting started; listening on addresses :[akka.tcp://sys...@127.0.0.1:59083]
[info] [INFO] [04/10/2014 14:18:51.692] [main] [Remoting] Remoting now listens on addresses: [akka.tcp://sys...@127.0.0.1:59083]
[info] [INFO] [04/10/2014 14:18:51.718] [main] [Remoting] Starting remoting
[info] [INFO] [04/10/2014 14:18:51.727] [main] [Remoting] Remoting started; listening on addresses :[akka.tcp://sys...@127.0.0.1:59084]
[info] [INFO] [04/10/2014 14:18:51.727] [main] [Remoting] Remoting now listens on addresses: [akka.tcp://sys...@127.0.0.1:59084]
[info] Message is Test
The exception thrown when port set to 2552:
[info] Loading project definition from /Users/username/projects/Remote/project/project
[info] Loading project definition from /Users/username/projects/Remote/project
[info] Set current project to Remote (in build file:/Users/username/projects/Remote/)
[info] Running com.epoch6.remote.RemoteMaster
[info] [INFO] [04/10/2014 14:05:02.449] [main] [Remoting] Starting remoting
[info] [INFO] [04/10/2014 14:05:02.610] [main] [Remoting] Remoting started; listening on addresses :[akka.tcp://sys...@127.0.0.1:2552]
[info] [INFO] [04/10/2014 14:05:02.611] [main] [Remoting] Remoting now listens on addresses: [akka.tcp://sys...@127.0.0.1:2552]
[info] [INFO] [04/10/2014 14:05:02.637] [main] [Remoting] Starting remoting
[error] Exception in thread "main" org.jboss.netty.channel.ChannelException: Failed to bind to: /127.0.0.1:2552
[error] at org.jboss.netty.bootstrap.ServerBootstrap.bind(ServerBootstrap.java:272)
[error] at akka.remote.transport.netty.NettyTransport$$anonfun$listen$1.apply(NettyTransport.scala:392)
[info] [ERROR] [04/10/2014 14:05:02.649] [main] [Remoting] Remoting error: [Startup failed] [
[error] at akka.remote.transport.netty.NettyTransport$$anonfun$listen$1.apply(NettyTransport.scala:389)
[error] at scala.util.Success$$anonfun$map$1.apply(Try.scala:206)
[info] akka.remote.RemoteTransportException: Startup failed
[error] at scala.util.Try$.apply(Try.scala:161)
[info] at akka.remote.Remoting.akka$remote$Remoting$$notifyError(Remoting.scala:128)
[info] at akka.remote.Remoting.start(Remoting.scala:193)
[error] at scala.util.Success.map(Try.scala:206)
[info] at akka.remote.RemoteActorRefProvider.init(RemoteActorRefProvider.scala:184)
[error] at scala.concurrent.Future$$anonfun$map$1.apply(Future.scala:235)
[info] at akka.actor.ActorSystemImpl.liftedTree2$1(ActorSystem.scala:617)
[error] at scala.concurrent.Future$$anonfun$map$1.apply(Future.scala:235)
[info] at akka.actor.ActorSystemImpl._start$lzycompute(ActorSystem.scala:615)
[error] at scala.concurrent.impl.CallbackRunnable.run(Promise.scala:32)
[info] at akka.actor.ActorSystemImpl._start(ActorSystem.scala:615)
[error] at akka.dispatch.BatchingExecutor$Batch$$anonfun$run$1.processBatch$1(BatchingExecutor.scala:67)
[info] at akka.actor.ActorSystemImpl.start(ActorSystem.scala:632)
[error] at akka.dispatch.BatchingExecutor$Batch$$anonfun$run$1.apply$mcV$sp(BatchingExecutor.scala:82)
[info] at akka.actor.ActorSystem$.apply(ActorSystem.scala:141)
[error] at akka.dispatch.BatchingExecutor$Batch$$anonfun$run$1.apply(BatchingExecutor.scala:59)
[info] at akka.actor.ActorSystem$.apply(ActorSystem.scala:118)
[error] at akka.dispatch.BatchingExecutor$Batch$$anonfun$run$1.apply(BatchingExecutor.scala:59)
[info] at com.epoch6.remote.RemoteMaster$.main(RemoteMaster.scala:28)
[info] at com.epoch6.remote.RemoteMaster.main(RemoteMaster.scala)
[error] at scala.concurrent.BlockContext$.withBlockContext(BlockContext.scala:72)
[error] at akka.dispatch.BatchingExecutor$Batch.run(BatchingExecutor.scala:58)
[info] Caused by: org.jboss.netty.channel.ChannelException: Failed to bind to: /127.0.0.1:2552
[error] at akka.dispatch.TaskInvocation.run(AbstractDispatcher.scala:41)
[info] at org.jboss.netty.bootstrap.ServerBootstrap.bind(ServerBootstrap.java:272)
[error] at akka.dispatch.ForkJoinExecutorConfigurator$AkkaForkJoinTask.exec(AbstractDispatcher.scala:393)
[info] at akka.remote.transport.netty.NettyTransport$$anonfun$listen$1.apply(NettyTransport.scala:392)
[error] at scala.concurrent.forkjoin.ForkJoinTask.doExec(ForkJoinTask.java:260)
[info] at akka.remote.transport.netty.NettyTransport$$anonfun$listen$1.apply(NettyTransport.scala:389)
[error] at scala.concurrent.forkjoin.ForkJoinPool$WorkQueue.runTask(ForkJoinPool.java:1339)
[info] at scala.util.Success$$anonfun$map$1.apply(Try.scala:206)
[error] at scala.concurrent.forkjoin.ForkJoinPool.runWorker(ForkJoinPool.java:1979)
[info] at scala.util.Try$.apply(Try.scala:161)
[error] at scala.concurrent.forkjoin.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:107)
[info] at scala.util.Success.map(Try.scala:206)
[error] Caused by: java.net.BindException: Address already in use
[info] at scala.concurrent.Future$$anonfun$map$1.apply(Future.scala:235)
[error] at sun.nio.ch.Net.bind(Native Method)
[error] at sun.nio.ch.ServerSocketChannelImpl.bind(ServerSocketChannelImpl.java:124)
[error] at sun.nio.ch.ServerSocketAdaptor.bind(ServerSocketAdaptor.java:59)
[info] at scala.concurrent.Future$$anonfun$map$1.apply(Future.scala:235)
[info] at scala.concurrent.impl.CallbackRunnable.run(Promise.scala:32)
[error] at org.jboss.netty.channel.socket.nio.NioServerBoss$RegisterTask.run(NioServerBoss.java:193)
[info] at akka.dispatch.BatchingExecutor$Batch$$anonfun$run$1.processBatch$1(BatchingExecutor.scala:67)
[error] at org.jboss.netty.channel.socket.nio.AbstractNioSelector.processTaskQueue(AbstractNioSelector.java:372)
[info] at akka.dispatch.BatchingExecutor$Batch$$anonfun$run$1.apply$mcV$sp(BatchingExecutor.scala:82)
[error] at org.jboss.netty.channel.socket.nio.AbstractNioSelector.run(AbstractNioSelector.java:296)
[info] at akka.dispatch.BatchingExecutor$Batch$$anonfun$run$1.apply(BatchingExecutor.scala:59)
[error] at org.jboss.netty.channel.socket.nio.NioServerBoss.run(NioServerBoss.java:42)
[info] at akka.dispatch.BatchingExecutor$Batch$$anonfun$run$1.apply(BatchingExecutor.scala:59)
[error] at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:895)
[info] at scala.concurrent.BlockContext$.withBlockContext(BlockContext.scala:72)
[error] at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:918)
[info] at akka.dispatch.BatchingExecutor$Batch.run(BatchingExecutor.scala:58)
[error] at java.lang.Thread.run(Thread.java:695)
[info] at akka.dispatch.TaskInvocation.run(AbstractDispatcher.scala:41)
[info] at akka.dispatch.ForkJoinExecutorConfigurator$AkkaForkJoinTask.exec(AbstractDispatcher.scala:393)
[info] at scala.concurrent.forkjoin.ForkJoinTask.doExec(ForkJoinTask.java:260)
[info] at scala.concurrent.forkjoin.ForkJoinPool$WorkQueue.runTask(ForkJoinPool.java:1339)
[info] at scala.concurrent.forkjoin.ForkJoinPool.runWorker(ForkJoinPool.java:1979)
[info] at scala.concurrent.forkjoin.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:107)
[info] Caused by: java.net.BindException: Address already in use
[info] at sun.nio.ch.Net.bind(Native Method)
[info] at sun.nio.ch.ServerSocketChannelImpl.bind(ServerSocketChannelImpl.java:124)
[info] at sun.nio.ch.ServerSocketAdaptor.bind(ServerSocketAdaptor.java:59)
[info] at org.jboss.netty.channel.socket.nio.NioServerBoss$RegisterTask.run(NioServerBoss.java:193)
[info] at org.jboss.netty.channel.socket.nio.AbstractNioSelector.processTaskQueue(AbstractNioSelector.java:372)
[info] at org.jboss.netty.channel.socket.nio.AbstractNioSelector.run(AbstractNioSelector.java:296)
[info] at org.jboss.netty.channel.socket.nio.NioServerBoss.run(NioServerBoss.java:42)
[info] at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:895)
[info] at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:918)
[info] at java.lang.Thread.run(Thread.java:695)
[info] ]
[info] [INFO] [04/10/2014 14:05:02.655] [system-akka.remote.default-remote-dispatcher-7] [akka://system/system/remoting-terminator] Shutting down remote daemon.
[info] [INFO] [04/10/2014 14:05:02.656] [system-akka.remote.default-remote-dispatcher-7] [akka://system/system/remoting-terminator] Remote daemon shut down; proceeding with flushing remote transports.
[info] [INFO] [04/10/2014 14:05:02.662] [ForkJoinPool-5-worker-15] [Remoting] Remoting shut down
[info] [INFO] [04/10/2014 14:05:02.662] [system-akka.remote.default-remote-dispatcher-6] [akka://system/system/remoting-terminator] Remoting shut down.
Thanks,
Bruce