Sidekiq runitスクリプトがもろすぎる: **discourse:www-data** **+ forced** **-L log/sidekiq.log** **で1秒クラッシュが発生

チームの皆さん、

公式のDocker/runit設定で、再構築やアップグレードなしにSidekiq(ひいてはAI/バックグラウンドジョブ)がサイレントに停止する障害モードを報告します。

環境

  • 公式Discourse Dockerインストール(標準コンテナ + runitサービス)。
  • 問題発生直前の再構築/アップグレードなし。
  • Discourse AIプラグインが有効になっているが、AIが応答しなくなった。

症状

  • 管理UIでは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'

2つの脆弱な点:

  1. プライマリグループ www-data 私のコンテナでは、通常の書き込み可能なパスはdiscourse:discourseによって所有されています。tmp/pidsや共有パスのいずれかのドリフトにより、手動でdiscourseとして起動した場合は機能するにもかかわらず、www-dataの下で起動したSidekiqが起動時に終了する可能性があります。
  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 (グループ書き込み可能) です。
  • logrotateは、グローバルのsuディレクティブが設定されていない限り、ローテーションを拒否します。これはアップストリームの予期された動作です。

日々の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 sidekiqrunのままになります。
  • AI/バックグラウンドジョブが再開されます。

リクエスト/提案

公式のDocker/runit Sidekiqサービスをデフォルトでより堅牢にすることを検討していただけないでしょうか?

例えば:

  • Sidekiqをコンテナ内の通常の所有権と一致するdiscourse:discourseの下で実行する。
  • bundle exec sidekiq -C config/sidekiq.ymlを優先する。
  • -L log/sidekiq.logを介した共有ログファイルの強制を避けるか、logrotate/共有ボリュームのパーミッションのドリフトに対して耐性を持たせる。

ドキュメントに「Sidekiqがdown: 1sを示すが手動起動が機能する場合は、/etc/service/sidekiq/runを確認し、強制的な共有ロギングを避けてください」といった注記があるだけでも、セルフホスターにとって非常に役立ちます。

さらにログが必要な場合は喜んで提供します。ありがとうございます!