Uploads não estão sendo órfãos e purgados.

Olá,

Recentemente, tornei-me o último administrador e mantenedor restante de uma instância básica de imagem Docker do Discourse que foi originalmente instalada em nosso servidor em 2021 (acho) e, em grande parte, atualizada por outra pessoa. Há algum tempo, possivelmente desde o início, temos tido um problema com uploads de posts excluídos de forma suave que não estão sendo órfãos e purgados, e venho tentando solucionar esse problema novamente há alguns dias, pois os arquivos obsoletos continuam se acumulando e desperdiçando espaço de armazenamento. Não estamos usando S3 e há espaço de armazenamento suficiente para os uploads que realmente queremos manter disponíveis.

Migrei o arquivo de backup completo do Discourse, incluindo uploads, para um servidor de staging separado para testes, reconstruindo com nosso app.yml seguindo os guias oficiais de instalação do Discourse Docker e, em seguida, restaurando o backup a partir da linha de comando. Ambas as instalações parecem estar rodando de forma idêntica e sem outros problemas óbvios, mas o problema de upload permanece.

Não consigo encontrar nenhum erro relevante nos logs e o Sidekiq está executando os trabalhos de limpeza conforme agendado. Executei rake db:migrate na versão de staging e reconstruí muitas vezes, tentei excluir posts permanentemente e verifiquei as configurações. Após excluir permanentemente alguns posts diretamente do console rails e tentar executar o trabalho de limpeza manualmente, notei que o diretório tombstone havia crescido um pouco em tamanho em algum momento e já havia alguns arquivos nele de qualquer maneira, então o mecanismo deve ter funcionado em algumas situações, certo? Julgando pelo pequeno aumento de tamanho, quase todos os arquivos obsoletos ainda não são detectados como órfãos.

As configurações atuais relevantes do painel de administração estão listadas abaixo. Posso definir as últimas para 0 para efetivamente pular os períodos de carência durante os testes?

limpar uploads = true
período de carência de horas para uploads órfãos = 1
dias de carência para purgar uploads excluídos = 1

Como posso solucionar isso eficientemente? Sinto-me confortável com a linha de comando, mas minhas habilidades de banco de dados são rudimentares, então eu realmente apreciaria algumas dicas para evitar passar por todos os possíveis detalhes de configuração do servidor sem ter ideia do que estou procurando neste momento.

Tenho pesquisado e lido desesperadamente neste fórum por casos semelhantes, mas há apenas alguns e esses tópicos parecem parar em um beco sem saída ou em soluções manuais para arquivos únicos, então não são diretamente adequados para este caso de uso.

Por favor, me peça mais detalhes se necessário, estou fazendo o meu melhor para resolver isso de uma vez por todas.

3 curtidas

Olá e bem-vindo @Uphill4721 :slight_smile:

Acho que há algumas informações relevantes nesses tópicos, se bem me lembro:

1 curtida

Obrigado pela resposta rápida!

Esses tópicos e alguns outros vinculados a eles tornaram-se bastante familiares para mim ao tentar resolver este problema, mas, infelizmente, eles não forneceram nenhuma solução definitiva para este problema.

Ontem, no servidor de staging, executei estes comandos modificados para tópicos e posts excluídos há mais de 9 dias:

Depois disso, notei um leve aumento no tamanho do conteúdo do diretório de túmulos e ainda estou monitorando a situação devido ao período de carência, ainda me perguntando se alterar as configurações relevantes para zero horas/dias contornaria o tempo de espera durante os testes.

Anteriormente, no servidor original, tentei remover uploads das revisões de posts mais recentes, mas os arquivos ainda estavam disponíveis após o período de carência.

Neste ponto, eu estaria pessoalmente mais do que feliz em descobrir qualquer solução manual funcional para excluir permanentemente até mesmo um único tópico com seus posts e uploads não referenciados em nenhum outro lugar, mas isso pode ser um grande problema para outras pessoas que executam o Discourse, naturalmente assumindo que as configurações de limpeza no painel de administração seriam eficazes conforme descrito, mas não necessariamente notando se não for o caso e acabando com uploads potencialmente sensíveis que deveriam ser excluídos permanentemente, mas que na verdade permanecem no sistema de arquivos. Nosso problema, felizmente, considera apenas armazenamento desperdiçado, mas para outra pessoa isso pode ser muito pior.

Há outra menção semelhante há apenas dois meses:

Então, alguma dica sobre como descobrir se isso é uma má configuração do nosso lado ou um bug real? Estamos muito satisfeitos com o Discourse, caso contrário, e estou muito motivado a resolver isso e ajudar outras pessoas no caminho.

