How to keep Scala Process Alive? - scala

I type "sbt run", and compilation is ok, the server binds to the port, and then the process quietly terminates. How can I keep the process alive though? (I'm running an akka tcp server pulled straight from the akka docs -- should remain alive.)
Pseudocode:
object Main extends App {
val ac = ActorSystem();
val s = ac.actorOf(WebSocketManager.props());
}
Edit: The process stays alive after adding into build.sbt:
Compile / run / fork := true
Not sure what this does or if correct, but it works.

Related

Enable tilde trigger with Akka and sbt

With sbt it is possible to do ~run to recompile and run the program when the source changes. However once an ActorSystem is created it does not work anymore.
When the system is shutdown it works, but I don't want to shutdown the system.
import akka.actor.ActorSystem
object Test {
def main(args: Array[String]) : Unit = {
val system = ActorSystem()
// if this line is removed, source code detection is disabled
system.shutdown()
}
}
Is there any workaround ?
You have to remember that SBTs ~run by itself is not hot-reloading, it is simply "once the process finishes, run it again please". Akka's thread-pools are non-daemonic, which means that until the ActorSystem is "alive" the program will not terminate, thus SBT's ~run won't trigger again.
Instead you might want to look into the sbt-revolver SBT plugin, which can do what you're looking for (including for Akka based apps).

SBT to run Play app exits immediately when started using scala.sys.process.run?

I am writing an integration test that needs to start up several applications. One of these applications is a Play one as a SBT project called appA.
I am able to start the app on the right port using scala.sys.process as follows:
import scala.sys.process._
import org.scalatest._
class Main extends FeatureSpec with Matchers{
val app = Seq("sbt", "project appA", "run 7777").run
println(app.exitValue)
}
The spawned application however exits immediately with return value 0. No errors are displayed to the console. I just see:
[info] play - Listening for HTTP on /0:0:0:0:0:0:0:0:3000
(Server started, use Ctrl+D to stop and go back to the console...)
[success] Total time: 1 s, completed Feb 27, 2014 10:26:56 PM
0
The 0 at the end of the output is from calling exitValue on the created process. exitValue blocks until the spawned process exits.
How can I run the Play application without it exiting immediately? Is there a better way to start the application?
SBT has 2 run modes - interactive and batch. If you run without any args it goes to interactive mode and does not exit. When you run it by passing commands it runs in a batch mode and exits when the last command is complete. It does not matter if your application inside SBT runs in a forked JVM or not.
Thus to "fix" it you can apply this hack: add ~ command to the end of the list of sbt commands/args:
val app = Seq("sbt", "project appA", "run 7777", "~").run
~ is used to watch source code for changes and recompile when it happens. Thus SBT will never exit unless stopped by a user or killed.
A cleaner way would be to run Play application in a Jetty container (assuming you have WAR to run) or such by calling a main class that starts up Jetty with a command like java com.example.MyMain but that requires additional setup.

Why does my actorFor fail when deployed to a Akka Microkernel JAR?

Have a somewhat simple project deployed to a JAR. I am starting up a supervisor actor that confirms it is booting up by sending out the following log message:
[akka://service-kernel/user/Tracker] Starting new Tracker
However, when I go to reference the actor via actorFor locally with an sbt run, it finds it no problem. In production, I use the same .actorFor("akka://service-kernel/user/Tracker") and it throws a NullPointerException. I can confirm via the logs that in production, the Tracker has sent out its confirmation that it booted up.
Are there any issues when using a Microkernel deployed to a JAR to make actor references?
Edit
I am suspecting that both the way I reference the system and the way Akka treats the start up class are related to the issue. Since I have specified a start up class called ServiceKernel, I am performing the reference as such: ServiceKernel.system.actorFor. Will provide an answer if confirmed.
Confirmed that it was related to the startup class handling the Microkernel.
The ServiceKernel mentioned above is used in the start script to boot up the Microkernel JAR: ./start com.package.ServiceKernel. In an sbt shell, this isn't needed so the alternative class I provided works well for referencing an Actor System.
However, in a Microkernel the ServiceKernel appears to be using a different Actor System altogether, so if you reference that system (like I did) then actorFor lookups will always fail. I solved the problem by passing the system down into the boot classes into the specific class where I was making the actorFor reference and it worked. Did it like this (pseudo-code):
class ServiceKernel extends Bootable {
val system = ActorSystem("service-kernel")
def startup = {
system.actorOf(Props(new Boot(isDev, system))) ! Start
}
}
And then passing it to an HttpApi class:
class Boot(val isDev: Boolean, system: ActorSystem) extends Actor with SprayCanHttpServerApp {
def receive = {
case Start =>
// setup HTTP server
val service = system.actorOf(Props(new HttpApi(system)), "tracker-http-api")
}
}

Akka Actor can't connect to remote server where Scala Actor could

I got a little problem. I just moved the client-server-communication of my current project from remote Scala Actors to remote Akka Actors.
Everything worked fine while testing on my local machine but once I tried to run the code with the client and server at different machines the client can't reach the server anymore (I get a java.nio.channels.NotYetConnectedException). I double and tripple checked the ip and port being used. It's the same host data I used in the code with the Scala actors (which by the way still work. So apparently nothing changed at the firewall settings and server is technically reachable)
Here are the important parts of the code (which I mostly copy pasted from akkas homepage):
On the server actor
import akka.actor.Actor._
import akka.actor.{Actor, ActorRef, Supervisor}
override def preStart = {
// I also tried the servers external ip here
remote.start(host, 1357)
// SERVER_SERVICE_NAME is a string constant in a trait that both server
// and client extend
// all actual work is refered to SessionActor
remote.registerPerSession(SERVER_SERVICE_NAME, actorOf[SessionActor])
}
and on the client:
import akka.actor.Actor._
import akka.actor.{Actor, ActorRef, Supervisor}
override def preStart = {
// CLIENT_SERVICE_NAME is a string constant
Actor.remote.start("localhost", 5678).register(CLIENT_SERVICE_NAME, self)
// I also tried "Thread sleep 1000" here just in case
// internalServer is a private var of the type Option[ActorRef]
// host and serverPort are actually read from a propertiesfile. Guess this
// doesn't matter. I checked them.
internalServer = Some(
remote.actorFor(SERVER_SERVICE_NAME, host, serverPort)
)
// Again I tried "Thread sleep 1000" here. Didn't help neither
internalServer foreach (server => {
(server !! Ping) foreach (_ match { // !!! this is where the exception is thrown !!!
case Pong => println("connected")
case _ => println("something's fishy")
})
})
}
I am using:
Scala 2.8.1 (although I'm no sure whether the machines at my client are 2.8 or 2.8.1, I use the scala-library.jar from the akka distribution)
Akka 1.0
I know that you can't debugg my code her but I'd be very thankfull for any kind of hint or idea what might be going wrong here.
P.S.: the Exception is thrown within a splitsecond after trying to send the Ping. So I didn't bother increasing the Timeout-time.
DISCLAIMER: I am the PO of Akka
Try using a raw IP address instead of a hostname in remote.start(), if that doesn't solve it you have 2 options:
Make sure that the two parties can
DNS resolve eachother
Upgrade to
current master (1.1-SNAPSHOT), since
I've made quite a few changes to
avoid name resolution.
Does that help?

How do I turn off the Scala Fast Compilation server's (FSC) timeout?

I am using a Scala compilation server. This is probably not related to my IDE IntelliJ IDEA, but I will just inform you that I start the Scala compilation server through a special run configuration in that IDE.
After some time that goes by without compiling anything, the compilation server terminates, without any message. Usually, I only notice this when I try to compile something and compilation fails. Then, I need to start the compilation server again, and of course the next compilation takes a long time, because it's once more the first compilation since starting the compilation server.
How do I turn off that timeout? I looked at the manpage for scalac, and there seems to be no option for it. I can add VM options for that run configuration.
Pass -max-idle 0 as parameter. It will work on a very (very!) recent nightly, and it should be available on Scala 2.9.0 when it comes out. However, there's no guarantee the name won't change until then.
I don't think you can. Here is a code snippet from the compilation server:
object SocketServer
{
// After 30 idle minutes, politely exit.
// Should the port file disappear, and the clients
// therefore unable to contact this server instance,
// the process will just eventually terminate by itself.
val IdleTimeout = 1800000
val BufferSize = 10240
def bufferedReader(s: Socket) = new BufferedReader(new InputStreamReader(s.getInputStream()))
def bufferedOutput(s: Socket) = new BufferedOutputStream(s.getOutputStream, BufferSize)
}
I think you should open a feature request in scala-lang.org