0

I have a script that's executed every minute by cron in an Alpine container. Said script may run for long time, which is why it handles locking itself.

Just now I noticed the busybox' crond avoids executing the script for the first 10 minutes of a long-running instance, only after that the expected schedule is resumed. Verified this behavior by logging from the script; also crond: user abc: process already running: sync.sh is logged by cron (see below) during said period when script is expected to be triggered.

Why is this and where is the logic documented?


$ crond --help
BusyBox v1.36.1 (2023-07-27 17:12:24 UTC) multi-call binary.

Usage: crond [-fbS] [-l N] [-d N] [-L LOGFILE] [-c DIR]

    -f  Foreground
    -b  Background (default)
    -S  Log to syslog (default)
    -l N    Set log level. Most verbose 0, default 8
    -d N    Set log level, log to stderr
    -L FILE Log to FILE
    -c DIR  Cron dir. Default:/var/spool/cron/crontabs
$ cat /etc/crontabs/abc 
PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
MAILTO=""

# m h dom mon dow     command
# ============================================================================
*/1 * * * *  sync.sh

Cron is started in container with /usr/sbin/crond -f -l 8 -L /dev/stdout -c /etc/crontabs

#   from docker host:
$ docker logs  my-container
usermod: no changes
crond: crond (busybox 1.36.1) started, log level 8
crond: USER abc pid  27 cmd sync.sh
crond: user abc: process already running: sync.sh
crond: USER root pid 158 cmd run-parts /etc/periodic/15min
crond: user abc: process already running: sync.sh
crond: user abc: process already running: sync.sh
crond: user abc: process already running: sync.sh
crond: user abc: process already running: sync.sh
crond: user abc: process already running: sync.sh
crond: user abc: process already running: sync.sh
crond: user abc: process already running: sync.sh
crond: user abc: process already running: sync.sh

/ around here 10 minute mark is hit, and crond starts invoking sync.sh again /

crond: USER abc pid 193 cmd sync.sh
sendmail: can't connect to remote host (127.0.0.1): Connection refused
crond: USER abc pid 219 cmd sync.sh
sendmail: can't connect to remote host (127.0.0.1): Connection refused
crond: USER abc pid 245 cmd sync.sh
sendmail: can't connect to remote host (127.0.0.1): Connection refused

Stripped down reproduction of said script:

#!/usr/bin/env bash

#####################################
readonly SELF="${0##*/}"
DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)"
JOB_ID="test-$$"
LOG="/config/${SELF}.log"

STATE_FILE=/tmp/test.state
#####################################

_prepare_locking()  { eval "exec 9>\"/tmp/test.lock\""; }
exlock_now()             { flock -xn 9; }

_log() {
    local lvl msg
    readonly lvl="$1"
    readonly msg="$2"
    echo -e "[$(date '+%F %T')] [$JOB_ID]\t$lvl  $msg" | tee -a "$LOG" >&2
    return 0
}

info() {
    _log INFO "$*"
}


update_statefile() {
    local time time_d

    _write_state() {
        echo -n "$time" > "$STATE_FILE"
    }

    time="$(date +%s)"

    if [[ -s "$STATE_FILE" ]]; then
        time_d="$((time - $(cat -- "$STATE_FILE")))"

        if [[ "$time_d" -ge 600 ]]; then
            info "$SELF has been running for at least ${time_d}s..."
            exit 1
        fi
    else
        _write_state
    fi

    info 'unable to obtain lock, process is already running'
    exit 0  # exit, not return
}


#### ENTRY ####
_prepare_locking || exit 1
exlock_now || update_statefile
info "$SELF starting up..."
sleep 20m  # block

exit 0

Edit: So far can only conclude it's some busybox' cron oddity -- this comment in a related thread seems to confirm it.

Explicitly backgrounding the process in crontab using & makes this phenomenon disappear. Downside to this however is that killing the process group via kill -- -pid no longer works:

container-hostname:/# ps -ef | grep sync.sh
   34 abc       0:00 bash /usr/local/sbin/sync.sh
 1633 root      0:00 grep sync.sh
container-hostname:/# kill -9 -- -34
bash: kill: (-34) - No such process
2
  • 1
    This more likely is caused by your script, about which we know nothing.
    – harrymc
    Commented Aug 10, 2023 at 18:57
  • @harrymc fair enough. Added sample script.
    – laur
    Commented Aug 11, 2023 at 1:06

2 Answers 2

0

I discovered this after much hair-pulling. It appears to be intentional and specific to busybox cron based on a comment in the source.

I believe this may be where the logic is actually implemented. Looks like it has always been this way so doubt it will ever be changed.

0

I can confirm this behavior on OpenWrt 23.05.3.

To verify used this crontab:

 * * * * * sleep 48 ; echo 48 
 * * * * * sleep 49 ; echo 49 
 * * * * * sleep 51 ; echo 51 

Using logread -f you will must probably see that the latter commands probably will only be only every second minute...

1
  • This does not really answer the question. If you have a different question, you can ask it by clicking Ask Question. To get notified when this question gets new answers, you can follow this question. Once you have enough reputation, you can also add a bounty to draw more attention to this question. - From Review
    – zx485
    Commented Apr 5 at 22:16

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .