Las cargas no se quedan huérfanas ni se purgan

Hola,

Recientemente me convertí en el último administrador y mantenedor de una instancia básica de imagen Docker de Discourse que se instaló originalmente en nuestro servidor en 2021 (creo) y fue actualizada en su mayoría por otra persona. Desde hace algún tiempo, posiblemente desde el principio, hemos tenido un problema con las cargas de archivos de publicaciones eliminadas de forma suave que no se quedan huérfanas y se purgan, y he estado intentando solucionar este problema nuevamente durante unos días, ya que los archivos obsoletos se acumulan y desperdician espacio de almacenamiento. No usamos S3 y hay suficiente almacenamiento para las cargas que realmente queremos mantener disponibles.

He migrado el archivo de copia de seguridad completo de Discourse, incluidas las cargas, a un servidor de staging separado para realizar pruebas reconstruyendo con nuestro app.yml siguiendo las guías oficiales de instalación de Docker de Discourse y, después de eso, restaurando la copia de seguridad desde la línea de comandos. Ambas instalaciones parecen funcionar de manera idéntica sin otros problemas obvios, pero el problema de las cargas persiste.

No parece que encuentre errores relevantes en ningún registro y Sidekiq está ejecutando los trabajos de limpieza según lo programado. He ejecutado rake db:migrate en la versión de staging y reconstruido muchas veces, he intentado eliminar publicaciones permanentemente y he revisado la configuración. Después de eliminar permanentemente algunas publicaciones directamente desde la consola de Rails e intentar ejecutar el trabajo de limpieza manualmente, noté que el directorio de marcadores de tumba había crecido un poco en tamaño en algún momento y ya había algunos archivos al principio, por lo que el mecanismo debe haber estado funcionando en algunas situaciones, ¿verdad? A juzgar por el pequeño aumento de tamaño, casi todos los archivos obsoletos aún no se detectan como huérfanos.

Configuración actual relevante del panel de administración que se enumera a continuación. ¿Puedo establecer las últimas en 0 para omitir efectivamente los períodos de gracia durante las pruebas?

limpiar cargas = true
período de gracia de horas para cargas huérfanas = 1
días de período de gracia para purgar cargas eliminadas = 1

¿Cómo puedo solucionar esto de manera eficiente? Me siento cómodo con la línea de comandos, pero mis habilidades de base de datos son rudimentarias, por lo que realmente agradecería algunos consejos para evitar revisar cada detalle posible de la configuración del servidor sin tener idea de lo que estoy buscando en este momento.

He estado buscando y leyendo desesperadamente en este foro casos similares, pero solo hay unos pocos y esos hilos parecen detenerse en un callejón sin salida o en soluciones manuales para archivos individuales, por lo que no son directamente adecuados para este caso de uso.

Por favor, pídame más detalles si es necesario, estoy haciendo todo lo posible para resolver esto de una vez por todas.

3 Me gusta

Hola y bienvenido @Uphill4721 :slight_smile:

Creo que hay información relevante en estos temas, si mal no recuerdo:

1 me gusta

¡Gracias por la rápida respuesta!

Esos temas y algunos más enlazados en ellos me resultan bastante familiares mientras intento resolver este problema, pero lamentablemente no han proporcionado ninguna solución definitiva a este problema.

Ayer, en el servidor de staging, ejecuté estos comandos modificados para temas y publicaciones eliminados hace más de 9 días:

Después de esto, noté un ligero aumento en el tamaño del contenido del directorio de lápidas y todavía estoy monitoreando la situación debido al período de gracia, todavía me pregunto si cambiar la configuración relevante a cero horas/días evitaría el tiempo de espera durante las pruebas.

Anteriormente, en el servidor original, intenté eliminar cargas de las revisiones de publicaciones más recientes, pero los archivos todavía estaban disponibles después del período de gracia.

En este punto, personalmente estaría más que encantado de encontrar cualquier solución manual que funcione para eliminar permanentemente incluso un solo tema con sus publicaciones y cargas no referenciadas en ningún otro lugar, pero este podría ser un gran problema para otras personas que ejecutan Discourse, asumiendo naturalmente que la configuración de limpieza en el panel de administración sería efectiva como se describe, pero sin notar necesariamente si no es el caso y terminando con cargas potencialmente sensibles que se espera que se eliminen permanentemente pero que en realidad permanecen en el sistema de archivos. Nuestro problema, afortunadamente, solo considera el almacenamiento desperdiciado, pero para otra persona esto podría ser mucho peor.

Hay otra mención similar hace solo dos meses:

Entonces, ¿algún consejo sobre cómo determinar si se trata de una mala configuración de nuestra parte o de un error real? Hemos estado muy contentos con Discourse en otros aspectos y estoy muy motivado para resolver esto y ayudar a otros en el camino.

1 me gusta

Esto es puramente especulativo, pero con un vistazo rápido a los modelos post, post_upload y upload, probablemente puedas averiguar si tienes subidas huérfanas (objetos de base de datos) con esto:

Upload.find_by_sql("select * from uploads where id in (select upload_id from post_uploads where post_id not in (select id from posts))")

