转载

使用 flock 确保只有一个命令实例在运行

公司的机房设置了一个5分钟执行一次的数据同步脚本。一般每次同步只需要花费不到20秒即可完成,但网络出现问题时,就可能五分钟无法完成同步。脚本第二次启动可能干扰仍在运行的第一次脚本,需要有一个办法确保只有一个实例在运行。

Ubuntu系统提供了一个软件包叫 run-one ,可能实现这一功能,让我们来试试。首先安装软件包,以root权限运行:

# apt-get install run-one 

安装好之后,运行 run-one <要单实例运行的命令> ,就可以确保只有一个实例运行了。比如:

# run-one tail -f /var/log/syslog 

我们可以看到syslog的最后几行,并随着日志输出而滚动。此时如果打开另一个terminal,再次输入上述命令,会直接退出,并且exit code是1:

# run-one tail -f /var/log/syslog # echo $? 1 

除了 run-one 命令, run-one 软件包中还提供了几个实用的命令:

  • run-one 只运行一个进程实例,如果实例已存在,直接退出
  • run-this-one 只运行一个进程实例,如果实例已存在,kill掉它并重新运行
  • run-one-constantlyrun-one 一样,只运行一个进程实例,当进程退出时自动重新启动
  • keep-one-running run-one-constantly 的别名
  • run-one-until-successrun-one-constantly 相似,但只有当进程退出码不为0时才重新启动进程
  • run-one-until-failurerun-one-constantly 相似,但只有当进程退出码为0时才重新启动进程

在CentOS系统中,并没有 run-one 软件包可供使用。不过我们可以利用 flock 锁定的机制自己实现只有一个进程运行。

可以写一个脚本:

#!/bin/bash  TODAY=`date +%Y%m%d` (   flock -xn 100 || exit 1   scp root@myhost:/data/backups/$TODAY.log.gz /data/backups/myhost/   gzip -d /data/backups/myhost/$TODAY.log.gz | xz -9 -e > /data/backups/myhost/$TODAY.log.xz && /   rm /data/backups/myhost/$TODAY.log.gz ) 100>/tmp/backup_data.lock 

上面的脚本中, flock 命令会对 /tmp/sync_data.lock 文件加上写入锁(排它锁),分别在两个terminal中运行这个命令,会看到一个开始scp拷贝数据,另一个直接退出,退出状态码为1。

flock 命令有三种写法:

  1. flock [-sxun][-w #] fd#
  2. flock [-sxon][-w #] file [-c] command...
  3. flock [-sxon][-w #] directory [-c] command...

我们前面用的是第一种,定义一个文件描述符,这种方法适合用于多行命令需要排它运行的场景。后两种flock的用法适合只有一条命令要运行的场景。 flock-s 选项表示要获取读取锁(共享锁); -x 选项表示要获取写入锁(排它锁); -o 选项表示在运行命令前关闭已取得锁定的文件,如果后面的命令可能产生不该取得锁定的子进程,这个选项会很有用; -n 选项表示不要阻塞,如果无法取得锁,不要等待其它进程释放锁定,直接退出; -w 10 表示等待10秒,如果10秒仍无法取得锁,就退出。

run-one 是一个Bash脚本,通过查看 run-one 命令的源码得知,它也是利用 flock 实现的唯一化处理。如果不想自己编写带 flock 的程序,又想使用 run-one 提供的完整功能,可以去 Github 上下载 run-one 项目的代码。

原文  https://xts.so/linux/run-singleton-with-flock.html
正文到此结束
Loading...