我正在考虑使用rsync
将我的笔记本电脑通过 备份到我的家庭服务器ssh
。我想每天都这样做,所以我计划使用crontab
。我的问题是:如果错过一项工作(比如说备份安排在笔记本电脑关闭时进行),它会尽快执行吗?还是会直接错过?
答案1
由于您明确要求:
即使计算机处于睡眠或关闭状态,队列也会失败或错过备份作业
运行备份作业时在服务器上,重试(排队)失败的作业相对容易,因为我们可以假设服务器将是“稳定”因素。通过将 cronjob 路由到脚本,可以在备份失败时创建队列,从而将错过的备份排队。
当作业运行时在客户端上然而,情况略有不同。当我们从 运行作业时cron
,我们如何注意到作业失败了?由于如果客户端计算机处于睡眠或关闭状态,则作业不会启动,因此从 cron 设置会变得复杂得多。
因此,如果你想运行计划备份,确保失败或错过的作业将在第一时间运行,我建议不要使用 cron根本。
在单个文件中设置计划/队列备份
下面的解决方案设置起来相对简单,按照以下步骤进行:
- 编写并测试
rsync
备份命令。grsync
如果您不确定如何执行此操作,请使用。 将下面的脚本复制到一个空文件中,并为其指定备份作业的名称(例如),如:
backup1.py
在脚本的头部进行适当的设置:
#--- 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
有多个备份作业?
该脚本大部分时间处于休眠状态。如果没有休眠,它每分钟只会查看一次队列文件。这意味着没有什么在您的系统中,完全可以同时运行多个备份作业,每个作业都有自己的日志和队列文件。由于日志和队列文件都以脚本的名称命名,因此您所要做的就是为每个脚本指定一个唯一的名称