Rake uploads:migrate_from_s3 échoue

J’ai suivi les étapes ici, sauvegardé l’intégralité de mon site, cloné mon bucket AWS S3, modifié le nom du bucket dans les paramètres de Discourse pour passer du bucket original au backup, et décoché la case « uploads to S3 » dans les paramètres.

Je suis donc enfin prêt à démarrer la migration depuis S3… et elle échoue. :frowning:

Le message d’erreur

root@ubuntu:/var/www/discourse# rake uploads:migrate_from_s3
Migrating uploads from S3 to local storage for '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
(See full trace by running task with --trace)

(Voici la ligne sur GitHub où l’erreur se produit — je suppose qu’il n’arrive pas à récupérer la valeur de s3_bucket ?)

Autres tentatives

  • J’ai essayé d’ajouter les identifiants en ligne de commande, mais cela n’a rien changé. Par exemple :
    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

  • J’ai aussi essayé de remettre le nom du bucket S3 dans mes paramètres à celui du bucket original, mais sans succès, même résultat.

  • J’ai également essayé de reconstruire l’application. Même résultat.

@vinothkannans, sais-tu ce qui se passe ?

S’il vous plaît, aidez-moi, amis Discourse !

P.S. petite remarque secondaire : rake --tasks ne liste pas cette tâche ni aucune tâche commençant par uploads, je ne sais pas si cela signifie quelque chose.

Problème potentiellement lié ? cc @mcdanlj

@pnoeric oui, cela ressemble exactement à la même chose. Je n’ai pas eu de retour sur cette question concernant précisément l’intention derrière SiteSettings par rapport à GlobalSettings pour S3, donc je ne peux pas vous aider davantage pour le moment, si ce n’est à l’ajouter à SiteSettings via la configuration (point 1 dans mon message).

Salut, merci pour cette réponse… Je ne suis même pas sûr de ce que signifient SiteSettings par rapport à GlobalSettings — je ne suis pas un très bon développeur RoR et je ne comprends pas encore bien toute la configuration. Je me contente de suivre les instructions de base. :wink:

Mais j’espère que @vinothkannans va intervenir aussi ; je pense qu’il a écrit le code pour les tâches de migration. Ou n’importe qui d’autre de l’équipe @team qui pourrait savoir…

Gardons un œil sur ce sujet…

s3_bucket se trouve dans GlobalSettings, qui est défini à partir du fichier config/discourse.conf, généralement créé à partir des variables d’environnement dans le fichier app.yml. SiteSettings désigne les éléments que vous modifiez depuis les Paramètres d’administration de l’application.

Il semble qu’à l’origine, la seule façon de modifier S3 était de reconstruire l’application, et plus récemment, il est devenu possible de saisir les données dans les Paramètres d’administration. Je ne peux pas déterminer quelle était l’intention de ne pas effectuer une migration complète lors de l’ajout de la possibilité de définir S3 dans SiteSettings.

[Edit : J’ai inversé par erreur les deux termes lors de la première publication de cette réponse]

Hum @mcdanlj, juste pour confirmer, tu n’as pas encore réussi à faire fonctionner migrate_from_s3, c’est bien ça ?

Je n’ai aucun problème à modifier les paramètres, les fichiers de bas niveau ou tout ce qui est nécessaire… J’ai juste besoin de quitter S3 au plus vite, car cela me coûte les yeux de la tête.

Bonjour @pnoeric et @mcdanlj,

Une approche de débogage pourrait consister à accéder à la console Rails, puis à examiner les paramètres du site S2 ?

Par exemple, dans une application Discourse Docker standard, autonome et sans configuration personnalisée :

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

Comparer les paramètres du site (via la console Rails) avec les valeurs par défaut, listées ici :

Peut-être que déboguer de cette manière pourrait s’avérer utile (je n’en sais rien vraiment, car nous n’utilisons ni AWS ni S3) ? La console Rails pourrait peut-être aider un peu ?

La commande rake --tasks n’affiche que les tâches qui ont une description. Vous pouvez consulter toutes les tâches disponibles via rake -AT.

Je ne pense pas que cela aidera, car j’ai exécuté ces tâches très récemment sur un site de test. Les deux semblent dépendre de variables S3 définies dans l’environnement (env), mais cela remonte à quelques mois et migrate_from_s3 ne fonctionnait pas vraiment pour moi.

