Ajuda para restaurar - sistema travou à meia-noite

Okay this was bound to happen, things were just too good for too long. Years of running on cruise control, the system would automatically update itself and I would update Discourse every few weeks. At midnight last night, Amazon showed the system was unresponsive, discourse was down and the CPU was pegged at 100% until it ran out of AWS CPU resources. Couldn’t login to the system, the one time after several reboots I was able to login momentarily, I saw this in htoptaking up a lot of CPU

snap lxd activate

If anyone has seen this can can throw some light as to why this may happened by itself, it would be much appreciated for future reference.

Coming the pressing issue at hand, I proceeded to rebuild a new server on AWS using Ubuntu 20LTS, Discourse setup was exceedingly easy. I had a copy of the app.yml file which I used to recreate the discourse forum. The old server was using S3 for the backups AND for the content (images etc).

After creating the server, I downloaded the latest discourse backup file from S3, manually uploaded it to the discourse server and hit the Restore buttons. After a few minutes I get this error.

[2022-06-09 09:01:56] ALTER TABLE
[2022-06-09 09:01:56] ALTER TABLE
[2022-06-09 09:01:56] Migrating the database...
[2022-06-09 09:02:11] == 20220308201942 CreateUploadReferences: migrating ===========================
-- create_table(:upload_references, {})
   -> 0.0486s
-- add_index(:upload_references, [:upload_id, :target_type, :target_id], {:unique=>true, :name=>"index_upload_references_on_upload_and_target"})
   -> 0.0030s
== 20220308201942 CreateUploadReferences: migrated (0.0580s) ==================

== 20220309132719 CopyPostUploadsToUploadReferences: migrating ================
-- execute("INSERT INTO upload_references(upload_id, target_type, target_id, created_at, updated_at)\nSELECT post_uploads.upload_id, 'Post', post_uploads.post_id, uploads.created_at, uploads.updated_at\nFROM post_uploads\nJOIN uploads ON uploads.id = post_uploads.upload_id\nON CONFLICT DO NOTHING\n")
   -> 0.0595s
== 20220309132719 CopyPostUploadsToUploadReferences: migrated (0.0602s) =======

== 20220309132720 CopyPostUploadsToUploadReferencesForSync: migrating =========
-- execute("INSERT INTO upload_references(upload_id, target_type, target_id, created_at, updated_at)\nSELECT upload_id, 'Post', post_id, NOW(), NOW()\nFROM post_uploads\nON CONFLICT DO NOTHING\n")
   -> 0.0076s
== 20220309132720 CopyPostUploadsToUploadReferencesForSync: migrated (0.0080s) 

== 20220330160747 CopySiteSettingsUploadsToUploadReferences: migrating ========
-- execute("WITH site_settings_uploads AS (\n  SELECT id, unnest(string_to_array(value, '|'))::integer upload_id\n  FROM site_settings\n  WHERE data_type = 17\n  UNION\n  SELECT id, value::integer\n  FROM site_settings\n  WHERE data_type = 18 AND value != ''\n)\nINSERT INTO upload_references(upload_id, target_type, target_id, created_at, updated_at)\nSELECT site_settings_uploads.upload_id, 'SiteSetting', site_settings_uploads.id, uploads.created_at, uploads.updated_at\nFROM site_settings_uploads\nJOIN uploads ON uploads.id = site_settings_uploads.upload_id\nON CONFLICT DO NOTHING\n")
   -> 0.0034s
== 20220330160747 CopySiteSettingsUploadsToUploadReferences: migrated (0.0038s) 

== 20220330160751 CopyBadgesUploadsToUploadReferences: migrating ==============
-- execute("INSERT INTO upload_references(upload_id, target_type, target_id, created_at, updated_at)\nSELECT badges.image_upload_id, 'Badge', badges.id, uploads.created_at, uploads.updated_at\nFROM badges\nJOIN uploads ON uploads.id = badges.image_upload_id\nWHERE badges.image_upload_id IS NOT NULL\nON CONFLICT DO NOTHING\n")
   -> 0.0006s
== 20220330160751 CopyBadgesUploadsToUploadReferences: migrated (0.0010s) =====

== 20220330160754 CopyGroupsUploadsToUploadReferences: migrating ==============
-- execute("INSERT INTO upload_references(upload_id, target_type, target_id, created_at, updated_at)\nSELECT groups.flair_upload_id, 'Group', groups.id, uploads.created_at, uploads.updated_at\nFROM groups\nJOIN uploads ON uploads.id = groups.flair_upload_id\nWHERE groups.flair_upload_id IS NOT NULL\nON CONFLICT DO NOTHING\n")
   -> 0.0050s