1 curtida

Isto é puramente especulativo, mas com uma rápida olhada nos modelos post, post_upload e upload, você provavelmente pode descobrir se tem uploads órfãos (objetos de banco de dados) com isto:

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))")

Eu não testei isso, então não posso ter certeza se ele encontrará uploads órfãos corretamente ou mesmo executará sem erro. Caso não funcione como está e alguém mais possa fazê-lo funcionar, bem como apenas para qualquer outra pessoa interessada, vou detalhar a intenção.

  1. Upload.find_by_sql() retorna uma coleção de objetos Upload que são correspondidos pela consulta SQL fornecida.
  2. (select id from posts) obtém todos os IDs de posts existentes.
  3. (select upload_id from post_uploads where post_id not in () obtém todos os IDs de uploads de posts para os quais não existe post.
  4. select * from uploads where id in () obtém todos os uploads que correspondem a esses IDs de uploads de posts.

Essa é apenas uma via possível para investigar, infelizmente não conheço o sistema de uploads bem o suficiente para contribuir muito de outra forma, exceto para dizer que o acima definitivamente não leva em conta todas as situações. Posts editados em vez de excluídos são um exemplo óbvio.

Existem também outros tipos de uploads não contabilizados, como uploads de usuários, que presumo serem coisas como o upload de uma foto de perfil.

Plugins também podem criar e reter uploads, não sei o que acontece com eles se, digamos, o plugin for removido. Acho que os dados do plugin permanecem no banco de dados após a remoção de um plugin, o que potencialmente significa que quaisquer uploads criados por esse plugin nunca são removidos nessa situação.

4 curtidas

Obrigado pela resposta!

A consulta funciona, mas lista apenas dois uploads e seus detalhes. Deveria haver centenas ou milhares de uploads correspondendo aos critérios órfãos, a maioria são arquivos de imagem originalmente carregados por usuários ao fazer postagens normais.

Atualmente, estamos usando apenas plugins oficiais:

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

Houve uma espécie de reformulação no processo de upload um tempo depois da nossa instalação original, me pergunto se poderia estar relacionado à nossa situação de alguma forma: A new era for file uploads in Discourse

O período de carência já deveria ter passado no servidor de staging, mas não vejo nenhum efeito no tamanho do diretório de uploads e os arquivos de teste ainda estão disponíveis. O que devo procurar a seguir? Isso poderia ser causado por permissões de sistema de arquivos defeituosas ou algo assim, existe uma maneira fácil de verificar? Estou ficando sem ideias de alvos específicos, todo o resto está funcionando bem e este é o único problema que temos atualmente.

Revisando tópicos semelhantes para coletar casos potencialmente correspondentes e não resolvidos, aqui está um bom exemplo de como essas situações podem até causar problemas legais devido a uploads de usuários que não são órfãos e removidos permanentemente como deveriam:

Outra situação semelhante, de 2016:

Esses tipos de condições criam uma enorme abertura para abuso e até ataques direcionados para o upload de conteúdo ilegal que pode não ser permanentemente removido do servidor, mesmo quando os administradores assumem que seria. Claro, excluir arquivos individuais manualmente direto do sistema de arquivos é possível, mas não acho que as pessoas devam ser forçadas a seguir esse caminho para uma necessidade tão básica, especialmente quando há uma configuração de GUI indicando um processo de purga automática e os moderadores muitas vezes não têm acesso direto ao servidor. Além disso, a exclusão manual não é prática com muitos arquivos espalhados em diferentes tópicos excluídos.

Existe base suficiente aqui para um relatório de bug real? Ainda não estou descartando uma possível má configuração de nossa parte, mas estou perplexo com a falta de mensagens de erro e tudo mais parece estar funcionando bem. Passei um tempo crescente de dias em solução de problemas e testes, ganhando mais conhecimento sobre o Discourse e seus componentes no processo, então acho que com alguma orientação eu poderia ajudar a descobrir se há algum detalhe de caso extremo acionando esse comportamento estranho. Espero que esteja tudo bem em pingar @zogstrip neste ponto?

Como solução temporária, é possível mover manualmente todos os uploads para o diretório de lixeira e usar os métodos de recuperação de upload para restaurar apenas os arquivos não órfãos de volta aos seus diretórios corretos? Na verdade, tentei fazer isso hoje, mas rake uploads:recover_from_tombstone não restaurou nenhum arquivo. Isso poderia indicar um problema maior com as entradas do banco de dados de uploads?

Olá. Estou enfrentando o mesmo problema ou um semelhante, não consigo descobrir por que os arquivos não podem ser excluídos. Mais alguém ainda está tendo esse problema?
Executei algumas consultas SQL e as referências de upload “travadas” parecem ser todos Rascunhos, mas verifiquei meus e os Rascunhos de outros usuários e não há nenhum. As tabelas de Rascunhos estão vazias.
A limpeza de órfãos está habilitada e as configurações estão definidas para excluir os órfãos o mais rápido possível.
Anexei uma 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)