Question épineuse. J’ai bien défini s3_bucket dans config/discourse.conf comme mentionné dans le post que tu as lié, ce qui a résolu cette erreur particulière, comme je l’ai noté là-bas.

Ce fichier se trouve à l’intérieur du conteneur (./launcher enter app). Notez que pour que cela survive à ./launcher rebuild app, vous devez également ajouter DISCOURSE_S3_BUCKET à la section env de votre fichier containers/app.yml.

Le fait que je l’aie corrigé explique pourquoi c’était un post de développement et non une demande d’assistance ; je demandais aux développeurs quelle était la bonne solution alors que je continue à bidouiller cela.

J’ai environ 100 Go de fichiers dans S3, donc j’avance très prudemment. J’ai mis en place une limite pour les publications à examiner, et je dois maintenant mettre en place une limite pour les publications à modifier. J’essaie une chose à la fois. Le fait que ce code semble rarement utilisé et que j’aie vu cette erreur à plusieurs reprises me préoccupe quant à la dégradation du code ; je ne veux pas soudainement défigurer l’ensemble de mon site à cause d’un bug, et cela semble être un bon moyen de faire cette erreur.

  • Pour les uploads upload:// (pour moi, cela signifie les uploads non vidéo), jusqu’à présent, cela semble fonctionner. Je procède un par un, puis j’examine la publication concernée pour m’assurer que tout fonctionne.

  • Pour les uploads qui n’utilisent pas la syntaxe upload:// (pour moi, cela signifie les uploads vidéo, d’après ce que je comprends), où il y a une référence littérale à l’URL dans S3, cela déforme les URL. Ce n’est pas un bug difficile à corriger dès que je suis certain de savoir ce que je dois les changer en, mais je ne l’ai pas encore fait. Donc, c’est probablement l’un des PR que je publierai bientôt.

C’est un projet que je fais sur mon temps libre, donc pas de promesses concernant les délais.

Ah, merci ! Je vais essayer.

Argh, toujours rien, @neounix @mcdanlj @vinothkannans. Ça échoue encore. Mais au moins, il y a un nouveau message d’erreur différent…

Voici ce que j’ai essayé aujourd’hui :

  1. Mettre à jour vers la dernière version de Discourse, juste pour être sûr.

  2. Ajouter mon s3_bucket dans config/discourse.conf.

  3. ./launcher enter app.

  4. Modifier containers/app.yml et ajouter la variable DISCOURSE_S3_BUCKET.

  5. Tenter rake uploads:migrate_from_s3, et maintenant cela échoue avec un nouveau message d’erreur (avant, c’était downcase qui posait problème, maintenant ça semble être start_with?) :

/var/www/discourse# rake uploads:migrate_from_s3
Migrating uploads from S3 to local storage for 'default'...
rake aborted!
NoMethodError: undefined method `start_with?' for 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
(See full trace by running task with --trace)
  1. J’ai donc essayé ./launcher rebuild app.

  2. Puis à nouveau ./launcher enter app, rake uploads:migrate_from_s3.

Exactement le même problème :

/var/www/discourse# rake uploads:migrate_from_s3
Migrating uploads from S3 to local storage for 'default'...
rake aborted!
NoMethodError: undefined method `start_with?' for 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
(See full trace by running task with --trace)

D’autres idées ?

Au passage, faire ce processus est vraiment pénible — je dois planifier à l’avance et annoncer l’indisponibilité du forum plusieurs jours à l’avance, puis, le jour J, modifier le site principal pour empêcher les gens d’accéder au forum, et enfin, je dois arrêter le serveur du forum sur DigitalOcean et prendre une capture avant de continuer. Ça prend déjà environ 30 minutes. Ensuite, je le redémarre et je peux essayer les étapes ci-dessus. Je regrette tellement d’avoir configuré Amazon S3 pour le stockage des médias ! J’ai passé des heures à essayer d’annuler ce choix, toujours sans succès (et toujours une grosse facture Amazon chaque mois). J’aimerais vraiment comprendre ce qui se passe. Comment puis-je aider ?

Cette ligne est :

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

Il semble qu’elle exige également s3_region ; je ne vois pas pourquoi je n’ai pas rencontré ce problème.

