Script runit do Sidekiq muito frágil: **discourse:www-data** **+ forçado** **-L log/sidekiq.log** **causa falha de 1 segundo**

Olá equipe,

relatando um modo de falha na configuração oficial do Docker/runit que pode encerrar silenciosamente o Sidekiq (e, portanto, os trabalhos de IA/background) sem qualquer reconstrução ou atualização.

Ambiente

  • Instalação oficial do Discourse Docker (container padrão + serviços runit).
  • Nenhuma reconstrução/atualização imediatamente antes do início do problema.
  • Plugin Discourse AI ativado, mas a IA parou de responder.

Sintomas

  • A IA parece ativada na interface de administração, mas nenhuma resposta de IA aparece.
  • Os trabalhos em segundo plano (IA/embeddings/resposta automática) parecem travados.
  • sv status sidekiq mostra o Sidekiq morrendo repetidamente logo após a inicialização:
down: sidekiq: 1s, normally up, want up
  • Iniciar o Sidekiq manualmente funciona bem, então o aplicativo em si está OK:
bundle exec sidekiq -C config/sidekiq.yml
# permanece ativo, conecta-se ao Redis, processa trabalhos

O que descobrimos

O script runit padrão era:

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

Dois pontos de fragilidade:

  1. Grupo primário www-data No meu container, os caminhos graváveis típicos são de propriedade de discourse:discourse. Qualquer desvio em tmp/pids ou caminhos compartilhados pode fazer com que o Sidekiq saia durante a inicialização quando executado sob www-data, mesmo que a inicialização manual como discourse funcione.
  2. Escrita forçada -L log/sidekiq.log para logs compartilhados O caminho do log é um link simbólico para /shared/log/rails/sidekiq.log. Se esse arquivo/diretório for recriado com propriedade/permissões diferentes, o Sidekiq pode sair imediatamente antes de produzir logs úteis.

Gatilho relacionado: logrotate falhando diariamente

Separadamente, o logrotate estava falhando todos os dias com:

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

A causa eram as permissões padrão do Debian/Ubuntu:

  • /var/log é root:adm com 0775 (grupo gravável).
  • logrotate se recusa a rotacionar, a menos que uma diretiva su global seja definida. Este é o comportamento upstream esperado.

No momento em que o trabalho diário do logrotate falhou, ele também recriou arquivos em /shared/log/rails/ (incluindo sidekiq.log), o que provavelmente interagiu com o log forçado via -L e contribuiu para o loop de “crash de 1s” do Sidekiq.

Correção (nenhuma reconstrução necessária)

  1. Corrigir logrotate para que ele pare de tocar nos logs compartilhados em estado de falha Adicionar uma diretiva su global:
# /etc/logrotate.conf (topo)
su root adm

Depois disso, logrotate -v sai com código 0 e não relata mais permissões de diretório pai inseguras.

  1. Substituir o script runit do Sidekiq por um padrão mais robusto Mudar para discourse:discourse e o sidekiq.yml padrão, e não forçar -L log/sidekiq.log, torna o Sidekiq estável:
#!/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'

Depois disso:

  • sv status sidekiq permanece em execução:
  • Os trabalhos de IA/background são retomados.

Solicitação / sugestão

Poderíamos considerar tornar o serviço Sidekiq oficial do Docker/runit mais robusto por padrão?

Por exemplo:

  • Executar o Sidekiq sob discourse:discourse (correspondendo à propriedade típica dentro do container).
  • Preferir bundle exec sidekiq -C config/sidekiq.yml.
  • Evitar forçar um arquivo de log compartilhado via -L log/sidekiq.log, ou torná-lo resiliente à deriva de permissões do volume compartilhado/logrotate.

Mesmo uma nota na documentação (“se o Sidekiq mostrar down: 1s, mas a inicialização manual funcionar, verifique /etc/service/sidekiq/run e evite o log forçado compartilhado”) ajudaria muito os auto-hospedeiros.

Fico feliz em fornecer mais logs, se necessário. Obrigado!

1 curtida

Onde você está encontrando isso? O Sidekiq é iniciado via o mestre do unicorn para conservar memória. Não estou vendo este código em lugar nenhum no discourse_docker. Parece que você está usando uma configuração muito antiga?

2 curtidas

Olá — deixe-me reformular isso estritamente com base nos fatos de tempo de execução do contêiner Docker oficial.

O que estou vendo no contêiner em execução (fatos)

Esta é uma instalação Docker oficial com runit (fluxo de trabalho padrão do lançador /var/discourse; sem reconstrução imediatamente antes do incidente). Dentro do contêiner:

  1. Um serviço Sidekiq do runit existe e é o que está sendo supervisionado
ls -l /etc/service/sidekiq/run
sv status sidekiq

Saída durante o incidente:

down: sidekiq: 1s, normally up, want up
  1. A inicialização manual do Sidekiq funciona
cd /var/www/discourse
sudo -u discourse bundle exec sidekiq -C config/sidekiq.yml

Isso permanece ativo, conecta-se ao Redis e processa trabalhos.

  1. Apenas a aplicação de patch em /etc/service/sidekiq/run (sem reconstrução) corrige o loop de falha imediatamente Substituí /etc/service/sidekiq/run por:
#!/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'

Depois disso:

sv status sidekiq
run: sidekiq: (pid <PID>) <SEGUNDOS>s

Portanto, o Sidekiq não está sendo iniciado via mestre Unicorn nesta imagem; é um serviço runit cujo script de tempo de execução pode entrar em loop de falha.

Por que você pode não ver o código exato em

discourse_docker

Concordo que o texto literal pode não estar no repositório porque /etc/service/sidekiq/run é um artefato de tempo de execução gerado/injetado durante a construção/inicialização da imagem, não necessariamente um arquivo literal em discourse_docker. Mas é o serviço supervisionado ativo nesta imagem oficial, como mostrado acima.

O que desencadeou a fragilidade (fatos + inferência mínima)

  • Também observamos falhas diárias do logrotate devido a permissões padrão do Debian: /var/log = root:adm 0775, então o logrotate recusou a rotação até adicionar global su root adm.
  • Quando o logrotate falhava, ele recriava arquivos em /shared/log/rails/, incluindo sidekiq.log.
  • O script runit padrão nesta imagem usava discourse:www-data e forçava -L log/sidekiq.log para /shared/log, o que torna o Sidekiq muito sensível à deriva de permissões de volume compartilhado e pode causar uma saída imediata antes de logs úteis.

Solicitação / proposta

Dado o acima, poderíamos considerar reforçar o serviço Sidekiq padrão do Docker/runit?

Padrões sugeridos:

  • executar como discourse:discourse (corresponde à propriedade típica dentro do contêiner),
  • iniciar via bundle exec sidekiq -C config/sidekiq.yml,
  • evitar forçar um compartilhamento -L log/sidekiq.log (ou torná-lo resiliente).

Isso evitaria o loop de falha silencioso down: 1s que interrompe todos os trabalhos em segundo plano/IA.

Ficarei feliz em testar qualquer branch/commit que você me aponte.

Novamente… estou confuso sobre de onde você está obtendo sua imagem:

image

Esta é a imagem oficial.

Esta é uma busca pela palavra sidekiq no discourse docker oficial.

Existem 3 resultados… nada sobre uma unidade runit. É gerenciado via unicorn.

1 curtida

Olá — obrigado, essa captura de tela ajuda a esclarecer o layout.

Concordo que na imagem oficial atual o Sidekiq não é um serviço runit separado (sem /etc/service/sidekiq/). Ele é iniciado a partir da cadeia de inicialização do serviço runit do unicorn, o que corresponde à sua listagem em /etc/service/.

Meu relatório ainda é sobre um modo de falha em tempo de execução desse caminho de inicialização do Sidekiq, independentemente de ele residir em uma unidade runit autônoma ou dentro de unicorn/run:

Fatos em tempo de execução no meu VPS (Docker oficial, sem reconstrução/atualização imediatamente antes do incidente):

  1. Os trabalhos em segundo plano pararam e as respostas da IA pararam.

  2. O Sidekiq entrou em um loop de falha imediato (abaixo: 1s) quando iniciado pelo supervisor/cadeia de inicialização do contêiner.

  3. A inicialização manual como discourse via bundle exec sidekiq -C config/sidekiq.yml permaneceu ativa e processou trabalhos, então o app/redis estavam bem.

  4. Ao mesmo tempo, falhas no logrotate fizeram com que /shared/log/rails/sidekiq.log (e caminhos relacionados) fossem recriados com permissões diferentes; após estabilizar o comando de inicialização do Sidekiq (executar como discourse:discourse, usar sidekiq.yml, evitar forçar o compartilhamento -L sidekiq.log), o loop de falha parou imediatamente.

Portanto, o arquivo literal /etc/service/sidekiq/run pode não existir nesta imagem — concordo — mas a etapa de inicialização do Sidekiq incorporada ao serviço runit do unicorn é frágil a desvios de permissões/logrotate de volume compartilhado e pode desativar silenciosamente o Sidekiq sem uma reconstrução. Essa é a questão central.

Sugestão: considere reforçar a inicialização do Sidekiq no script runit oficial do unicorn (ou onde ele é gerado):

  • Executar o Sidekiq sob discourse:discourse,

  • Preferir bundle exec sidekiq -C config/sidekiq.yml,

  • Evitar forçar um -L log/sidekiq.log compartilhado (ou torná-lo resiliente).