blob: ab664bbb6e235ba6d222ecc7397f59d0c194c42c [file] [log] [blame]
# Copyright (c) 2014 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
# A program wrapper that disallows multiple instances of the given program.
# It can optionally send email alerts about unintended instance conflicts.
# Sample Usage:
# No alerts, just prevent multiple instances:
# ./ sleep 10
# Default alerts - stderr output, 10 minute instance timeout:
# ALERT_ON_LOCKED=1 ./ sleep 10
# Email alerts on every instance conflict (no timeout):
# ALERT_THROTTLE=0 ./ sleep 10
# Trigger an alert when there is an existing program instance.
# If set to 0, alerts will be disabled. Disabling is useful for watchdog
# cronjobs, which expect the program to be running and just want to restart it
# if it dies.
# Number of seconds to allow a program to be locked before printing an alert.
# This can be used to prevent frequently run cronjobs from sending alert emails
# on every run, in case it's OK for previous instances to "spill over".
# Use internal email mechanism to send alerts to the given list of recipients.
# If not set, alerts are printed on stderr. Setting this allows nicer formatting
# of alert messages when run from cronjobs, instead of defaulting to cron's
# boilerplate emails.
# A unique identifier for the program being run.
# The default is to use the first argument of the wrapped command, but if that's
# not reasonably unique (e.g. 'python' would use 'python'), then a
# PROGRAM_NAME should be specified such that it's less likely to conflict with
# the lock files of other wrapped programs (e.g. '' would be better).
if [ -z "$1" ]; then
echo "ERROR: Please specify a program to wrap."
exit 1
flock -n -x 200
if [ $? != 0 ]; then
if [ "$ALERT_ON_LOCKED" != "0" ]; then
SENDMAIL=$(which sendmail)
NOWTIME=$(date +"%s")
LOCKTIME=$(stat -c %Y "$LOCKFILE")
if [ "$DIFFTIME" -gt "$ALERT_THROTTLE" ]; then
PID=$(cat "$LOCKFILE")
MSG="WARNING: Cannot execute '$@'\n"
MSG+="Previous instance [$PID] has been "
MSG+="running for $DIFFTIME seconds."
if [ -n "$ALERT_EMAIL_RCPTS" ] && [ -n "$SENDMAIL" ]; then
SENDER=$LOGNAME@$(hostname -f)
cat <<!
Subject: Locked Process on $HOSTNAME: $@ [pid $PID]
$(echo -e "$MSG")
echo -e "$MSG" >&2
exit 2 # previous instance, alert triggered
exit 1 # previous instance, not timed out, no alert
exit 0 # previous instance, no alert (not an error)
fi # no previous isntance
# Run the wrapped program.
"$@" &
# Store the program PID in the lock file for alert message.
echo -n $! > "$LOCKFILE"
# Wait for the program to exit.
# Truncate the lock file to clear the PID for the next run.
# Use >> to prevent changes to the lock file modification time on unsuccessful
# runs, which would otherwise throw off the DIFFTIME calculations.
) 200>>"$LOCKFILE"