== 20220330160754 CopyGroupsUploadsToUploadReferences: migrated (0.0055s) =====

== 20220330160757 CopyUserExportsUploadsToUploadReferences: migrating =========
-- execute("INSERT INTO upload_references(upload_id, target_type, target_id, created_at, updated_at)\nSELECT user_exports.upload_id, 'UserExport', user_exports.id, uploads.created_at, uploads.updated_at\nFROM user_exports\nJOIN uploads ON uploads.id = user_exports.upload_id\nON CONFLICT DO NOTHING\n")
   -> 0.0013s
== 20220330160757 CopyUserExportsUploadsToUploadReferences: migrated (0.0041s) 

== 20220330164740 CopyThemeFieldsUploadsToUploadReferences: migrating =========
-- execute("INSERT INTO upload_references(upload_id, target_type, target_id, created_at, updated_at)\nSELECT theme_fields.upload_id, 'ThemeField', theme_fields.id, uploads.created_at, uploads.updated_at\nFROM theme_fields\nJOIN uploads ON uploads.id = theme_fields.upload_id\nWHERE type_id = 2\nON CONFLICT DO NOTHING\n")
   -> 0.0006s
== 20220330164740 CopyThemeFieldsUploadsToUploadReferences: migrated (0.0010s) 

== 20220404195635 CopyCategoriesUploadsToUploadReferences: migrating ==========
-- execute("INSERT INTO upload_references(upload_id, target_type, target_id, created_at, updated_at)\nSELECT categories.uploaded_logo_id, 'Category', categories.id, uploads.created_at, uploads.updated_at\nFROM categories\nJOIN uploads ON uploads.id = categories.uploaded_logo_id\nWHERE categories.uploaded_logo_id IS NOT NULL\nON CONFLICT DO NOTHING\n")
   -> 0.0095s
-- execute("INSERT INTO upload_references(upload_id, target_type, target_id, created_at, updated_at)\nSELECT categories.uploaded_background_id, 'Category', categories.id, uploads.created_at, uploads.updated_at\nFROM categories\nJOIN uploads ON uploads.id = categories.uploaded_background_id\nWHERE categories.uploaded_background_id IS NOT NULL\nON CONFLICT DO NOTHING\n")
   -> 0.0004s
== 20220404195635 CopyCategoriesUploadsToUploadReferences: migrated (0.0103s) =

== 20220404201949 CopyCustomEmojisUploadsToUploadReferences: migrating ========
-- execute("INSERT INTO upload_references(upload_id, target_type, target_id, created_at, updated_at)\nSELECT custom_emojis.upload_id, 'CustomEmoji', custom_emojis.id, uploads.created_at, uploads.updated_at\nFROM custom_emojis\nJOIN uploads ON uploads.id = custom_emojis.upload_id\nWHERE custom_emojis.upload_id IS NOT NULL\nON CONFLICT DO NOTHING\n")
   -> 0.0032s
== 20220404201949 CopyCustomEmojisUploadsToUploadReferences: migrated (0.0036s) 

== 20220404203356 CopyUserProfilesUploadsToUploadReferences: migrating ========
-- execute("INSERT INTO upload_references(upload_id, target_type, target_id, created_at, updated_at)\nSELECT user_profiles.profile_background_upload_id, 'UserProfile', user_profiles.user_id, uploads.created_at, uploads.updated_at\nFROM user_profiles\nJOIN uploads ON uploads.id = user_profiles.profile_background_upload_id\nWHERE user_profiles.profile_background_upload_id IS NOT NULL\nON CONFLICT DO NOTHING\n")
   -> 0.0017s
-- execute("INSERT INTO upload_references(upload_id, target_type, target_id, created_at, updated_at)\nSELECT user_profiles.card_background_upload_id, 'UserProfile', user_profiles.user_id, uploads.created_at, uploads.updated_at\nFROM user_profiles\nJOIN uploads ON uploads.id = user_profiles.card_background_upload_id\nWHERE user_profiles.card_background_upload_id IS NOT NULL\nON CONFLICT DO NOTHING\n")
   -> 0.0011s
== 20220404203356 CopyUserProfilesUploadsToUploadReferences: migrated (0.0033s) 

