【Linux】写个脚本实现简单的程序单例运行功能

需求

写了个爬虫脚本放到服务器上定时运行,当脚本碰到耗时的任务阻塞太久的时候可能下一次定时调用会发生,这会导致同时运行的脚本数量大于一个,可能会造成数据库数据重复等问题。现在想解决这个问题,但是并不想更改爬虫脚本相关的代码。

分析需求不难看出同时运行的爬虫脚本不能大于一个,由于脚本是通过定时任务启动(这里假设是 cron),我们可以在启动爬虫的指令上动手脚,在启动爬虫之前先判断是否有爬虫脚本运行,如果有则不启动爬虫。

实现方法1:ps(失败)

最直观的方法是通过 ps 查找指定名称的进程,然后判断进程是否存在,如果存在则不启动脚本:

TASK=`ps aux | grep sh /root/run_crawler.sh | grep -v grep`
if [ "$TASK" = "" ]; then
  # 执行一些耗时的任务
  python run.py 
fi

如示例代码所示,这个脚本的主要问题在 grep 查找进序上,因为通过 cron 启动这个脚本的时候也会启动同名的进程,所以在查找之前该进程就已经被创建,而根据脚本“进程不存在才执行”的逻辑,这段脚本永远不会执行 if 段里面的内容。

实现方法2:判断指定文件是否存在

我们可以在运行脚本之前判断一个指定的文件是否存在,如果存在表示脚本正在运行,否则运行脚本并创建该文件,脚本运行结束后删除该文件,伪代码如下:

filename = 'LOCK'

if filename 不存在:
  创建文件(filename)
  # 执行耗时操作
  python run.py
  删除文件(filename)

示例 bash 代码如下:

LOCK="LOCK.temp"
if [ ! -f "$LOCK" ]; then
  touch $LOCK
  python run_crawlers.py
  sleep 2
  python push_message.py
  rm -rf $LOCK

这种写法有两个主要的问题:

  1. 文件名可能会和本地文件冲突 - 可以通过生成时间戳文件名等方法解决
  2. 可能产生 if 内脚本永远无法运行的 bug
    第二个问题产生的原因是当我们执行 if 段的代码时,创建了 lock 文件,但是执行过程中脚本的运行被打断,导致 lock 文件无法被自动删除,除非手动删除否则该脚本永远不会执行。

第二个问题的解决方法
增加一个超时机制,即如果 lock 存在的时间超过指定时间,删除 lock,这里用到了 stat 指令用来获取文件创建的时间戳,date +%s 获取当前时间戳,完整代码如下:

LOCK="LOCK.temp"
if [ ! -f "$LOCK" ]; then
  touch $LOCK
  # 执行一些耗时操作
  python main.py
  rm -rf $LOCK
else
  ts=`stat -c %Y $LOCK`
  now=`date +%s`
  # 超时时间为 1800s (30min)
  if [ $[ $now - $ts ] -gt 1800 ]; then
    rm -rf $LOCK
    echo "Lock expired, deleted"
  fi
fi

总结

以上提供了一种单例运行的思路,实际上还有很多其他的方法能够避免数据重复写的问题,可以根据自己的实际情况选择。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值