Here’s a way to ensure that only one instance of your application runs at a time. Perhaps it updates a resource and you need to prevent duplicate updates. Or, in another use, I recently wanted to make sure an application was always running. So I wrote a cron job to periodically start the program; if it was already running, the new start failed.
A traditional method for ensure single instances of program uses file locking and PIDs. A program, upon start up, would get its process id (PID) from the OS, then write it to a file called “program.lock” in a known, fixed location. Then it would read the file and check the written PID against its own. If they match, great; continue. If they don’t match, it means that another file succeeded at creating the file, ie got the lock, so this application must shut down. You might think that if the file exists, then no check is necessary. However, the idea is to handle the situation when multiple instances start at nearly identical times. Neither sees the file and tries to create it, but only one succeeds because Unix file creation is atomic.
The traditional method is clever, but challenging to get right. Lock files must be removed on exit, requiring more code. If the program terminates unexpectedly, provisions must be made to catch the exit signal and clean up or use additional methods to reap leftover lockfiles.
Here’s a much simpler method. Like the traditional method, each application attempts to hold a shared resource. Only one succeeds, and the resource hold is automatically released on program termination. The resource? A OS network port. So the only risk is accidentally choosing a port needed by another application for actual communication.
All you have to do is choose a port to use as an “application exclusion group id”. Several applications use the id. But only one application among the group sharing the id can run at a time.
Here’s the code. Include the file in your program, then call SingletonApp.performSolo as shown in the demo. To demo, just run multiple copies of the file as shown in the comments. Only one will run at a time…
import java.net.BindException
import java.net.ServerSocket
/**
* This class enables applications to ensure that only one instance
* of the application runs at a time.
*
* @author Gary Boone, PhD
* @version 1.0, 2010/02/24
*/
object SingletonApp {
var serverSocket:ServerSocket = null
/**
* Pick a port number to use as the application exclusion
* group id. Choose a port that won't conflict with other
* applications. See
* http://en.wikipedia.org/wiki/List_of_TCP_and_UDP_port_numbers
* for common port numbers.
*
* Additionally, pass in a closure to be run if the application
* is already running.
*/
def performSolo( portToHold:Int)( fail: => Unit ) = {
try {
serverSocket = new ServerSocket(portToHold)
} catch {
case e:BindException => fail
}
}
/**
* Demo the SingletonApp class
*
* Compile, or run with:
* scala -i SingletonApp.scala -e 'SingletonApp.main(null)' &
* Then start another instance to see it fail.
*/
def main( args:Array[String] ) : Unit = {
val DEMO_PORT_TO_HOLD = 15486
// ensure single instance
SingletonApp.performSolo(DEMO_PORT_TO_HOLD) {
println("failing due to already-running instance.")
exit
}
println("Application started. Try to start another instance.")
Thread.sleep(300000) // 3e6 ms = 300 sec = 5 min
println("exiting")
}
}