即使计算机处于睡眠或关闭状态,我如何才能将失败或错过的备份作业排队?

即使计算机处于睡眠或关闭状态,我如何才能将失败或错过的备份作业排队?

我正在考虑使用rsync将我的笔记本电脑通过 备份到我的家庭服务器ssh。我想每天都这样做,所以我计划使用crontab。我的问题是:如果错过一项工作(比如说备份安排在笔记本电脑关闭时进行),它会尽快执行吗?还是会直接错过?

答案1

由于您明确要求:

即使计算机处于睡眠或关闭状态,队列也会失败或错过备份作业

运行备份作业时在服务器上,重试(排队)失败的作业相对容易,因为我们可以假设服务器将是“稳定”因素。通过将 cronjob 路由到脚本,可以在备份失败时创建队列,从而将错过的备份排队。

当作业运行时在客户端上然而,情况略有不同。当我们从 运行作业时cron,我们如何注意到作业失败了?由于如果客户端计算机处于睡眠或关闭状态,则作业不会启动,因此从 cron 设置会变得复杂得多。

因此,如果你想运行计划备份,确保失败或错过的作业将在第一时间运行,我建议不要使用 cron根本

在单个文件中设置计划/队列备份

下面的解决方案设置起来相对简单,按照以下步骤进行:

  1. 编写并测试rsync备份命令。grsync如果您不确定如何执行此操作,请使用。
  2. 将下面的脚本复制到一个空文件中,并为其指定备份作业的名称(例如),如:

    backup1.py
    
  3. 在脚本的头部进行适当的设置:

    #--- enter the working rsync command below
    rsync = "rsync -r -t --progress -s '/home/jacob/Bureaublad/test2' '/home/jacob/Bureaublad/test1'"
    #--- set backup time interval below in hours/minutes
    interval = [0, 10]
    #--- set message True if you'd like a warning if a job failed (else False)
    message = True
    

    输入rsync命令双引号之间,如示例中所示。

    • 使用以下方式保存脚本unique_name.py

就是这样。从脚本的开始时间开始,备份将在每个间隔后准确运行。如果作业失败,它将被排队(每分钟重试一次),直到可以成功运行。之后,新的备份将在准确的计划(下一个)时间设置。

  • 随后,使用以下命令测试运行脚本:

    python3 /path/to/script.py
    

    如果一切正常,请将其添加到启动应用程序:Dash > 启动应用程序 > 添加。添加命令:

    python3 /path/to/script.py
    

剧本

#!/usr/bin/env python3
import subprocess
import time
import os
import datetime

#--- enter the working rsync command below
rsync = "rsync -r -t -s '/home/jacob/Bureaublad/test2' '/home/jacob/Bureaublad/test1'"
#--- set backup time interval below in hours/minutes
interval = [24, 0]
#--- set message True if you'd like a warning if a job failed (else False)
message = True
#--- set the max- size of the logfile below (n- lines)
maxlog = 100

#--- don't change anything below
backup_id = os.path.basename(__file__).split(".")[0]
home = os.environ["HOME"]
datefile = home+"/next_backup_"+backup_id; logfile = home+"/backup_log_"+backup_id
print(datefile, logfile)
interval = (interval[0]*3600)+(interval[1]*60)
failed = False

def failed_message():
    # shows a zenity message if a backup failed
    subprocess.Popen([
        "zenity",
        "--info",
        "--text="+backup_id+" failed\n"+\
        "See "+logfile]) 

def readable_t(sec):
    # converts epoch time to readable date & time
    return datetime.datetime.fromtimestamp(sec).strftime('%Y-%m-%d %H:%M:%S')

def currtime():
    # returns current (epoch) time
    return int(time.strftime("%s"))

def sync(failed):
    # performs the rsync command, on errors: writes to log and shows message
    try:
        subprocess.check_call(["/bin/bash", "-c", rsync])
        set_next(planned, interval, currt)
        return False
    except subprocess.CalledProcessError:
        if failed == False:
            open(logfile, "+a").write(readable_t(planned)+" failed\n")
            if message == True:
                failed_message()
        return True

def next_run():
    # reads current queue file, creates it if it doesn't exist
    try:
        return int(open(datefile).read())
    except FileNotFoundError:
        currt = currtime()
        open(datefile, "wt").write(str(currt))
        return currt

def set_next(lastr, interval, currt):
    # creates the next queue, maintains the log file
    nextrun = lastr
    while nextrun <= currt:
        nextrun += interval
    open(datefile, "wt").write(str(nextrun))
    newline = [readable_t(lastr)+" succesfully finished on "+\
                        readable_t(currtime())+"\n"]
    try:
        limited_lines = open(logfile).readlines()[-maxlog+1:]+newline
    except FileNotFoundError:
        limited_lines = newline
    with open(logfile, "wt") as log:
        for l in limited_lines:
            print("4")
            log.write(l)

while True:
    time.sleep(60)
    planned = next_run(); currt = currtime()
    if currt > planned:
        failed = sync(failed)

此外

  • 该脚本保存一个以备份脚本命名的日志文件。
    日志文件中保存的最大行数可以在脚本的开头设置:

    #--- set the max- size of the logfile below (n- lines)
    maxlog = 50
    

    一个例子

    在此处输入图片描述

    在下面的示例中,脚本设置为从上午 11:10 开始每五分钟备份一次

    • 前两次(11:10、11:15)运行成功
    • 第三次(计划于 11:20 执行)失败,因为笔记本电脑处于睡眠状态。该作业已排队并略微延迟执行。该作业于 11:27 完成,下一次计划的备份将于 10:30 运行
    • 然后,由于服务器不可用,计划于 11:35 执行的作业失败。如果您设置message = True

      在此处输入图片描述

    • 该作业已排队并于稍后 11:41:44 成功运行

    等等

如何重置备份的开始时间?

只需删除相应备份作业的主目录中的队列文件(以 开头next_backup_),当前时间将成为周期的新开始时间。

其内部工作原理

  • 当脚本启动时,会创建第一个备份(从脚本启动后一分钟内开始)。
  • 当作业完成时,脚本会创建一个队列文件,定时于作业的(开始)时间完成的工作+ 集合备份间隔
  • 该脚本每分钟检查一次队列文件是否“超时”,并将当前时间与队列时间进行比较。如果是,则脚本运行备份作业,创建新队列等等。

    如果笔记本电脑(客户端)关闭,会发生什么情况?
    然后,最新创建的队列文件不会被脚本刷新(覆盖),因此它将在计算机启动(或唤醒)后第一次运行延迟备份。

    此后下一个备份队列是如何创建的?
    下一次备份总是按备份间隔的整步计算,并且始终“同相”。换句话说,如果第一次备份是在下午 12:00 进行的,并且您将间隔设置为,则下一次备份将始终在第二天[24, 0]排队。12:00

有多个备份作业?

该脚本大部分时间处于休眠状态。如果没有休眠,它每分钟只会查看一次队列文件。这意味着没有什么在您的系统中,完全可以同时运行多个备份作业,每个作业都有自己的日志和队列文件。由于日志和队列文件都以脚本的名称命名,因此您所要做的就是为每个脚本指定一个唯一的名称

相关内容