Je ne suis pas sûr de suivre votre logique ; ma propre migration d’environ 100 Go de contenu est prévue en direct, après une sauvegarde normale du site. Mais je commence petit, c’est pourquoi j’ai travaillé à limiter la quantité migrée à la fois. Une mise en garde : le code semble incorrect pour les traductions d’URL littérales, comme je l’ai constaté pour les téléversements vidéo. Ainsi, si vous autorisez les téléversements vidéo, vous pourriez rencontrer un problème avec le code dans son état actuel.

Alors, peut-être que je devrais répéter toutes les étapes que j’ai faites plus haut, mais en ajoutant s3_bucket, s3_region, s3_cnd_url, s3_secret_access_key, etc. (en gros, toutes les variables que j’ai) dans les fichiers conf et yml ? Je préfère lui donner plus que ce dont il a peut-être besoin, juste pour que ça fonctionne vraiment.

J’ai vu que quelqu’un de l’équipe Discourse avait suggéré de sauvegarder l’ensemble du site local avant de commencer cette transition. Ce qui m’oblige à mettre mon serveur Digital Ocean hors ligne. :frowning:

Exactement. Je commence petit aussi… chaque fois que j’essaie, je migre 0 fichier. :grin:

Heureusement, seuls les fichiers JPG, GIF et PNG sont autorisés pour les uploads de membres sur mon forum, donc ça devrait aller.

Croisons les doigts.

La sauvegarde et l’instantané ne sont pas la même chose. Un instantané est la forme la plus rudimentaire de sauvegarde. La console d’administration dispose d’un outil de sauvegarde. Assurez-vous de le configurer pour sauvegarder les miniatures dans la configuration en premier lieu.

Maintenant que vous savez que vous n’avez pas besoin de mettre votre site hors ligne, vous devriez pouvoir vous détendre. Vous pouvez utiliser batch_migrate_from_s3 pour migrer au maximum un certain nombre de fichiers uploadés. Pour l’instant, cela limite les publications prises en compte plutôt que les migrations effectuées, un bug que je dois résoudre dans une future PR. Mais je dois aussi régler le bug relatif aux uploads vidéo, et j’aimerais envisager d’afficher des retours, car l’un des objectifs de la limite est de pouvoir confirmer dans les publications concernées que la migration a réussi.

Je vais probablement faire tout cela au cours des 1 à 2 prochains mois, donc si vous souhaitez attendre, cela pourrait valoir le coup de payer quelques mois supplémentaires de S3. À vous de voir, je ne fais pas de promesses, je déclare simplement mon intention.

@pnoeric, puisque vous êtes préoccupé par la disponibilité du site, je voulais vous transmettre ce que j’ai appris jusqu’à présent.

J’ai effectué ma migration en direct, comme je l’ai mentionné. Si je ne limite pas le débit de la migration, les files d’attente qui gèrent des tâches comme notifier les utilisateurs de l’activité des autres se saturent, ce qui dégrade l’expérience utilisateur du site.

J’ai migré environ 500 publications avec des vidéos et environ 30 000 publications avec des images, ce qui a pris environ deux semaines pour être terminé.

Si vous souhaitez essayer le code que j’ai utilisé, il se trouve actuellement à l’adresse suivante :

Vous pouvez le télécharger et le copier dans votre application pour remplacer le contenu actuel de lib/tasks/uploads.rake.

Avec ce code, vous pouvez faire quelque chose comme ceci :

bin/rake uploads:batch_migrate_from_s3[100,1000]

Cela ne prendra en compte que 1 000 publications au total contenant des fichiers joints, et migrera les fichiers d’un maximum de 100 publications avant de s’arrêter ; chaque fois qu’il modifie effectivement une publication après avoir migré ses fichiers joints, il attendra que la file d’attente soit vide avant de démarrer la suivante.

Si vous copiez le fichier, cela cassera les futures mises à jour du site jusqu’à ce que vous annuliez le changement. Le moyen le plus simple de l’annuler une fois satisfait est simplement ./launcher rebuild app (bien que, en tant que développeur, j’utilise git checkout HEAD lib/tasks/uploads.rake pour annuler mes modifications…).