== 20220404204439 CopyUserAvatarsUploadsToUploadReferences: migrating =========
-- execute("INSERT INTO upload_references(upload_id, target_type, target_id, created_at, updated_at)\nSELECT user_avatars.custom_upload_id, 'UserAvatar', user_avatars.id, uploads.created_at, uploads.updated_at\nFROM user_avatars\nJOIN uploads ON uploads.id = user_avatars.custom_upload_id\nWHERE user_avatars.custom_upload_id IS NOT NULL\nON CONFLICT DO NOTHING\n")
   -> 0.0200s
-- execute("INSERT INTO upload_references(upload_id, target_type, target_id, created_at, updated_at)\nSELECT user_avatars.gravatar_upload_id, 'UserAvatar', user_avatars.id, uploads.created_at, uploads.updated_at\nFROM user_avatars\nJOIN uploads ON uploads.id = user_avatars.gravatar_upload_id\nWHERE user_avatars.gravatar_upload_id IS NOT NULL\nON CONFLICT DO NOTHING\n")
   -> 0.0069s
== 20220404204439 CopyUserAvatarsUploadsToUploadReferences: migrated (0.0276s) 

== 20220404212716 CopyThemeSettingsUploadsToUploadReferences: migrating =======
-- execute("INSERT INTO upload_references(upload_id, target_type, target_id, created_at, updated_at)\nSELECT theme_settings.value::int, 'ThemeSetting', theme_settings.id, uploads.created_at, uploads.updated_at\nFROM theme_settings\nJOIN uploads ON uploads.id = theme_settings.value::int\nWHERE data_type = 6 AND theme_settings.value IS NOT NULL AND theme_settings.value != ''\nON CONFLICT DO NOTHING\n")
   -> 0.0025s
== 20220404212716 CopyThemeSettingsUploadsToUploadReferences: migrated (0.0030s) 

== 20220526203356 CopyUserUploadsToUploadReferences: migrating ================
-- execute("INSERT INTO upload_references(upload_id, target_type, target_id, created_at, updated_at)\nSELECT users.uploaded_avatar_id, 'User', users.id, uploads.created_at, uploads.updated_at\nFROM users\nJOIN uploads ON uploads.id = users.uploaded_avatar_id\nWHERE users.uploaded_avatar_id IS NOT NULL\nON CONFLICT DO NOTHING\n")
   -> 0.0227s
== 20220526203356 CopyUserUploadsToUploadReferences: migrated (0.0234s) =======


[2022-06-09 09:02:11] Reconnecting to the database...
[2022-06-09 09:02:12] Reloading site settings...
[2022-06-09 09:02:12] Disabling outgoing emails for non-staff users...
[2022-06-09 09:02:14] Disabling readonly mode...
[2022-06-09 09:02:14] Clearing category cache...
[2022-06-09 09:02:14] Reloading translations...
[2022-06-09 09:02:14] Remapping uploads...
[2022-06-09 09:02:14] Restoring uploads, this may take a while...
[2022-06-09 09:03:05] EXCEPTION: 509 of 1823 uploads are not migrated to S3. S3 migration failed for db 'default'.
[2022-06-09 09:03:05] /var/www/discourse/lib/file_store/to_s3_migration.rb:132:in `raise_or_log'
/var/www/discourse/lib/file_store/to_s3_migration.rb:79:in `migration_successful?'
/var/www/discourse/lib/file_store/to_s3_migration.rb:373:in `migrate_to_s3'
/var/www/discourse/lib/file_store/to_s3_migration.rb:66:in `migrate'
/var/www/discourse/lib/file_store/s3_store.rb:328:in `copy_from'
/var/www/discourse/lib/backup_restore/uploads_restorer.rb:62:in `restore_uploads'
/var/www/discourse/lib/backup_restore/uploads_restorer.rb:44:in `restore'
/var/www/discourse/lib/backup_restore/restorer.rb:61:in `run'
/var/www/discourse/script/spawn_backup_restore.rb:23:in `restore'
/var/www/discourse/script/spawn_backup_restore.rb:36:in `block in <main>'
/var/www/discourse/script/spawn_backup_restore.rb:4:in `fork'
/var/www/discourse/script/spawn_backup_restore.rb:4:in `<main>'

Can anyone advise on what’s the problem and how I can restore the server from the Amazon S3 server backups?

Olá,
após recriar o novo servidor a partir do app.yml, você teve acesso aos backups na seção https://your.domain/admin/backups?