No lo he probado, así que no puedo estar seguro de si encontrará subidas huérfanas correctamente o incluso si se ejecutará sin errores. En caso de que no funcione tal cual y alguien más pueda hacerlo funcionar, así como para cualquier otra persona interesada, desglosaré la intención.

  1. Upload.find_by_sql() devuelve una colección de objetos Upload que coinciden con la consulta SQL proporcionada.
  2. (select id from posts) obtiene todos los IDs de las publicaciones existentes.
  3. (select upload_id from post_uploads where post_id not in ()) obtiene todos los IDs de las subidas de publicaciones para las que no existe ninguna publicación.
  4. select * from uploads where id in () obtiene todas las subidas que coinciden con esos IDs de subidas de publicaciones.

Sin embargo, esa es solo una vía posible para investigar, desafortunadamente no conozco el sistema de subidas lo suficientemente bien como para contribuir mucho más, excepto para decir que lo anterior definitivamente no tiene en cuenta todas las situaciones. Las publicaciones editadas en lugar de eliminadas son una obvia.

También hay otros tipos de subidas no tenidas en cuenta, como las subidas de usuarios, que supongo que son cosas como subir una foto de perfil.

Los plugins también pueden crear y retener subidas, no sé qué sucede con ellas si, por ejemplo, se elimina el plugin. Creo que los datos del plugin permanecen en la base de datos después de que se elimina un plugin, lo que potencialmente significa que cualquier subida creada por ese plugin nunca se elimina en esa situación.

4 Me gusta

¡Gracias por la respuesta!

La consulta funciona, pero solo muestra dos cargas y sus detalles. Debería haber cientos o miles de cargas que coincidan con los criterios de “huérfanas”, la mayoría son archivos de imagen cargados originalmente por los usuarios al hacer publicaciones normales.

Actualmente solo estamos utilizando complementos oficiales:

hooks:
  after_code:
    - exec:
        cd: $home/plugins
        cmd:
          - git clone https://github.com/discourse/docker_manager.git
          - git clone https://github.com/discourse/discourse-chat-integration.git
          - git clone https://github.com/discourse/discourse-prometheus.git
          - git clone https://github.com/discourse/discourse-bbcode-color
          - git clone https://github.com/discourse/discourse-data-explorer

Hubo una especie de revisión del proceso de carga poco después de nuestra instalación original, me pregunto si podría estar relacionado con nuestra situación de alguna manera: A new era for file uploads in Discourse

El período de gracia debería haber pasado ya en el servidor de staging, pero no veo ningún efecto en el tamaño del directorio de carga y los archivos de prueba todavía están disponibles. ¿Qué debería buscar a continuación? ¿Podría ser causado por permisos defectuosos del sistema de archivos o algo similar, hay una forma fácil de comprobarlo? Me estoy quedando sin ideas de objetivos específicos, todo lo demás funciona muy bien y este es el único problema que tenemos actualmente.

Revisando temas similares para recopilar casos sin resolver que puedan coincidir, aquí hay un buen ejemplo de cómo estas situaciones podrían incluso causar problemas legales debido a que las cargas de los usuarios no se quedan huérfanas y se eliminan permanentemente como deberían:

Otra situación similar desde 2016:

Estas condiciones crean una gran apertura para el abuso e incluso para ataques dirigidos para cargar contenido ilegal que podría no eliminarse permanentemente del servidor, incluso cuando los administradores asumen que lo haría. Por supuesto, eliminar archivos individuales manualmente directamente desde el sistema de archivos es posible, pero no creo que la gente deba verse obligada a tomar esa ruta para una necesidad tan básica, especialmente cuando hay una configuración gráfica que indica un proceso de purga automática y los moderadores a menudo no tienen acceso directo al servidor. Además, la eliminación manual no es práctica con una gran cantidad de archivos dispersos en diferentes temas eliminados.

¿Hay suficiente base aquí para un informe de error real? Todavía no descarto una posible mala configuración de nuestra parte, pero estoy desconcertado por la falta de mensajes de error y todo lo demás parece estar funcionando bien. He pasado una cantidad creciente de días en la resolución de problemas y pruebas, adquiriendo más conocimiento sobre Discourse y sus componentes en el proceso, así que creo que con algo de orientación podría ayudar a determinar si hay algún detalle de un caso extremo que esté desencadenando este comportamiento extraño. ¿Espero que esté bien mencionar a @zogstrip en este punto?

Como solución temporal, ¿es posible mover manualmente todas las cargas al directorio de “tombstone” y usar los métodos de recuperación de cargas para restaurar solo los archivos no huérfanos de vuelta a sus directorios correctos? De hecho, intenté hacer esto hoy, pero rake uploads:recover_from_tombstone no restauró ningún archivo. ¿Podría esto apuntar a un problema mayor con las entradas de la base de datos de las cargas?

Hola. Estoy experimentando el mismo problema o uno similar, no puedo averiguar por qué los archivos no se pueden eliminar. ¿Alguien más sigue teniendo este problema?
Ejecuté algunas consultas SQL y las referencias de carga “atascadas” parecen ser todas Borradores, pero revisé mis Borradores y los de otros usuarios y no hay ninguno. Las tablas de Borradores están vacías.
La limpieza de huérfanos está habilitada y la configuración está establecida para eliminar los huérfanos lo más rápido posible.
Adjunto una consulta SQL.

