Rake uploads:migrate_from_s3 falha

Segui os passos aqui, fiz backup de todo o meu site, clonei meu bucket do AWS S3, alterei o nome do bucket nas configurações do Discourse do bucket original para o backup e desmarquei a caixa de seleção “uploads para S3” nas configurações.

Então, finalmente, estou pronto para iniciar a migração do S3… e ela falha. :frowning:

A mensagem de erro

root@ubuntu:/var/www/discourse# rake uploads:migrate_from_s3
Migrando uploads do S3 para armazenamento local para 'default'...
rake aborted!
NoMethodError: undefined method `downcase' for nil:NilClass
/var/www/discourse/app/models/global_setting.rb:107:in `s3_bucket_name'
/var/www/discourse/app/models/site_setting.rb:157:in `absolute_base_url'
/var/www/discourse/lib/tasks/uploads.rake:138:in `migrate_from_s3'
/var/www/discourse/lib/tasks/uploads.rake:118:in `block in migrate_all_from_s3'
/var/www/discourse/vendor/bundle/ruby/2.6.0/gems/rails_multisite-2.2.2/lib/rails_multisite/connection_management.rb:68:in `with_connection'
/var/www/discourse/vendor/bundle/ruby/2.6.0/gems/rails_multisite-2.2.2/lib/rails_multisite/connection_management.rb:78:in `each_connection'
/var/www/discourse/lib/tasks/uploads.rake:118:in `migrate_all_from_s3'
/var/www/discourse/lib/tasks/uploads.rake:93:in `block in <top (required)>'
/usr/local/bin/bundle:23:in `load'
/usr/local/bin/bundle:23:in `<main>'
Tasks: TOP => uploads:migrate_from_s3
(Veja o rastreamento completo executando a tarefa com --trace)

(Aqui está a linha no GitHub onde ocorre a falha — acho que não consegue obter o valor de s3_bucket?)

Outras coisas que tentei

  • Tentei adicionar as credenciais na linha de comando, mas isso não fez diferença. Ou seja:
    DISCOURSE_S3_BUCKET="dn-forum-storage-backup" DISCOURSE_S3_REGION="us-east-1" DISCOURSE_S3_ACCESS_KEY_ID="xxxxxxxxxxxxxxxxxxxx" DISCOURSE_S3_SECRET_ACCESS_KEY="xxxxxxxxxxxxxxxxxxxx" DISCOURSE_S3_CDN_URL="https://dn-forum-storage-backup.s3.us-east-1.amazonaws.com" rake uploads:migrate_from_s3

  • Também tentei alterar o nome do bucket S3 nas minhas configurações de volta para o nome do bucket original, mas sem sorte, mesmo resultado.

  • Também tentei reconstruir o aplicativo. Mesmo resultado.

@vinothkannans, você sabe o que está acontecendo?

Por favor, ajudem, amigos do Discourse!

P.S. pequena nota lateral: rake --tasks não lista esta tarefa nem nenhuma tarefa que comece com uploads, não sei se isso significa algo.

Possível problema relacionado? cc @mcdanlj

@pnoeric sim, isso parece ser exatamente a mesma coisa. Ainda não recebi retorno naquela issue sobre qual é a intenção exata entre SiteSettings e GlobalSettings para o S3, então não tenho mais nenhuma ajuda a oferecer agora além de adicioná-lo ao SiteSettings via configuração (ponto 1 do meu post).

Ei, obrigado pela resposta… Nem tenho certeza do que significa SiteSettings versus GlobalSettings — não sou um desenvolvedor RoR tão experiente e não entendo bem toda a configuração. Estou apenas seguindo as instruções básicas. :wink:

Mas espero que o @vinothkannans também apareça; acho que foi ele quem escreveu o código das tarefas de migração. Ou qualquer outra pessoa da @team que possa saber…

Vamos ficar de olho neste tópico…

s3_bucket está em GlobalSettings, que é definido a partir do arquivo config/discourse.conf, normalmente criado a partir de variáveis de ambiente no arquivo app.yml. SiteSettings são configurações que você altera nas Configurações de Administrador no aplicativo.

Parece que, quando isso foi criado inicialmente, era possível alterar o S3 apenas reconstruindo o aplicativo e, mais recentemente, tornou-se possível preencher os dados nas Configurações de Administrador. Não consigo determinar qual era a intenção de não realizar uma migração completa ao adicionar a configuração do S3 em SiteSettings.

[Edição: Inadvertidamente, inverti os dois ao postar esta resposta pela primeira vez]

Hmm, @mcdanlj, só para confirmar, você ainda não conseguiu descobrir como fazer o migrate_from_s3 funcionar de verdade, certo?

Não tenho problema em editar qualquer configuração, arquivo de baixo nível ou o que for necessário… Só preciso sair do S3 o mais rápido possível, pois está me custando uma fortuna.

Olá @pnoeric e @mcdanlj,

Uma abordagem de depuração pode ser acessar o console do Rails e dar uma olhada nas configurações do site S2?

Por exemplo, em um aplicativo standalone simples do Docker do Discourse (sem configurações extras):

root@localhost:~# docker exec -it app rails c
[1] pry(main)> SiteSetting.s3_upload_bucket
=> ""
[2] pry(main)> SiteSetting.enable_s3_uploads
=> false
[3] pry(main)> 

Comparando as SiteSettings (via console do Rails) com os valores padrão, listados aqui:

Talvez depurar dessa maneira seja útil (na verdade, não tenho certeza, já que não usamos AWS ou S3). Talvez o console do Rails possa ajudar um pouco?

O rake --tasks mostra apenas tarefas que possuem uma descrição. Você pode visualizar todas as tarefas disponíveis usando rake -AT.

Acho que não vai ajudar, pois executei essas tarefas recentemente em um site de teste. Ambas parecem depender de variáveis do S3 definidas no env, no entanto, isso foi há alguns meses e o migrate_from_s3 realmente não funcionou para mim.

Pergunta complicada. Eu configurei o s3_bucket no config/discourse.conf, conforme mencionado no post que você linkou, o que resolveu esse erro específico, como observei lá.

Esse arquivo está dentro do container (./launcher enter app). Note que, para que essa configuração sobreviva ao comando ./launcher rebuild app, você também precisa adicionar DISCOURSE_S3_BUCKET na seção env do seu arquivo containers/app.yml.

O fato de eu ter corrigido o problema é o motivo de ter sido um post de desenvolvimento e não uma solicitação de suporte; eu estava perguntando o que os desenvolvedores consideram a solução correta enquanto continuo a fazer ajustes nesse código.

Tenho cerca de 100 GB de arquivos no S3, então estou avançando com muita cautela. Implementei um limite para os posts a serem analisados, e agora preciso implementar um limite para os posts a serem modificados. Tenho tentado fazer uma coisa de cada vez. O fato de esse código parecer pouco utilizado e eu ter visto esse erro repetidamente me preocupa quanto à deterioração do código (code rot), e não quero estragar acidentalmente todo o meu site por causa de um bug; isso parece ser uma boa maneira de cometer esse erro.

  • Para uploads com o prefixo upload:// (no meu caso, isso significa uploads que não são de vídeo), até agora, parece estar funcionando. Estou processando um de cada vez e revisando o post afetado para garantir que tudo funcione corretamente.

  • Para uploads que não usam a sintaxe upload:// (no meu caso, isso significa uploads de vídeo, pelo que pude constatar), onde há uma referência literal à URL no S3, as URLs estão sendo corrompidas. Não é um bug difícil de corrigir assim que eu descobrir com certeza para o que devo alterá-las, mas ainda não fiz isso. Então, isso provavelmente será um dos PRs que publicarei em breve.

Esse é um projeto de tempo livre para mim, então não há garantias quanto ao prazo.

Aha, obrigado! Vou tentar.

Argh, sem sorte, @neounix @mcdanlj @vinothkannans. Ainda falhando. Mas pelo menos há uma mensagem de erro nova/diferente…

Isso é o que tentei hoje:

  1. Atualizar para a versão mais recente do Discourse, só para ter certeza.

  2. Adicionar meu s3_bucket em config/discourse.conf

  3. ./launcher enter app

  4. Editar containers/app.yml e adicionar a variável DISCOURSE_S3_BUCKET

  5. Tentar rake uploads:migrate_from_s3 e agora falha com uma nova mensagem de erro (antes era o downcase que causava o problema, agora parece ser o start_with?):

/var/www/discourse# rake uploads:migrate_from_s3
Migrando uploads do S3 para armazenamento local para 'default'...
rake aborted!
NoMethodError: método `start_with?' não definido para nil:NilClass
/var/www/discourse/app/models/site_setting.rb:161:in `absolute_base_url'
/var/www/discourse/lib/tasks/uploads.rake:138:in `migrate_from_s3'
/var/www/discourse/lib/tasks/uploads.rake:118:in `block in migrate_all_from_s3'
/var/www/discourse/vendor/bundle/ruby/2.6.0/gems/rails_multisite-2.3.0/lib/rails_multisite/connection_management.rb:68:in `with_connection'
/var/www/discourse/vendor/bundle/ruby/2.6.0/gems/rails_multisite-2.3.0/lib/rails_multisite/connection_management.rb:78:in `each_connection'
/var/www/discourse/lib/tasks/uploads.rake:118:in `migrate_all_from_s3'
/var/www/discourse/lib/tasks/uploads.rake:93:in `block in <main>'
/usr/local/bin/bundle:23:in `load'
/usr/local/bin/bundle:23:in `<main>'
Tasks: TOP => uploads:migrate_from_s3
(Veja o rastreamento completo executando a tarefa com --trace)
  1. Então tentei ./launcher rebuild app

  2. E novamente ./launcher enter app, rake uploads:migrate_from_s3

Exatamente o mesmo problema:

/var/www/discourse# rake uploads:migrate_from_s3
Migrando uploads do S3 para armazenamento local para 'default'...
rake aborted!
NoMethodError: método `start_with?' não definido para nil:NilClass
/var/www/discourse/app/models/site_setting.rb:161:in `absolute_base_url'
/var/www/discourse/lib/tasks/uploads.rake:138:in `migrate_from_s3'
/var/www/discourse/lib/tasks/uploads.rake:118:in `block in migrate_all_from_s3'
/var/www/discourse/vendor/bundle/ruby/2.6.0/gems/rails_multisite-2.3.0/lib/rails_multisite/connection_management.rb:68:in `with_connection'
/var/www/discourse/vendor/bundle/ruby/2.6.0/gems/rails_multisite-2.3.0/lib/rails_multisite/connection_management.rb:78:in `each_connection'
/var/www/discourse/lib/tasks/uploads.rake:118:in `migrate_all_from_s3'
/var/www/discourse/lib/tasks/uploads.rake:93:in `block in <main>'
/usr/local/bin/bundle:23:in `load'
/usr/local/bin/bundle:23:in `<main>'
Tasks: TOP => uploads:migrate_from_s3
(Veja o rastreamento completo executando a tarefa com --trace)

Alguma outra ideia?

Aliás, fazer esse processo é um verdadeiro saco — tenho que agendar com antecedência e anunciar a interrupção do fórum dias antes, no dia da mudança, alterar o site principal para que as pessoas não consigam acessar o fórum e, em seguida, desligar o servidor do fórum no Digital Ocean e criar um snapshot antes de prosseguir. Isso já leva uns 30 minutos. Depois, reinicio e só então posso tentar os passos acima. Estou ME arrependendo muito de ter configurado o Amazon S3 para armazenamento de mídia! Já perdi horas tentando desfazer essa escolha e ainda sem sorte (e ainda com uma conta $$$ grande da Amazon todo mês). Gostaria muito de resolver isso. Como posso ajudar?

Essa linha é:

        if SiteSetting.Upload.s3_region.start_with?("cn-")

Parece que também exige s3_region; não está claro para mim por que não encontrei isso.

Não tenho certeza se entendi sua lógica; minha própria migração de ~100 GB de conteúdo pretendo fazer ao vivo, após um backup normal do site. Mas estou começando aos poucos, por isso tenho trabalhado para limitar a quantidade migrada de uma só vez. Um aviso: o código parece incorreto para traduções de URLs literais, como vi para uploads de vídeo, então se você permitir uploads de vídeo, pode ter um problema ali com o código no estado atual.

Então, talvez eu devesse repetir todas as etapas que fiz acima, mas vou colocar s3_bucket, s3_region, s3_cnd_url, s3_secret_access_key etc. (basicamente, todas as variáveis que tenho) nos arquivos conf e yml? Prefiro fornecer mais do que o (talvez) necessário, apenas para garantir que a coisa realmente funcione.

Vi que alguém da equipe do Discourse sugeriu fazer um backup de todo o site local antes de iniciar essa transição. Isso me obriga a tirar meu servidor Digital Ocean do ar. :frowning:

Certo. Também estou começando aos poucos… toda vez que tento, estou migrando 0 arquivos. :grin:

Felizmente, os membros só podem fazer upload de JPG, GIF e PNG no meu fórum, então deve estar tudo bem.

Fingers crossed.

Backup e snapshot não são a mesma coisa. Um snapshot é a forma mais rudimentar de backup. O console de Admin possui um recurso de backup. Certifique-se de configurá-lo para fazer backup das miniaturas nas configurações primeiro.

Agora que você sabe que não precisa tirar seu site do ar, deve conseguir se tranquilizar. Você pode usar batch_migrate_from_s3 para migrar no máximo um certo número de uploads. No momento, ele limita as postagens consideradas em vez das migrações realizadas — um bug que preciso resolver em um futuro PR. Mas também preciso resolver o bug de upload de vídeo, e gostaria de considerar imprimir um feedback, pois um dos pontos do limite é poder confirmar nas postagens afetadas que a migração foi bem-sucedida.

É provável que eu faça tudo isso ao longo dos próximos 1 a 2 meses. Então, se quiser esperar até lá, pode valer a pena pagar mais alguns meses de S3. A decisão é sua, e não estou fazendo promessas, apenas declarando minha intenção.

@pnoeric, já que você está preocupado com o tempo de atividade do site, achei que deveria compartilhar com você o que aprendi até agora.

Fiz minha migração ao vivo, como mencionei. Se eu não limitar a taxa da migração, as filas que realizam tarefas como notificar usuários sobre a atividade uns dos outros ficam congestionadas e a experiência do usuário no site é prejudicada.

Migrei cerca de 500 posts com vídeos e aproximadamente 30 mil posts com imagens, o que levou cerca de duas semanas para ser concluído.

Se quiser testar o código que usei, ele está atualmente em:

Você pode baixá-lo e copiá-lo para o seu aplicativo, substituindo o conteúdo atual de lib/tasks/uploads.rake.

Com esse código, você pode fazer algo como:

bin/rake uploads:batch_migrate_from_s3[100,1000]

Isso considerará apenas 1000 posts com uploads no total e migrará arquivos de no máximo 100 posts antes de parar; sempre que o script modificar realmente um post após migrar seus uploads, ele aguardará até que a fila esteja vazia antes de iniciar o próximo.

Se você copiar o arquivo, quebrará futuras atualizações do site até que a alteração seja revertida. A maneira mais fácil de desfazer isso, depois de satisfeito, é simplesmente executar ./launcher rebuild app (embora, como desenvolvedor, eu use git checkout HEAD lib/tasks/uploads.rake para reverter minhas alterações…).

Notei que, pelo menos com os espaços do Digital Ocean, às vezes preciso tentar algumas vezes antes que a migração seja bem-sucedida. O script, como está atualmente, não avisa quando isso acontece, e você precisa apenas continuar executando-o e aguardando para ver. Tenho um PR aguardando revisão que imprime os erros nesses casos, para que você pelo menos saiba que algo deu errado.

Adicionei um simples loop de repetição curto, bem como a mensagem de erro, e parece que o loop de repetição resolve o problema. Além disso, a validação contra as regras atuais estava sendo feita no conteúdo bruto de posts antigos, o que poderia quebrar a migração e deixar silenciosamente posts que precisavam ser reprocessados; isso também foi corrigido. Você definitivamente não deve fazer uma migração sem obter pelo menos a correção de validação, que é um dos commits do meu PR atualmente em revisão.

Concluí minha migração, até onde sei. Meu PR contém todo o código que usei para completar a migração. Ele ainda não foi revisado. Sugiro acompanhar em Migrate_from_s3 problems se desejar.

Obrigado! Vou dar uma chance a isso nos próximos dias.

Acabei de adicionar uma nota naquele post sobre um bug que ainda resta, descoberto hoje: as fotos de perfil sumiram para alguns usuários, e não sei o motivo. Deu de ombros e temos pedido aos usuários afetados que restaurem, com desculpas pelo problema.

Com certeza fiz backups frequentes durante esse processo! :smiling_face:

Boa sorte!

Sério, isso pode me deixar ainda mais maluco? :crazy_face:

Foi o que fiz:

  1. Copiei o novo código do lib/tasks/upload.rake para o meu Discourse
  2. Adicionei TODAS as minhas variáveis Amazon s3_ ao config/discourse.conf
  3. Também as adicionei ao app.yml (não tenho certeza se isso faz alguma diferença, mas por que não)
  4. Executei este comando e obtive…
root@:/var/www/discourse/config# rake uploads:batch_migrate_from_s3[100,1000]
You must disable S3 uploads before running that task.

E confirmei:

Tudo bem. Então, editei o arquivo uploads.rake e removi apenas essa verificação.

Agora obtenho:

root@:/var/www/discourse/lib/tasks# rake uploads:batch_migrate_from_s3[100,1000]
Migrating uploads from S3 to local storage for 'default'...
Migrating up to 100 of 1000 posts...
... (muita saída aqui) ...
Modified 91/100: 28795: 28486/1 - https://example.com/t/topic-title-here/28486/1
... (muita saída aqui) ...

Então parecia que estava funcionando! Uhuu!

Depois que ele processou aquele primeiro lote de 100, verifiquei o sidekiq e vi que meu post de teste estava na fila, então esperei que terminasse…

…depois voltei e verifiquei… e aquele post ainda está buscando sua imagem no Amazon S3. :frowning: Tentei “Reconstruir HTML” no post e isso não mudou nada.

Então, tentei todo o processo novamente, desde o rake até o final, e obtive os mesmos resultados — os mesmos 100 posts foram processados, as mesmas coisas enfileiradas no sidekiq e, depois de deixar rodar, a imagem daquele post de teste ainda vem do S3.

Hmmm, não tenho certeza do que tentar a seguir. :man_shrugging:t2:

@mcdanlj, agradeço qualquer sugestão ou conselho que você possa ter :wink:

Isso é exatamente o que eu esperaria se você removesse essa verificação. Não tenho certeza do motivo pelo qual você decidiu removê-la. É intencional. Desative os uploads para o S3 antes de iniciar a migração.

Eles estavam desligados — completamente desligados. (A imagem da caixa de seleção no meu post está com a configuração correta, certo?) Eu até os ativei e desativei novamente. Não funcionou.