文章

别再每分钟扫目录了:让 VPS 盯着文件变化自己干活

静水流深 5小时前 · 1,631 字 · 约 5 分钟 · 19 次阅读
我发布了文章:《别再每分钟扫目录了:让 VPS 盯着文件变化自己干活》

每分钟跑一次的脚本,毛病在哪

"看看目录里有没有新文件"这种需求,很多人第一反应是写个 cron 每分钟跑一遍。它确实能用,代价是一堆你迟早会遇到的麻烦:上一轮还没跑完下一轮就起来了,你得自己加锁;文件落到一半就被扫到,处理出来是半个文件;绝大多数分钟里它什么也没干,白占一次调度。

Linux 早就有更合适的东西:inotify。内核 2.6.13 起并入,应用注册好监视点后就阻塞等事件,文件一有动静内核主动通知,不用轮询。

三条路,选哪条

  • 直接调 C API,除非你在写系统级程序。
  • 命令行工具 inotifywait / inotifywatch(Debian 的 inotify-tools 包),适合临时调试;inotifywait 的 daemon 模式只能把事件记进日志,干不了活。
  • Python 库,写常驻脚本最省事。

装什么

Debian 13(trixie)可以直接 apt -y install python3-inotify,仓库里是 0.2.10-5,上游就是这个库;习惯用 pip 的就 pip install inotify,两边模块名都是 inotify。要提醒一句:早年有个同名的 PyInotify 项目已经停维护,跟现在这个库没有关系,装混了 import 会对不上。守护进程化再补一个 apt -y install python3-daemonize

先跑通一个能看见事件的脚本

#!/usr/bin/python3
import inotify.adapters

i = inotify.adapters.InotifyTree('/tmp/test')
for event in i.event_gen(yield_nones=False):
    (_, type_names, path, filename) = event
    print("PATH=[{}] FILENAME=[{}] EVENT_TYPES={}".format(path, filename, type_names))

chmod 755 后跑起来,另开一个终端在 /tmp/test 里 touch、写、chmod、删,你会看到一串 IN_CREATE、IN_OPEN、IN_MODIFY、IN_CLOSE_WRITE、IN_DELETE。这一步很重要——先看清一个动作会触发几个事件,再决定你的脚本该认哪个。

变成开机就跑的常驻服务

把要监视的目录、要调用的脚本、要认的事件三行配置抽出来,用 daemonize 包把它做成守护进程,再配一个 systemd unit:ExecStart 指向脚本,systemctl daemon-reload && systemctl enable --now watchfs。触发脚本拿到的参数是文件名,剩下爱干什么干什么——压缩、转码、同步、发通知,都在这一个 shell 脚本里。

认哪个事件,别选错

  • 上传或写入场景用 IN_CLOSE_WRITE(可写文件被关闭时触发);IN_CREATE 触发的那一刻文件可能才刚建好、内容还没写完。
  • rsync、sftp 这类先写临时文件再改名的,认 IN_MOVED_TO
  • 想一次认多个,就在循环里遍历 type_names,别只判断第一个。

三个一定会踩的坑

  1. 目录监视不递归。 内核只给你一层,像 InotifyTree 这种递归监视是库在用户态给子目录补 watch,新建目录和目录里立刻出现的文件之间存在竞态,理论上会漏事件;watch 总数还受 /proc/sys/fs/inotify/max_user_watches 限制。目录树很大时,不如只盯一两个入口目录。
  2. 事件队列会溢出。 事件爆发时内核直接丢,只给你一个 IN_Q_OVERFLOW。所以触发脚本要写成幂等的,跑一遍和跑三遍结果一样,重要场景另外加一次定时全量对账,别假设每个文件都会恰好被触发一次。
  3. 网络文件系统不触发。 NFS 之类的远端改动 inotify 收不到,这种场景只能退回轮询。

用在哪最有手感

  • 用户上传目录:图片落地自动压缩转码,再挪进 web 目录。
  • 静态站:内容目录一变就自动重建并同步到线上。
  • 备份链:备份脚本写完一个 flag 文件,下一步(校验、上传异地、发通知)自动接上。
  • 配置热加载:改完配置自动 reload,不用记着敲命令。

这套东西的价值不在省那几次 cron,而在于把"文件到了"变成一个可靠的触发信号。补一句:本站没在自己机器上跑过这套代码,命令与行为依据的是内核手册和上游库的说明。

登录 后参与评论

还没有人评论,来抢沙发