Use solo to Prevent Multiple Instances of an Application Running at the Same Time

solo is a very simple script (10 lines) originally written by Tim Kay, that prevents a program from running more than one copy at a time. It is useful with cron to make sure that a job doesn't run before a previous one has finished.

We've found it incredibly useful, but had some problems running it in our environment due to it not being Linux or BSD. Our fork with additional guidance is available here.

Usage:

solo -port=PORT COMMAND

where

PORT      some arbitrary IP port number to be used for the locking (1...65535)
COMMAND   shell command to run

options

-verbose  be verbose
-silent   be silent

Use it like this:

* * * * *  solo -port=3801 ./job blah blah

The script "job" will run every minute, but only if the previous one has finished. (Of course, you can use different cron parameters to run it other than every minute.)

Port 3801 in the example is an arbitrary TCP port number that isn't used elsewhere. solo works by binding to 127.x.y.1:port (see below). If the chosen port is not free, then a previous instance must still be running, and the job is aborted. Make sure to use a different port number for each job, or they will prevent each other from running. If you aren't running as root, the port number should be above 1023. The maximum allowed port number is 65535.

The loopback IP address 127.x.y.1 is used, where xy is the uid. This way, different users will never use the same ports even if they use the same port numbers.

(NOTE: OpenBSD doesn't allow 127.x.y.1 IP addresses. See the comment in the code, which changes the IP address to 127.0.0.1. It will work, but it will interlock between users. ThanksĀ www.gotati.com.)
(NOTE: Illumos and it's zone types also require the OpenBSD configuration for non-root users. Care must be taken to make sure ports don't overlap within the GZ, but each zone gets it's own network stack. SmartOS LX zones function with the OpenBSD change for non-root users too - ports inside a zone will overlap accross users, but not accross zones.)

The -silent switch tells solo to silently terminate when a previous instance is already running. Without -silent, a message is printed to stderr, indicating that a previous instance is already running.

Running a job this way (using crontab and solo) is much more maintainable than other methods:

  1. you don't need root privileges
  2. you avoid the complexity of /etc/rc.d files
  3. you don't have problems if the job crashes (cron restarts it)
  4. you can run multiple versions, one per directory, so, for example, you can have separate dev, stage, and live directories

A nice trick is to create a cron job:

  * * * * * solo -port=3802 find . -iname makefile -exec fgrep --silent repeatedly: {} \; -execdir make --silent repeatedly \;

This cron job will find each Makefile and execute its "repeatedly" target. Thus you can cause a job to run periodically by simply adding a target to a Makefile. The "-exec fgrep ..." step makes sure that the Makefile contains the target before "-execdir make ..." runs it, so error messages are avoided.

If you like, you can create multiple jobs that run targets named "repeatedly", "hourly", "daily", etc., to run jobs at different intervals.

Deploy Your Own Mail Server with mailcow and Docker