SELECT 
    uploads.original_filename,
    ROUND(uploads.filesize / 1000000.0, 2) AS size_in_mb,
    uploads.extension,
    uploads.created_at,
    uploads.url,
    upload_references.upload_id,
    upload_references.target_id,
    upload_references.target_type,
    upload_references.created_at,
    upload_references.updated_at
FROM upload_references
JOIN uploads ON uploads.id = upload_references.upload_id
ORDER BY uploads.filesize DESC
LIMIT 250

sql.csv (46,1 KB)

Esto sucede desde que instalé el foro. Incluso cuando no había temas personalizados ni plugins instalados.
Incluso el antiguo logotipo del foro que subí un par de veces (el primer archivo subido) todavía se referencia como Borrador y todavía está en la carpeta de subidas. :man_facepalming:
Teóricamente podría filtrar todas las referencias de carga y filtrar por Borradores por target_type, luego eliminar de la base de datos… y dejar que las tareas de sidekiq manejen la limpieza (¿tengo razón?)
pero estoy usando una instancia autoalojada y soy bastante nuevo en Discourse, así que es mejor preguntar aquí…
Esa sería una solución alternativa, pero todavía queda una pregunta: ¿por qué está sucediendo esto?

Espero que alguien tenga algunas sugerencias, mi espacio en disco está creciendo exponencialmente :smile:

1 me gusta

Sí, todavía tenemos este problema.\n\nRealmente me gustaría solucionarlo de alguna manera, nuestro foro recibe muchas cargas pero solo una fracción de ellas necesita ser conservada a largo plazo, por lo que se está desperdiciando mucho espacio en disco. Cualquier sugerencia para solucionar problemas es bienvenida.\n\n[quote="kilometrs, post:7, topic:259036, username:groove6j"]\nTeóricamente podría filtrar todas las referencias de carga y filtrar por borradores por tipo de destino, luego eliminar de la base de datos… y dejar que las tareas de sidekiq se encarguen de la limpieza (¿tengo razón?)\n[/quote]\n\nInteresado en esto como una solución temporal, si es práctica. :thinking:

Instalé el foro hace 2 semanas y ha tenido este problema desde el principio. Parece algún error.
¿Puedes ejecutar la misma consulta SQL y comprobar si hay muchas referencias de “Borradores” atascadas? Es fácil de ver, tengo docenas de ellas, pero en la tabla de borradores hay 2, quizás 3 borradores reales. Parece que no se eliminan después de editar (al dejar de ser un borrador, pero la referencia queda en la base de datos cada vez que se edita una publicación, por ejemplo).

Necesito averiguar cómo eliminar una entrada de referencia de la base de datos y eliminar las referencias de un archivo primero, luego comprobar si la tarea de limpieza funciona.
No sé qué tan seguro es hacer esto, pero estas innumerables entradas de Borradores me parecen simplemente incorrectas.

Puedo proporcionar registros al personal/desarrolladores, solo soy nuevo en Discourse y no sé qué archivos de registro serían útiles.

EDITAR:
Estoy tratando de entender la estructura de la base de datos, y ¿puedo eliminar esas entradas de carga sin más problemas (no quiero perderme algunas relaciones importantes de la base de datos)? Tampoco entiendo qué son exactamente las secuencias de borradores.
Pero tengo que duplicar mi foro de producción en una VM local, solo entonces podré probar…

Otro tema relevante, publiqué allí ya que no estaba al tanto de este tema.

Creo que la única forma de eliminar una imagen de forma automática es editarla manualmente antes de eliminarla. Pero no estoy completamente seguro de que eso funcione. Estoy usando la misma configuración que tú en cuanto a purga (pero uso almacenamiento compatible con S3) y también puedo confirmar que las imágenes nunca se purgan si la única publicación que contiene esa imagen (varias publicaciones pueden contener la misma imagen, presumiblemente avatares y banners de usuario también) se elimina.

Uso esta solución para buscar si una imagen se utiliza en publicaciones adicionales, que fue proporcionada por @RGJ

Sería genial si esto se pudiera hacer automáticamente. Particularmente debido a que Discourse maneja las imágenes de manera inteligente, evitando la creación de archivos duplicados si muchas publicaciones usan la misma imagen. La desventaja es que es muy tedioso eliminar imágenes individuales que se han utilizado mucho.

Tuve a alguien que spammeó contenido que necesitaba ser eliminado urgentemente a través de varias cuentas antes, y fue muy estresante intentar lidiar con ello y asegurarme de que se eliminara por completo (todos los archivos originales, archivos optimizados, caché de CDN, publicaciones, avatares, banners de usuario, etc.).

Hice esta sugerencia de función, ya que creo que sería muy útil. Si esto se implementara, además de purgar automáticamente el contenido contenido en las publicaciones eliminadas, creo que todos los casos estarían cubiertos y podrían manejarse sin acceso SSH.

1 me gusta