Script runit di Sidekiq troppo fragile: **discourse:www-data** **+ forced** **-L log/sidekiq.log** **causa crash di 1 secondo**

Ciao team,

segnalo una modalità di fallimento nella configurazione ufficiale Docker/runit che può terminare silenziosamente Sidekiq (e quindi i job AI/in background) senza alcuna ricostruzione o aggiornamento.

Ambiente

  • Installazione ufficiale di Discourse Docker (container standard + servizi runit).
  • Nessuna ricostruzione/aggiornamento immediatamente prima dell’inizio del problema.
  • Plugin Discourse AI abilitato, ma l’AI ha smesso di rispondere.

Sintomi

  • L’AI risulta abilitata nell’interfaccia di amministrazione, ma non compaiono risposte dall’AI.
  • I job in background (AI/embedding/risposta automatica) sembrano bloccati.
  • sv status sidekiq mostra che Sidekiq muore ripetutamente subito dopo l’avvio:
down: sidekiq: 1s, normally up, want up
  • L’avvio manuale di Sidekiq funziona correttamente, quindi l’applicazione è a posto:
bundle exec sidekiq -C config/sidekiq.yml
# rimane attivo, si connette a Redis, elabora i job

Cosa abbiamo scoperto

Lo script runit predefinito era:

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

Due punti di fragilità:

  1. Gruppo primario www-data Nel mio container, i percorsi tipicamente scrivibili sono di proprietà di discourse:discourse. Qualsiasi deriva in tmp/pids o nei percorsi condivisi può far uscire Sidekiq durante l’avvio quando eseguito sotto www-data, anche se l’avvio manuale come discourse funziona.
  2. Scrittura forzata -L log/sidekiq.log nei log condivisi Il percorso del log è un collegamento simbolico a /shared/log/rails/sidekiq.log. Se quel file/directory viene ricreato con proprietà/permessi diversi, Sidekiq può uscire immediatamente prima di produrre log utili.

Trigger correlato: logrotate fallisce quotidianamente

Separately, logrotate falliva ogni giorno con:

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

La causa erano i permessi standard Debian/Ubuntu:

  • /var/log è root:adm con 0775 (scrivibile dal gruppo).
  • logrotate rifiuta la rotazione a meno che non venga impostata una direttiva su globale. Questo è il comportamento previsto a monte.

Nel momento in cui il job giornaliero di logrotate è fallito, ha anche ricreato i file sotto /shared/log/rails/ (incluso sidekiq.log), che probabilmente ha interagito con la registrazione forzata tramite -L e ha contribuito al ciclo di crash di Sidekiq “1s”.

Correzione (nessuna ricostruzione necessaria)

  1. Correggere logrotate in modo che smetta di toccare i log condivisi in stato di errore Aggiungere una direttiva su globale:
# /etc/logrotate.conf (inizio)
su root adm

Dopodiché, logrotate -v esce con 0 e non segnala più permessi non sicuri della directory padre.

  1. Sostituire lo script runit di Sidekiq con uno predefinito più robusto Passare a discourse:discourse e al sidekiq.yml standard, e non forzare -L log/sidekiq.log, rende Sidekiq stabile:
#!/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'

Dopo questo:

  • sv status sidekiq rimane in esecuzione:
  • I job AI/in background riprendono.

Richiesta / suggerimento

Potremmo considerare di rendere il servizio Sidekiq ufficiale Docker/runit più robusto per impostazione predefinita?

Ad esempio:

  • Eseguire Sidekiq sotto discourse:discourse (corrispondente alla proprietà tipica all’interno del container).
  • Preferire bundle exec sidekiq -C config/sidekiq.yml.
  • Evitare di forzare un file di log condiviso tramite -L log/sidekiq.log, o renderlo resiliente alla deriva dei permessi di logrotate/volume condiviso.

Anche una nota nella documentazione (“se Sidekiq mostra down: 1s ma l’avvio manuale funziona, controllare /etc/service/sidekiq/run ed evitare la registrazione condivisa forzata”) aiuterebbe molto gli self-hoster.

Sono disponibile a fornire ulteriori log se necessario. Grazie!

1 Mi Piace

Dove lo stai trovando? Sidekiq viene avviato tramite il master di unicorn per conservare memoria. Non vedo questo codice affatto in discourse_docker. Sembra che tu stia usando una configurazione molto vecchia?

2 Mi Piace

Ciao, permettimi di ribadire questo basandomi strettamente sui fatti di runtime dal container Docker ufficiale.

Cosa sto vedendo nel container in esecuzione (fatti)

Questa è un’installazione Docker ufficiale con runit (flusso di lavoro standard del lanciatore /var/discourse; nessuna ricostruzione immediatamente prima dell’incidente). All’interno del container:

  1. Esiste un servizio Sidekiq runit ed è quello supervisionato
ls -l /etc/service/sidekiq/run
sv status sidekiq

Output durante l’incidente:

down: sidekiq: 1s, normally up, want up
  1. L’avvio manuale di Sidekiq funziona
cd /var/www/discourse
sudo -u discourse bundle exec sidekiq -C config/sidekiq.yml

Questo rimane attivo, si connette a Redis ed elabora i job.

  1. La sola modifica di /etc/service/sidekiq/run (nessuna ricostruzione) risolve immediatamente il crash loop Sostituito /etc/service/sidekiq/run con:
#!/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'

Dopo di che:

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

Quindi Sidekiq non viene avviato tramite Unicorn master in questa immagine; è un servizio runit il cui script di runtime può entrare in un ciclo di crash.

Perché potresti non vedere il codice esatto in

discourse_docker

Concordo sul fatto che il testo letterale potrebbe non essere nel repository perché /etc/service/sidekiq/run è un artefatto di runtime generato/iniettato durante la build/boot dell’immagine, non necessariamente un file verbatim in discourse_docker. Ma è il servizio supervisionato attivo in questa immagine ufficiale, come mostrato sopra.

Cosa ha innescato la fragilità (fatti + minima inferenza)

  • Abbiamo anche osservato fallimenti giornalieri di logrotate a causa delle autorizzazioni Debian standard: /var/log = root:adm 0775, quindi logrotate ha rifiutato la rotazione fino all’aggiunta di global su root adm.
  • Quando logrotate falliva, ricreava file sotto /shared/log/rails/, incluso sidekiq.log.
  • Lo script runit predefinito in questa immagine utilizzava discourse:www-data e forzava -L log/sidekiq.log in /shared/log, il che rende Sidekiq molto sensibile alla deriva delle autorizzazioni del volume condiviso e può causare un’uscita immediata prima che vengano generati log utili.

Richiesta / proposta

Dato quanto sopra, potremmo considerare di rafforzare il servizio Sidekiq Docker/runit predefinito?

Impostazioni predefinite suggerite:

  • eseguire come discourse:discourse (corrisponde alla proprietà tipica all’interno del container),
  • avviare tramite bundle exec sidekiq -C config/sidekiq.yml,
  • evitare di forzare un -L log/sidekiq.log condiviso (o renderlo resiliente).

Ciò impedirebbe il ciclo di crash silenzioso down: 1s che interrompe tutti i job in background/AI.

Sono disponibile a testare qualsiasi branch/commit che mi indicherai.

Ancora… sono confuso su dove stai prendendo la tua immagine:

image

Questa è l’immagine ufficiale.

Questa è una ricerca per la parola sidekiq nel discourse docker ufficiale.

https://github.com/search?q=repo%3Adiscourse%2Fdiscourse_docker%20sidekiq&type=code

Ci sono 3 risultati… niente su un’unità runit. È gestito tramite unicorn.

1 Mi Piace

Ciao, grazie, quello screenshot aiuta a chiarire il layout.

Sono d’accordo che nell’immagine ufficiale attuale Sidekiq non è un servizio runit separato (nessun /etc/service/sidekiq/). Viene avviato dalla catena di avvio del servizio runit di unicorn, che corrisponde al tuo elenco /etc/service.

Il mio rapporto riguarda ancora una modalità di errore a runtime di quel percorso di avvio di Sidekiq, indipendentemente dal fatto che risieda in un’unità runit autonoma o all’interno di unicorn/run:

Fatti dal runtime sul mio VPS (Docker ufficiale, nessun rebuild/aggiornamento subito prima dell’incidente):

  1. I processi in background si sono interrotti e le risposte AI si sono interrotte.

  2. Sidekiq è entrato in un loop di crash immediato (giù: 1s) quando è stato avviato dal supervisore/catena di avvio del container.

  3. L’avvio manuale come discourse tramite bundle exec sidekiq -C config/sidekiq.yml è rimasto attivo ed ha elaborato i job, quindi l’app/redis erano a posto.

  4. Allo stesso tempo, i fallimenti di logrotate hanno causato la ricreazione di /shared/log/rails/sidekiq.log (e percorsi correlati) con permessi diversi; dopo aver stabilizzato il comando di avvio di Sidekiq (eseguito come discourse:discourse, usa sidekiq.yml, evita di forzare shared -L sidekiq.log), il loop di crash si è interrotto immediatamente.

Quindi il file letterale /etc/service/sidekiq/run potrebbe non esistere in questa immagine — d’accordo — ma il passaggio di avvio di Sidekiq incorporato nel servizio runit di unicorn è fragile rispetto alle permessi del volume condiviso/deriva di logrotate e può silenziosamente terminare Sidekiq senza un rebuild. Questo è il problema principale.

Suggerimento: si prega di considerare di rafforzare l’avvio di Sidekiq nello script runit di unicorn ufficiale (o dove viene generato):

  • Esegui Sidekiq sotto discourse:discourse,

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

  • Evita di forzare un -L log/sidekiq.log condiviso (o rendilo resiliente).