What I've learned from setting up runit to run a sbt app

1 Jan 2017

I've been experimented with runit. It's a great way to supervise a long-lived application. I don't want to use nohup anymore.

There are many good tutorials. I've found that a tutorial from Mike Perham and the one on Rubyists are sufficient.

One thing I've learned from experimenting with runit is that process supervision is a solved problem. It doesn't make sense to solve it myself. I have been always inclined to create my own solution. That's not a good attitude. Because my solution is almost always inferior to a famous solution (where it has been tested for years). And my goal is not to solve process supervision; it's to build an application that solve user's problems. I need to remember that and learn to explore other people's solutions.

Here are what I've learned:

  • A folder is symlink to /etc/service to install the service. Yes, the folder contains the service's configuration.
  • If the ./log/run is added after a service is installed, we need to unsymlink and resymlink the folder again.
  • We need to use exec to run the process we want because exec run the process using the same PID. runit executes run and saves the PID. Therefore, if we didn't use exec, our process would have a different PID.
  • We can't use scala in run because scala spawns a different process with different PID to run the java app.
  • sbt stage from sbt-native-packager and run target/universal/stage/bin/[app] works fine.
  • I can't figure out how to allow other users to start/stop a service. Runit's FAQ says that we can simply allow the user to manage the files under ./supervise. I configure an runit service through Ansible. Those files don't exist before a service is started. And if I touch those files first (with Ansible), then those files will be invalid, and the service won't start.