Ayuda para restaurar - el sistema se colgó a medianoche

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?

Hola,
después de recrear el nuevo servidor desde el app.yml, ¿tuviste acceso a las copias de seguridad en la sección https://your.domain/admin/backups?

No, después de recrearlo desde app.yml, me dio una nueva configuración limpia sin nada. Descargué la última copia de seguridad de S3 y la subí manualmente a Discourse localmente y presioné restaurar.

Comienza a restaurarla, veo todas las configuraciones (incluyendo S3, las credenciales, todo desde la página de Configuración) que vuelven, veo que todas las categorías aparecen y las publicaciones aparecen y todo. Luego, de repente, después de unos minutos, recibo un mensaje de cierre de sesión y todas las categorías y temas desaparecen y los registros muestran ese error (parece que se revierte).

:thinking: ¿entonces la configuración de s3 no está en app.yml (como se describe aquí Configure an S3 compatible object storage provider for uploads )? ¿Sino configurada como en Set up file and image uploads to S3?

1 me gusta

No, no veo esto en mi app.yml

Toda la configuración de S3 se definió en las páginas de Administrador → Configuración y funcionó bien durante un año hasta que necesité restaurarla cuando el servidor se cayó anoche.

Correcto, esto es lo que usé para configurar las copias de seguridad y las subidas de S3.

Creo que intentaría editar el archivo app.yml con tu configuración y, a partir de ahí, creo (¿espero?) que deberías ver tus copias de seguridad en la sección de administración y restaurar desde allí, sin la importación manual y las cargas, que no deberías tener que restaurar, pero que parecen estar incluidas en las copias de seguridad. No sé por qué está fallando…

1 me gusta

Creo que esto puede deberse a que tu copia de seguridad contiene una mezcla de cargas de S3 y locales. Me temo que no es mi área de especialización, pero hay alguna discusión y una solución en este tema que te permite evitar el fallo. Sin embargo, era para un número mucho menor de errores, por lo que es posible que quieras tener eso en cuenta:

2 Me gusta

Lamentablemente, mi sitio se ha caído, así que solo me quedan las cargas y copias de seguridad de S3. Supongo que no hay forma de que pueda migrar los archivos locales restantes a S3 ahora.

Así que me pregunto cuáles son mis opciones ahora. ¿Hay alguna forma de restaurar desde las copias de seguridad de S3 e ignorar los archivos locales? Encontré una manera de que ignore la carga de S3, pero entonces casi todas las publicaciones tienen enlaces/imágenes rotas (probablemente el 90% está en S3 porque configuré la carga de S3 hace muchos, muchos años).

Así que una actualización para quienes puedan estar teniendo el mismo problema (básicamente, no puedo restaurar desde una copia de seguridad y el servidor se bloqueó debido a una actualización fallida del sistema).

Por lo que entiendo, la causa raíz del problema es que hay cargas locales Y cargas S3, por lo que cuando la herramienta de restauración intenta restaurar, falla porque no sabe cómo manejar restauraciones locales y S3 al mismo tiempo (quizás sea hora de que Discourse revise las copias de seguridad/restauraciones).

Gracias a @RGJ por este consejo, sugirió forzar a Discourse a ignorar la carga S3 mientras restaura:

  1. Agrega una línea a tu app.yml DISCOURSE_ENABLE_S3_UPLOADS=false
  2. Reconstruye Discourse ./launcher rebuild app
  3. Intenta una restauración (ya sea desde la página de Copias de seguridad de la GUI o usando la CLI)
  4. Luego, después de restaurar, elimina esa línea de app.yml y reconstruye una vez más.

Si bien esto funcionó, hay que tener en cuenta que el foro estaba muy dañado, las categorías, la configuración y las publicaciones se restauraron, sin embargo, todas las imágenes, enlaces, documentos incrustados, etc. estaban rotos y fallaron.

La solución de último recurso:
Logré rescatar el servidor antiguo y extraje el directorio /var/discourse (tar/gz) y lo copié en el nuevo servidor e hice un ./launcher rebuild app. Esto restauró completamente el funcionamiento del foro, sin embargo, el problema fundamental sigue ahí: las copias de seguridad NO funcionarán porque tienen una mezcla de cargas locales y S3.

Así que realmente necesito algún consejo sobre la mejor manera de solucionar este problema de una vez por todas. ¿Es mejor/más fácil mover todas las cargas de local a S3 o de S3 a local y cómo se hace? El propósito de una copia de seguridad es ayudar en situaciones como esta, pero me ha fallado, así que necesito que lo arregles.

1 me gusta

Si lo configuras como se describe en Usar almacenamiento de objetos para cargas (S3 y clones), deberías poder

 rake uploads:migrate_to_s3

Si quieres dejar de usar s3, puedes entrar en la consola de rails y establecer

  SiteSetting.include_s3_uploads_in_backups=true

