Date created: Friday, April 21, 2017 12:28:04 PM. Last modified: Sunday, January 27, 2019 11:46:00 AM

Rsync Backup Window

From 23.00 onwards (when the cronjob is scheduled to start) up until 07.30 the following morning, run rsync in a continuous loop. This is incase the connection is dropped overnight, then the backup jobs will fall behind. Whilst rsync is running the script checks the time, if it reaches 07.30 the script will kill rsync and exit (this is the end of the backup window). FINISH_DAYS is an offset from the start day, starting at 23.00 and one night and finishing at 07.30 the next day, the FINISH_DAYS offset is 1, use 0 for the same day, +2 to run all weekend etc.

#!/bin/bash 

set -u

# Both with leading zero
# 00-23:
FINISH_HOUR=07
# 00-59:
FINISH_MINUTE=00

# Additional days, no leading zero
FINISH_DAY=1

# Nothing to edit below here...


declare -a RSYNC_CMD
RSYNC_CMD[0]="/usr/bin/rsync -vrhit --partial --progress --stats --delete -e \"ssh -p 12345\" /media/drive1/dir1/ backup-user@1.2.3.4:~/backup/dir1/ &"
RSYNC_CMD[1]="/usr/bin/rsync -vrhit --partial --progress --stats --delete -e \"ssh -p 12345\" /media/drive2/dir2/ backup-user@1.2.3.4:~/backup/dir2/ &"
RSYNC_CMD[2]="/usr/bin/rsync -vrhit --partial --progress --stats --delete -e \"ssh -p 12345\" /media/drive3/dir3/ backup-user@1.2.3.4:~/backup/dir3/ &"

RSYNC_COUNT=2
INDEX=0
RSYNC_PID=0


function watch_rsync() {

    while true
    do

        # If the backup window has ended, kill rsync and exit
        NOW=$(date +"%s")
        if [[ $NOW -ge $2 ]]
        then
            echo "Killing PID $RSYNC_PID at: `date`"
            kill $RSYNC_PID
            exit 1
        fi

        sleep 60

    done

}


echo "Starting at: `date`"
END_DATE=$(date -d "+$FINISH_DAY day $FINISH_HOUR:$FINISH_MINUTE:00" +"%s")
echo "End date is: `date -d @$END_DATE`"

while true
do

    eval ${RSYNC_CMD[$INDEX]}
    RSYNC_PID=$!

    watch_rsync $RSYNC_PID $END_DATE &

    wait $RSYNC_PID
    RET=$?

    # If the current rsync command completed successfully,
    # move on to the next rsync task
    if [[ $RET -eq 0 ]]
    then

        let INDEX=INDEX+1

        if [[ $INDEX -gt $RSYNC_COUNT ]]
        then
            # All rsync jobs have finished so exit
            echo "Finishing at: `date`"
            exit 0
        fi

    # Exit code 20 means rsync received SIGUSR1 or SIGINT
    elif [[ $RET -eq 20 ]]
    then

        # Rsync was killed so stop the script
        echo "Stopping at: `date`"
        exit 1

    fi

    # Else if it wasn't exit code 0 or 20, rsync was probably
    # interrupted by a connection drop for example, so loop
    # back around and start the same rsync job again.

done