Não, depois de recriar a partir do app.yml, ele me deu uma nova configuração limpa sem nada. Baixei o último backup do S3 e fiz o upload manualmente para o Discourse localmente e cliquei em restaurar.

Ele começa a restaurar, vejo todas as configurações (incluindo o S3, as credenciais, tudo da página de Configurações) voltarem, vejo todas as categorias aparecerem e as postagens aparecerem e tudo. Então, de repente, após alguns minutos, recebo uma mensagem de logout e todas as categorias e tópicos desaparecem e os logs mostram aquele erro (Parece que ele reverte).

:thinking: então a configuração do s3 não está no app.yml (como descrito aqui Configure an S3 compatible object storage provider for uploads )? Mas configurado como em Set up file and image uploads to S3

1 curtida

Não, eu não vejo isso no meu app.yml

Todas as configurações do S3 foram definidas nas páginas Admin → Configurações e funcionou bem por um ano até que precisei restaurá-lo quando o servidor caiu ontem à noite.

Correto, é isso que usei para configurar os backups e uploads do S3.

Acho que você tentaria editar o app.yml com suas configurações e, a partir daí, acredito (espero?) que você verá seus backups na seção de administração e poderá restaurar a partir daí, sem a importação manual e os uploads, que você não deveria ter que restaurar, mas parecem estar incluídos nos backups. Não sei por que está falhando, no entanto…

1 curtida

Acho que isso pode ser porque seu backup contém uma mistura de uploads S3 e locais. Receio que não seja minha área de especialização, mas há alguma discussão e uma solução neste tópico que permite contornar a falha. No entanto, era para um número muito menor de erros, então você pode querer levar isso em consideração:

2 curtidas

Obrigado, meu site travou infelizmente, então só me restam os uploads e backups do S3. Suponho que não haja como migrar os arquivos locais restantes para o S3 agora.

Então, estou me perguntando quais são minhas opções agora? Existe uma maneira de restaurar a partir de backups do S3 e ignorar os arquivos locais? Encontrei uma maneira de fazer com que ele ignore o upload do S3, mas então praticamente todas as postagens têm links/imagens quebrados (90%+ provavelmente está no S3 porque configurei o upload do S3 há muitos, muitos anos).

Então, uma atualização para quem pode estar enfrentando o mesmo problema (basicamente, não consigo restaurar de um backup e o servidor travou devido a uma atualização de sistema com falha).

Pelo que entendi, a causa raiz do problema é que existem uploads locais E uploads S3, então quando a ferramenta de restauração tenta restaurar, ela falha porque não sabe como lidar com restaurações locais e S3 ao mesmo tempo (talvez seja hora do Discourse reavaliar backups/restaurações).

Graças a @RGJ por esta dica, ele sugeriu forçar o Discourse a ignorar o upload S3 durante a restauração:

  1. Adicione uma linha ao seu app.yml DISCOURSE_ENABLE_S3_UPLOADS=false
  2. Reconstrua o Discourse ./launcher rebuild app
  3. Tente uma restauração (seja na página de Backup da GUI ou usando a CLI)
  4. Em seguida, após a restauração, remova essa linha do app.yml e reconstrua mais uma vez

Embora isso tenha funcionado, é importante notar que o fórum estava muito quebrado, as categorias, configurações e postagens foram restauradas, no entanto, todas as imagens, links, documentos incorporados, etc., estavam quebrados e com erros.

A solução de último recurso:
Consegui salvar o servidor antigo e extraí o diretório /var/discourse (tar/gz) e o copiei para o novo servidor e executei ./launcher rebuild app. Isso restaurou completamente a operação do fórum, no entanto, o problema fundamental ainda permanece - os backups NÃO funcionarão porque eles têm uma mistura de uploads locais e S3.

Portanto, realmente preciso de alguns conselhos sobre a melhor maneira de corrigir esse problema de uma vez por todas. É melhor/mais fácil mover todos os uploads do local para S3 ou do S3 para o local e como fazer isso? O objetivo principal de um backup é ajudar em situações como esta, mas ele falhou comigo, então preciso que você o resolva.

1 curtida

Se você configurar conforme descrito em Usando Armazenamento de Objetos para Uploads (S3 e Clones), você poderá executar

 rake uploads:migrate_to_s3

Se você quiser parar de usar o s3, então você pode entrar no console do rails e definir

  SiteSetting.include_s3_uploads_in_backups=true