J’ai remarqué qu’au moins avec Digital Ocean Spaces, je dois parfois réessayer plusieurs fois avant qu’une migration ne réussisse. Le script tel qu’il est actuellement ne vous donne aucun avertissement lorsque cela se produit, et vous devez simplement continuer à l’exécuter et attendre de voir. J’ai une PR en attente de révision qui affiche les erreurs dans ce cas, afin que vous sachiez au moins qu’un problème s’est produit.

J’ai ajouté une simple boucle de réessai courte, ainsi que le message d’erreur, et il semble que la boucle de réessai résolve le problème. De plus, la validation par rapport aux règles actuelles était effectuée sur le contenu brut des publications passées, ce qui pouvait casser la migration et laisser silencieusement des publications nécessitant une nouvelle cuisson ; j’ai également corrigé cela. Vous ne voudrez absolument pas effectuer une migration sans obtenir au moins la correction de validation, qui fait partie des commits de ma PR actuellement en cours de révision.

J’ai terminé ma migration, à ma connaissance. Ma PR contient tout le code que j’ai utilisé pour achever ma migration. Elle n’a pas encore été révisée. Je vous suggère de suivre l’évolution sur Migrate_from_s3 problems si vous le souhaitez.

Merci ! Je vais essayer cela dans les prochains jours.

Je viens d’ajouter une note dans ce message indiquant qu’il reste un bug que nous avons découvert aujourd’hui : les photos de profil ont disparu pour certains utilisateurs, et je ne sais pas pourquoi. Nous avons haussé les épaules et avons demandé aux utilisateurs concernés de restaurer leurs données, en nous excusant pour ce problème.

J’ai bien sûr effectué des sauvegardes fréquentes tout au long de ce processus ! :smiling_face:

Bonne chance !

Sérieusement, est-ce que cela pourrait me rendre encore plus fou ? :crazy_face:

Voici ce que j’ai fait :

  1. J’ai copié votre nouveau code lib/tasks/upload.rake dans mon Discourse
  2. J’ai ajouté TOUS mes variables Amazon s3_ à config/discourse.conf
  3. Je les ai également ajoutées à app.yml (je ne suis pas sûr que cela ait un effet, mais pourquoi pas)
  4. J’ai exécuté cette commande et j’ai obtenu…
root@:/var/www/discourse/config# rake uploads:batch_migrate_from_s3[100,1000]
Vous devez désactiver les uploads S3 avant d'exécuter cette tâche.

Et j’ai confirmé :

Donc, d’accord. J’ai édité le fichier uploads.rake et j’ai simplement supprimé cette vérification.

Maintenant, j’obtiens :

root@:/var/www/discourse/lib/tasks# rake uploads:batch_migrate_from_s3[100,1000]
Migration des uploads depuis S3 vers le stockage local pour 'default'...
Migration d'un maximum de 100 messages sur 1000...
... (beaucoup de sortie ici) ...
Modifié 91/100 : 28795 : 28486/1 - https://example.com/t/topic-title-here/28486/1
... (beaucoup de sortie ici) ...

Donc cela semblait fonctionner ! Hourra !

Après ce premier lot de 100, j’ai vérifié sidekiq et j’ai vu que mon message de test était en file d’attente, alors j’ai attendu qu’il soit terminé…

…puis je suis revenu vérifier… et ce message tire toujours son image depuis Amazon S3. :frowning: J’ai essayé de “Reconstruire le HTML” sur le message, mais cela n’a rien changé.

Alors j’ai essayé tout le processus à nouveau, depuis la commande rake jusqu’au bout, et j’ai obtenu les mêmes résultats : les mêmes 100 messages ont été traités, les mêmes éléments mis en file d’attente dans sidekiq, et après avoir laissé tourner, l’image de ce message de test provient toujours de S3.

Hmm, je ne suis pas sûr de quoi essayer ensuite. :man_shrugging:t2:

@mcdanlj, toute suggestion ou conseil que vous pourriez avoir serait apprécié :wink:

C’est exactement ce à quoi je m’attendrais si vous supprimiez cette vérification. Je ne sais pas pourquoi vous avez décidé de la supprimer. C’est intentionnel. Désactivez les uploads vers S3 avant de lancer la migration.

Ils étaient désactivés — complètement désactivés. (L’image de la case à cocher dans mon message correspond bien au bon paramètre, n’est-ce pas ?) Je les ai même activés puis désactivés à nouveau. Rien n’y fait.