Isso acontece desde que instalei o fórum. Mesmo quando não havia temas personalizados ou plugins instalados.
Até mesmo o antigo logotipo do fórum que carreguei algumas vezes (o primeiro arquivo carregado de todos) ainda é referenciado como Rascunho e ainda está na pasta de uploads. :man_facepalming:
Teoricamente, eu poderia filtrar todas as referências de upload e filtrar por Rascunhos por target_type, então excluir do banco de dados… e deixar as tarefas do sidekiq cuidarem da limpeza (estou certo?)
mas estou usando uma instância auto-hospedada e sou bem novo no Discourse, então é melhor perguntar aqui…
Isso seria uma solução alternativa, mas ainda há uma questão: por que isso está acontecendo?

Espero que alguém tenha algumas sugestões, meu espaço em disco está crescendo exponencialmente :smile:

1 curtida

Sim, nós ainda estamos tendo esse problema também.

Eu realmente gostaria de resolver isso de alguma forma, nosso fórum recebe muitos uploads, mas apenas uma fração deles precisa ser preservada a longo prazo, então muito espaço em disco está sendo desperdiçado. Quaisquer sugestões para solução de problemas são bem-vindas.

Interessado nisso como uma solução temporária, se for prático. :thinking:

Instalei o fórum há 2 semanas e ele tem este problema desde o início. Parece algum bug.
Você pode executar a mesma consulta SQL e verificar se há muitas referências “Drafts” presas? É fácil de ver, tenho dezenas delas, mas na tabela de rascunhos existem 2, talvez 3 rascunhos reais. Parece que eles não são excluídos após a edição (deixando de ser um rascunho, mas a referência permanece no banco de dados toda vez que uma postagem é editada, por exemplo).

Preciso descobrir como excluir uma entrada de referência do banco de dados e excluir as referências de um arquivo primeiro, depois verificar se a tarefa de limpeza funciona.
Não sei o quão seguro é fazer isso, mas essas inúmeras entradas de Rascunhos parecem erradas para mim.

Posso fornecer logs para a equipe/desenvolvedores, sou apenas novo no Discourse e não sei quais arquivos de log ajudariam.

EDIT:
Estou tentando entender a estrutura do banco de dados, e posso excluir essas entradas de upload sem mais problemas (não quero perder algumas relações importantes do banco de dados). Também não entendo o que exatamente são draft_sequences.
Mas tenho que duplicar meu fórum de produção para uma VM local, só então poderei testar…

Outro tópico relevante, postei lá pois não estava ciente deste tópico.

Acredito que a única maneira de realmente excluir uma imagem de forma automática é editá-la manualmente antes de excluí-la. Mas não tenho certeza se isso funciona. Estou usando configurações idênticas às suas em relação à purga (mas uso armazenamento compatível com S3) e também posso confirmar que as imagens nunca são purgadas se a única postagem contendo essa imagem (várias postagens podem conter a mesma imagem, presumivelmente avatares e banners de usuário também) for excluída.

Eu uso esta solução para pesquisar se uma imagem está sendo usada em postagens adicionais, que foi fornecida por @RGJ

Seria ótimo se isso pudesse ser feito automaticamente. Particularmente devido ao Discourse lidar com imagens de forma inteligente, evitando a criação de arquivos duplicados se muitas postagens usarem a mesma imagem. O lado negativo é que é muito tedioso remover imagens individuais que foram usadas muitas vezes.

Tive alguém que enviou spam com conteúdo que precisava ser removido urgentemente por várias contas antes, e foi muito estressante tentar lidar com isso e garantir que fosse completamente removido (todos os arquivos originais, arquivos otimizados, cache de CDN, postagens, avatares, banners de usuário, etc.).

Fiz esta sugestão de recurso, pois seria muito útil, na minha opinião. Se isso fosse implementado, bem como a purga automática de conteúdo contido em postagens excluídas, acho que todos os casos seriam cobertos e poderiam ser tratados sem acesso SSH.

1 curtida