Luego haz una copia de seguridad, asegúrate de que no tienes s3 configurado en tu app.yml y restaura la copia de seguridad. Creo que esto restaurará las copias de seguridad a local.

Pero en cualquier caso, te recomiendo que configures tus claves y el bucket de copias de seguridad en variables de entorno en tu archivo app.yml y luego compruebes que puedes restaurarlo en un nuevo sitio.

2 Me gusta

Okay, creo que me he confundido un poco aquí.

Creo que lo ideal sería tener todas las subidas locales y guardar las copias de seguridad (zips) en S3. De esta manera, la copia de seguridad estará disponible en S3 si algo le sucede al servidor, pero la copia de seguridad en sí misma es autónoma y no tiene dependencias, por lo que debería ser fácil restaurarla en un nuevo servidor.

Entonces, si entendí correctamente, debería seguir estas instrucciones:

Si quieres dejar de usar s3, puedes entrar en la consola de rails y establecer
  SiteSetting.include_s3_uploads_in_backups=true
Luego haz una copia de seguridad, asegúrate de no tener s3 configurado en tu app.yml y restaura la copia de seguridad. Creo que esto restaurará las copias de seguridad a local.

y luego

  1. deshabilitar la opción enable upload to S3 en Admin → Settings → Files
  2. habilitar la opción de copia de seguridad a S3 en la página Admin → Settings → Backups

¿Es eso correcto?

Esta es la parte que me confundió, ¿por qué querría poner la configuración de S3 en el archivo app.yml?

Para que tenga acceso a sus copias de seguridad a través de una restauración de línea de comandos antes de restaurar su copia de seguridad. De lo contrario, tiene que configurar una cuenta de administrador y luego configurar S3 y luego restaurar. Del mismo modo, cualquier configuración que ponga en su base de datos se sobrescribe cuando restaura la base de datos.

Creo que la mejor práctica es configurar S3 solo a través de variables de entorno en el archivo app.yml. Probablemente tendría sentido hacer que fueran configuraciones ocultas, si no fuera por los cientos de personas que se sorprenderían de que hubieran desaparecido.

1 me gusta

Porque de lo contrario tendrá problemas para restaurar.

2 Me gusta

¿Cómo se restauraría una copia de seguridad de S3 usando la línea de comandos? Según las instrucciones aquí: Restore a backup from the command line
Dice que puedes soltar el archivo de copia de seguridad en la carpeta /var/discourse/shared/standalone/backups/default y luego iniciar una restauración desde la CLI. Esto es lo que había hecho con tu sugerencia anteriormente (que finalmente resultó en enlaces rotos, desafortunadamente), pero eso sí funciona.

¿Cómo se restaura directamente desde S3 usando la CLI?

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

Imprimirá las copias de seguridad disponibles que luego podrá copiar/pegar para realizar la restauración.

2 Me gusta

Gracias, así que leerá las copias de seguridad de S3 y las enumerará como una opción.

Jay, para dar seguimiento a una sugerencia que hiciste sobre mover los activos a local:

Creo que puedes establecer una configuración oculta include_s3_uploads_in_backups en true y luego hacer una copia de seguridad y restaurarla cuando S3 esté desactivado para dejar de usar S3.

Tener copias de seguridad de S3 con ellas configuradas en app.yml significa que puedes hacer una restauración desde la línea de comandos con solo el archivo app.yml (después de clonar discourse e instalar docker).

Para el primer paso, ¿necesitaría hacer una copia de seguridad de los buckets de S3 o es una operación segura para los buckets?

Bueno, al menos descubrí por qué mi servidor se bloqueó anoche (y de nuevo hoy después de una reconstrucción completa :frowning: , vea este tema para más detalles: Ubuntu 20.04 kernel update with docker causing a crash on EC2 and Lightsail

2 Me gusta

Para ponerlo en marcha desde una copia de seguridad, tuve que

  1. Desactivar Configuración → Archivoshabilitar cargas s3
  2. Configuración → Copias de seguridadubicación de copia de seguridadS3
  3. Habilitar Configuración → Copias de seguridadcopia de seguridad con cargas

Luego tomé una copia de seguridad y pude restaurarla con éxito. Sin embargo, una cosa se rompió, todos los archivos adjuntos (archivos) ahora tienen enlaces no válidos. Las imágenes están todas bien, pero los enlaces de los archivos adjuntos como https://domain.com/uploads/short-url/phu1HOLvkE8LWpkKYfnMPSWsvHh.zip ahora me dan un error

¡Uy! Esa página no existe o es privada.

¿Hay alguna forma de arreglar estos enlaces de url corta?

Es posible que intentes realizar una reconstrucción de HTML (también conocida como “rebake”) en uno de esos temas para ver si lo soluciona.

Gracias. ¿Hay alguna guía en alguna parte sobre cómo emitir el comando para hornear temas específicos?