Script runit de Sidekiq demasiado frágil: **discourse:www-data** **+ forzado** **-L log/sidekiq.log** **causa fallo de 1 segundo**

Hola equipo:

Informo de un modo de fallo en la configuración oficial de Docker/runit que puede terminar silenciosamente con Sidekiq (y por lo tanto con los trabajos de IA/fondo) sin ninguna reconstrucción o actualización.

Entorno

  • Instalación oficial de Discourse Docker (contenedor estándar + servicios runit).
  • Sin reconstrucción/actualización justo antes de que comenzara el problema.
  • El complemento Discourse AI está habilitado, pero la IA dejó de responder.

Síntomas

  • La IA parece habilitada en la interfaz de administración, pero no aparecen respuestas de IA.
  • Los trabajos en segundo plano (IA/incrustaciones/respuesta automática) parecen estar atascados.
  • sv status sidekiq muestra que Sidekiq muere repetidamente justo después de iniciarse:
down: sidekiq: 1s, normally up, want up
  • Iniciar Sidekiq manualmente funciona bien, por lo que la aplicación en sí está bien:
bundle exec sidekiq -C config/sidekiq.yml
# permanece activo, se conecta a Redis, procesa trabajos

Lo que encontramos

El script runit predeterminado era:

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

Dos puntos de fragilidad:

  1. Grupo principal www-data En mi contenedor, las rutas típicas de escritura son propiedad de discourse:discourse. Cualquier deriva en tmp/pids o rutas compartidas puede hacer que Sidekiq salga durante el arranque cuando se ejecuta bajo www-data, aunque el inicio manual como discourse funcione.
  2. Escritura forzada -L log/sidekiq.log en registros compartidos La ruta del registro es un enlace simbólico a /shared/log/rails/sidekiq.log. Si ese archivo/directorio se recrea con diferente propiedad/permisos, Sidekiq puede salir inmediatamente antes de producir registros útiles.

Desencadenante relacionado: logrotate fallando diariamente

Por separado, logrotate fallaba todos los días con:

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

La causa fueron los permisos estándar de Debian/Ubuntu:

  • /var/log es root:adm con 0775 (escritura de grupo).
  • logrotate se niega a rotar a menos que se establezca una directiva su global. Este es el comportamiento esperado aguas arriba.

En el momento en que el trabajo diario de logrotate falló, también recreó archivos en /shared/log/rails/ (incluido sidekiq.log), lo que probablemente interactuó con el registro forzado -L y contribuyó al bucle de “fallo de 1s” de Sidekiq.

Solución (no se necesita reconstrucción)

  1. Arreglar logrotate para que deje de tocar los registros compartidos en un estado de fallo Agregar una directiva su global:
# /etc/logrotate.conf (parte superior)
su root adm

Después de eso, logrotate -v sale con 0 y ya no informa de permisos de directorio padre inseguros.

  1. Reemplazar el script runit de Sidekiq con una predeterminada más robusta Cambiar a discourse:discourse y el sidekiq.yml estándar, y no forzar -L log/sidekiq.log, hace que Sidekiq sea estable:
#!/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'

Después de esto:

  • sv status sidekiq permanece en ejecución:
  • Los trabajos de IA/fondo se reanudan.

Solicitud / sugerencia

¿Podríamos considerar hacer que el servicio Sidekiq oficial de Docker/runit sea más robusto por defecto?

Por ejemplo:

  • Ejecutar Sidekiq bajo discourse:discourse (coincidiendo con la propiedad típica dentro del contenedor).
  • Preferir bundle exec sidekiq -C config/sidekiq.yml.
  • Evitar forzar un archivo de registro compartido a través de -L log/sidekiq.log, o hacerlo resistente a la deriva de permisos de logrotate/volumen compartido.

Incluso una nota de documentación (“si Sidekiq muestra down: 1s pero el inicio manual funciona, verifique /etc/service/sidekiq/run y evite el registro compartido forzado”) ayudaría mucho a los autoalojados.

Estoy a su disposición para proporcionar más registros si es necesario. ¡Gracias!

1 me gusta

¿Dónde estás encontrando eso? Sidekiq se lanza a través del maestro de unicornio para conservar memoria. No veo este código en absoluto en discourse_docker. Parece que quizás estás usando una configuración muy antigua?

2 Me gusta

Hola: permítame reiterar esto estrictamente basándome en los hechos en tiempo de ejecución del contenedor Docker oficial.

Lo que estoy viendo en el contenedor en ejecución (hechos)

Esta es una instalación oficial de Docker con runit (flujo de trabajo estándar del lanzador /var/discourse; sin reconstrucción justo antes del incidente). Dentro del contenedor:

  1. Existe un servicio Sidekiq de runit y es el que está siendo supervisado
ls -l /etc/service/sidekiq/run
sv status sidekiq

