Sidekiq runit 脚本过于脆弱:**discourse:www-data** **+ forced** **-L log/sidekiq.log** **导致 1 秒崩溃

大家好,

报告一下官方 Docker/runit 设置中存在的一种故障模式,它可以在不进行任何重建或升级的情况下静默终止 Sidekiq(进而终止 AI/后台作业)。

环境

  • 官方 Discourse Docker 安装(标准容器 + runit 服务)。
  • 问题开始前没有进行重建/升级。
  • Discourse AI 插件已启用,但 AI 停止回复。

症状

  • 管理界面中 AI 显示为启用,但没有 AI 回复出现。
  • 后台作业(AI/嵌入/自动回复)似乎卡住了。
  • sv status sidekiq 显示 Sidekiq 在启动后反复崩溃:
down: sidekiq: 1s, normally up, want up
  • 手动启动 Sidekiq 运行正常,说明应用程序本身没问题:
bundle exec sidekiq -C config/sidekiq.yml
# 保持运行,连接到 Redis,处理作业

我们发现的情况

默认的 runit 脚本是:

exec chpst -u discourse:www-data \
  bash -lc 'cd /var/www/discourse && ... bundle exec sidekiq -e production -L log/sidekiq.log'

两个脆弱点:

  1. 主用户组 www-data 在我的容器中,典型的可写路径归 discourse:discourse 所有。当 Sidekiq 在 www-data 权限下启动时,tmp/pids 或共享路径的任何权限漂移都可能导致 Sidekiq 在启动时退出,即使以 discourse 用户手动启动是正常的。
  2. 强制的 -L log/sidekiq.log 写入共享日志 该日志路径是指向 /shared/log/rails/sidekiq.log 的符号链接。如果该文件/目录以不同的所有权/权限重新创建,Sidekiq 可能会立即退出,而无法产生有用的日志。

相关触发因素:logrotate 每日失败

另外,logrotate 每天都会失败并报告:

error: skipping "...\log" because parent directory has insecure permissions
Set "su" directive in config file ...

原因是标准的 Debian/Ubuntu 权限设置:

  • /var/log 是 root:adm,权限为 0775(组可写)。
  • 除非设置全局 su 指令,否则 logrotate 会拒绝轮换。这是预期的上游行为。

在每日 logrotate 作业失败的时刻,它也重新创建了 /shared/log/rails/ 下的文件(包括 sidekiq.log),这很可能与强制的 -L 日志记录相互作用,并导致了 Sidekiq 的“1秒崩溃”循环。

修复方法(无需重建)

  1. 修复 logrotate,使其停止在失败状态下触碰共享日志 添加一个全局 su 指令:
# /etc/logrotate.conf (顶部)
su root adm

之后,logrotate -v 退出代码为 0,并且不再报告父目录权限不安全。

  1. 用更健壮的默认值替换 Sidekiq runit 脚本 切换到 discourse:discourse 和标准的 sidekiq.yml,并且不强制 -L log/sidekiq.log,使 Sidekiq 稳定:
#!/bin/bash
exec 2>&1
cd /var/www/discourse

mkdir -p tmp/pids
chown discourse:discourse tmp/pids || true

exec chpst -u discourse:discourse \
  bash -lc 'cd /var/www/discourse && rm -f tmp/pids/sidekiq*.pid; exec bundle exec sidekiq -C config/sidekiq.yml'

执行此操作后:

  • sv status sidekiq 保持运行状态:
  • AI/后台作业恢复。

请求/建议

我们能否考虑默认情况下使官方 Docker/runit Sidekiq 服务更加健壮?

例如:

  • 在 discourse:discourse 用户下运行 Sidekiq(与容器内典型所有权匹配)。
  • 优先使用 bundle exec sidekiq -C config/sidekiq.yml
  • 避免通过 -L log/sidekiq.log 强制指定共享日志文件,或者使其能够抵御 logrotate/共享卷权限漂移。

即使是添加一个文档说明(“如果 Sidekiq 显示 down: 1s 但手动启动正常,请检查 /etc/service/sidekiq/run 并避免强制共享日志记录”)也会对自托管用户有很大帮助。

如果需要更多日志,我很乐意提供。谢谢!