Em seguida, faça um backup, certifique-se de que não tenha o s3 configurado em seu app.yml e restaure o backup. Acho que isso restaurará os backups para o local.

Mas, em qualquer um dos casos, eu ainda recomendaria definir suas chaves e bucket de backup em variáveis de ambiente em seu arquivo app.yml e, em seguida, verificar se você pode restaurá-lo para um novo site.

2 curtidas

Ok, acho que me confundi um pouco aqui.

Estou pensando que o ideal seria ter todos os uploads locais e salvar os backups (zips) no S3. Dessa forma, o backup estará disponível no S3 caso algo aconteça com o servidor, mas o backup em si é autônomo, sem dependências, então deve ser fácil restaurá-lo em um novo servidor.

Então, se entendi corretamente, devo seguir estas instruções:

Se você quiser parar de usar o s3, pode entrar no console do rails e definir
  SiteSetting.include_s3_uploads_in_backups=true
Em seguida, faça um backup, certifique-se de que não tem o s3 configurado em seu app.yml e restaure o backup. Acho que isso restaurará os backups para o local.

e então

  1. desative a opção habilitar upload para S3 em Admin → Configurações → Arquivos
  2. habilite a opção de backup para S3 na página Admin → Configurações → Backups

Está correto?

Esta é a parte que me confundiu, por que eu gostaria de colocar a configuração do S3 no arquivo app.yml?

Para que você tenha acesso aos seus backups por meio de uma restauração de linha de comando antes de restaurar seu backup. Caso contrário, você terá que configurar uma conta de administrador e, em seguida, configurar o S3 e, em seguida, restaurar. Da mesma forma, quaisquer configurações que você coloque em seu banco de dados são substituídas ao restaurar o banco de dados.

Eu acho que a melhor prática é configurar o S3 apenas através de variáveis de ambiente no arquivo app.yml. Provavelmente faria sentido torná-los configurações ocultas, senão para centenas de pessoas que ficariam surpresas que eles desapareceram.

1 curtida

Porque você terá problemas para restaurar caso contrário.

2 curtidas

Como restaurar um backup do S3 usando a linha de comando? De acordo com as instruções aqui: Restore a backup from the command line
Diz que você pode soltar o arquivo de backup na pasta /var/discourse/shared/standalone/backups/default e, em seguida, iniciar uma restauração a partir da CLI. Foi o que fiz com sua sugestão anteriormente (o que acabou levando a links quebrados, infelizmente), mas isso funciona.

Como restaurar diretamente do S3 usando a CLI?

cd /var/discourse
./launcher enter app
discourse restore

Ele imprimirá os backups disponíveis que você pode então copiar/colar o que deseja restaurar.

2 curtidas

Obrigado, então ele lerá os backups do S3 e os listará como uma opção.

Jay, para dar seguimento a uma sugestão que você fez sobre mover ativos para o local:

Acho que você pode definir uma configuração oculta include_s3_uploads_in_backups como true e, em seguida, fazer um backup e restaurá-lo quando o S3 for desativado para parar de usar o S3.

Ter backups do S3 configurados em app.yml significa que você pode fazer uma restauração pela linha de comando apenas com o arquivo app.yml (após clonar o discourse e instalar o docker).

Para o primeiro passo, eu precisaria fazer backup dos buckets do S3 ou esta é uma operação segura para o bucket?

Bem, pelo menos descobri por que meu servidor travou ontem à noite (e novamente hoje após uma reconstrução completa :frowning: , veja este tópico para detalhes: Ubuntu 20.04 kernel update with docker causing a crash on EC2 and Lightsail

2 curtidas

Para colocá-lo em funcionamento a partir de um backup, tive que

  1. desabilitar Configurações → Arquivoshabilitar uploads s3
  2. Configurações → Backupslocalização do backupS3
  3. habilitar Configurações → Backupsbackup com uploads

Então fiz um backup e consegui restaurá-lo com sucesso. No entanto, uma coisa quebrou, todos os anexos (arquivos) agora têm links inválidos. As imagens estão todas boas, mas os links de anexos como https://domain.com/uploads/short-url/phu1HOLvkE8LWpkKYfnMPSWsvHh.zip agora me dão um erro

Ops! Essa página não existe ou é privada.

Existe alguma maneira de corrigir esses links de URL curta?

Você pode tentar fazer uma reconstrução de HTML (também conhecida como rebake) em um desses tópicos para ver se isso o corrige.

Obrigado. Existe algum guia sobre como emitir o comando para assar tópicos específicos?