Salida durante el incidente:

down: sidekiq: 1s, normally up, want up
  1. El inicio manual de Sidekiq funciona
cd /var/www/discourse
sudo -u discourse bundle exec sidekiq -C config/sidekiq.yml

Esto permanece activo, se conecta a Redis y procesa trabajos.

  1. Solo parchear /etc/service/sidekiq/run (sin reconstruir) soluciona el bucle de fallos inmediatamente Reemplacé /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'

Después de eso:

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

Por lo tanto, Sidekiq no se está iniciando a través del maestro de Unicorn en esta imagen; es un servicio runit cuyo script de tiempo de ejecución puede entrar en bucle de fallos.

Por qué es posible que no vea el código exacto en

discourse_docker

Estoy de acuerdo en que el texto literal puede no estar en el repositorio porque /etc/service/sidekiq/run es un artefacto de tiempo de ejecución generado/inyectado durante la compilación/arranque de la imagen, no necesariamente un archivo literal en discourse_docker. Pero es el servicio supervisado activo en esta imagen oficial, como se demostró anteriormente.

Lo que desencadenó la fragilidad (hechos + inferencia mínima)

  • También observamos fallos diarios de logrotate debido a los permisos estándar de Debian: /var/log = root:adm 0775, por lo que logrotate se negó a rotar hasta que se agregó su root adm global.
  • Cuando logrotate fallaba, recreaba archivos en /shared/log/rails/, incluido sidekiq.log.
  • El script runit predeterminado en esta imagen usaba discourse:www-data y forzaba -L log/sidekiq.log en /shared/log, lo que hace que Sidekiq sea muy sensible a la deriva de permisos del volumen compartido y puede causar una salida inmediata antes de obtener registros útiles.

Solicitud / propuesta

Dado lo anterior, ¿podríamos considerar reforzar el servicio Sidekiq predeterminado de Docker/runit?

Valores predeterminados sugeridos:

  • ejecutar como discourse:discourse (coincide con la propiedad típica dentro del contenedor),
  • iniciar a través de bundle exec sidekiq -C config/sidekiq.yml,
  • evitar forzar un -L log/sidekiq.log compartido (o hacerlo resistente).

Esto evitaría el bucle de fallos silencioso down: 1s que detiene todos los trabajos en segundo plano/IA.

Estaré encantado de probar cualquier rama/commit al que me señale.

De nuevo… estoy confundido sobre de dónde estás obteniendo tu imagen:

image

Esta es la imagen oficial.

Esta es una búsqueda de la palabra sidekiq en el discourse docker oficial.

Hay 3 resultados… nada sobre una unidad runit. Se gestiona a través de unicorn.

1 me gusta

Hola, gracias, esa captura de pantalla ayuda a aclarar el diseño.

Estoy de acuerdo en que en la imagen oficial actual Sidekiq no es un servicio runit separado (no hay /etc/service/sidekiq/). Se inicia desde la cadena de inicio del servicio runit de unicorn, lo que coincide con su listado de /etc/service.

Mi informe sigue siendo sobre un modo de fallo en tiempo de ejecución de esa ruta de lanzamiento de Sidekiq, independientemente de si reside en una unidad runit independiente o dentro de unicorn/run:

Hechos del tiempo de ejecución en mi VPS (Docker oficial, sin reconstrucción/actualización justo antes del incidente):

  1. Los trabajos en segundo plano se detuvieron y las respuestas de IA dejaron de funcionar.

  2. Sidekiq entró en un bucle de bloqueo inmediato (caído: 1s) cuando fue iniciado por el supervisor/cadena de inicio del contenedor.

  3. El inicio manual como discourse mediante bundle exec sidekiq -C config/sidekiq.yml se mantuvo activo y procesó trabajos, por lo que la aplicación/redis estaban bien.

  4. Al mismo tiempo, los fallos de logrotate provocaron que se recrearan /shared/log/rails/sidekiq.log (y rutas relacionadas) con permisos diferentes; después de estabilizar el comando de inicio de Sidekiq (ejecutar como discourse:discourse, usar sidekiq.yml, evitar forzar -L sidekiq.log compartido), el bucle de bloqueo se detuvo inmediatamente.

Por lo tanto, el archivo literal /etc/service/sidekiq/run puede no existir en esta imagen, estoy de acuerdo, pero el paso de inicio de Sidekiq incrustado en el servicio runit de unicorn es frágil a las permutaciones de volumen compartido/deriva de logrotate y puede matar silenciosamente a Sidekiq sin una reconstrucción. Ese es el problema central.

Sugerencia: considere fortalecer el lanzamiento de Sidekiq en el script runit oficial de unicorn (o donde se genera):

  • Ejecutar Sidekiq bajo discourse:discourse,

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

  • Evitar forzar un -L log/sidekiq.log compartido (o hacerlo resistente).