Rake uploads:migrate_from_s3 не выполняется

Я следовал этим инструкциям: сделал полную резервную копию сайта, клонировал свой бакет AWS S3, изменил имя бакета в настройках Discourse с оригинального на резервное и снял галочку «uploads to S3» в настройках.

Теперь я, наконец, готов начать миграцию с S3… но она завершается ошибкой. :frowning:

Сообщение об ошибке

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)

(Вот строка в GitHub, где происходит сбой— похоже, что значение s3_bucket не получается получить?)

Другие попытки решения

  • Я пробовал добавлять учётные данные в командную строку, но это не помогло. Например:
    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

  • Также я пробовал вернуть имя бакета S3 в настройках к оригинальному значению, но результата нет — та же ошибка.

  • Попробовал пересобрать приложение. Результат тот же.

@vinothkannans, вы не знаете, что происходит?

Пожалуйста, помогите, друзья из Discourse!

p.s. маленькое примечание: команда rake --tasks не показывает эту задачу или какие-либо задачи, начинающиеся с uploads. Не знаю, имеет ли это какое-то значение.

Возможно, это связанная проблема? cc @mcdanlj

@pnoeric да, это выглядит точно так же. Я не получил ответа в том обсуждении относительно того, какова именно цель использования SiteSettings по сравнению с GlobalSettings для S3, поэтому прямо сейчас я не могу предложить ничего иного, кроме как добавить эту настройку в SiteSettings через конфигурацию (пункт 1 в моём сообщении).

Привет, спасибо за этот ответ… Я даже не уверен, что означает SiteSettings в отличие от GlobalSettings — я не очень хорошо разбираюсь в коде RoR и не до конца понимаю всю настройку. Я просто следую базовым инструкциям. :wink:

Но надеюсь, что @vinothkannans тоже подключится; думаю, он писал код для задач миграции. Или кто-то другой из команды @team, кто может знать…

Давайте будем следить за этой темой…

s3_bucket находится в GlobalSettings, которые обычно задаются из файла config/discourse.conf, созданного на основе переменных окружения в файле app.yml. SiteSettings — это параметры, которые вы меняете в разделе «Настройки администратора» в приложении.

Похоже, что изначально изменение настроек S3 требовало пересборки приложения, а относительно недавно появилась возможность вводить эти данные через «Настройки администратора». Неясно, почему при добавлении возможности настройки S3 в SiteSettings не было выполнено полное перенесение данных.

[Редактирование: Я по ошибке перепутал эти два понятия при первом написании этого ответа]

Хм, @mcdanlj, просто для уточнения: вы так и не смогли разобраться, как заставить migrate_from_s3 работать, верно?

Меня устраивает редактирование любых настроек, низкоуровневых файлов или чего там ещё потребуется… Мне просто нужно как можно скорее уйти от S3, так как это стоит мне целого состояния.

Привет @pnoeric и @mcdanlj,

Один из подходов к отладке — зайти в консоль Rails и затем взглянуть на настройки сайта s2?

Например, в обычном OOTB приложении Discourse в виде одного контейнера Docker:

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)

Сравнивая настройки сайта (через консоль Rails) с значениями по умолчанию, перечисленными здесь:

Возможно, такая отладка окажется полезной (на самом деле не знаю, так как мы не используем AWS или S3)? Может быть, консоль Rails немного поможет?

rake --tasks показывает только задачи, у которых есть описание. Все доступные задачи можно просмотреть с помощью rake -AT.

Я не думаю, что это поможет, так как я совсем недавно запускал эти задачи на тестовом сайте. Обе, похоже, зависят от того, что переменные S3 определены в env, однако это было пару месяцев назад, и migrate_from_s3 не очень хорошо сработал для меня.

Непростой вопрос. Я действительно установил s3_bucket в config/discourse.conf, как упоминалось в сообщении, на которое вы ссылаетесь, и это действительно устранило эту конкретную ошибку, как я и отмечал там.

Этот файл находится внутри контейнера (./launcher enter app). Обратите внимание, что чтобы изменения сохранились после выполнения ./launcher rebuild app, вам также необходимо добавить DISCOURSE_S3_BUCKET в секцию env вашего файла containers/app.yml.

То, что я уже исправил это, стало причиной того, что мой пост был посвящён разработке, а не поддержке: я спрашивал, что разработчики считают правильным решением, пока я продолжаю экспериментировать.

У меня в S3 около 100 ГБ файлов, поэтому я действую очень осторожно. Я реализовал ограничение на количество просматриваемых постов, и теперь мне нужно реализовать ограничение на количество постов для изменения. Я пытаюсь делать по одной вещи за раз. Тот факт, что этот код, судя по всему, используется редко, а я вижу эту ошибку неоднократно, вызывает у меня опасения по поводу «гниения» кода, и я не хочу случайно испортить весь свой сайт из-за ошибки; при этом это выглядит как один из способов допустить такую ошибку.

  • Для загрузок с префиксом upload:// (для меня это загрузки, не являющиеся видео) пока всё работает. Я обрабатываю по одному и затем проверяю затронутый пост, чтобы убедиться, что всё функционирует корректно.

  • Для загрузок, которые не используют синтаксис upload:// (для меня, насколько я могу судить, это загрузки видео), где есть буквальная ссылка на URL в S3, происходит искажение URL. Это не сложная ошибка для исправления, как только я точно определю, на что именно их нужно менять, но я ещё этого не сделал. Поэтому это, скорее всего, будет одним из PR, которые я опубликую в ближайшее время.

Для меня это проект на свободное время, поэтому никаких гарантий по срокам дать не могу.

Ага, спасибо! Я попробую.

Ах, всё ещё безрезультатно, @neounix @mcdanlj @vinothkannans. Всё ещё ошибка. Но хотя бы теперь новое/другое сообщение об ошибке…

Вот что я пробовал сегодня:

  1. Обновился до последней версии Discourse, просто на всякий случай.

  2. Добавил свой s3_bucket в config/discourse.conf.

  3. ./launcher enter app.

  4. Отредактировал containers/app.yml и добавил переменную DISCOURSE_S3_BUCKET.

  5. Попробовал rake uploads:migrate_from_s3, и теперь он падает с новым сообщением об ошибке (ранее проблема была в downcase, теперь, похоже, в 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. Тогда я попробовал ./launcher rebuild app.

  2. Снова ./launcher enter app, rake uploads:migrate_from_s3.

Проблема точно та же:

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

Есть какие-то другие идеи?

Кстати, этот процесс — настоящая мука: мне приходится заранее планировать и объявлять о простое форума за несколько дней, затем в день простоя изменять главную страницу, чтобы пользователи не могли попасть на форум, а затем отключать сервер форума на DigitalOcean и делать снимок перед продолжением. Это уже около 30 минут. Потом я снова запускаю его и только тогда могу попробовать шаги выше. Я так жалею, что настроил Amazon S3 для хранения медиа! Я потратил часы, пытаясь исправить это решение, но всё ещё безрезультатно (и при этом каждый месяц получаю большой счёт от Amazon). Я бы очень хотел разобраться в этом. Чем я могу помочь?

Эта строка выглядит так:

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

Кажется, что требуется также и s3_region; непонятно, почему у меня это не вызвало проблем.

Не совсем понимаю вашу логику; я планирую выполнить миграцию своего контента объемом около 100 ГБ в режиме реального времени после обычной резервной копии сайта. Но я начинаю с малого, поэтому и стараюсь ограничивать объем данных, мигрируемых за один раз. Одно предупреждение: код, похоже, написан неправильно для буквальных переводов URL, как я видел на примере загрузки видео. Поэтому, если вы разрешите загрузку видео, с текущим состоянием кода у вас могут возникнуть проблемы.

Так, может, мне стоит повторить все шаги, которые я делал выше, но добавить s3_bucket, s3_region, s3_cnd_url, s3_secret_access_key и т. д. (по сути, все мои переменные) в файлы conf и yml? Я лучше дам системе больше, чем ей (возможно) нужно, лишь бы всё заработало.

Я видел, что кто-то из команды Discourse предложил сделать полную резервную копию локального сайта перед началом этой миграции. Это потребует отключить мой сервер Digital Ocean. :frowning:

Понятно. Я тоже начинаю с малого… каждый раз, когда пытаюсь, я мигрирую 0 файлов. :grin:

К счастью, в моём форуме участники могут загружать только JPG, GIF и PNG, так что всё должно быть в порядке.

Надеюсь на лучшее.

Резервное копирование и снимок — это не одно и то же. Снимок — это самая грубая форма резервного копирования. В консоли администратора есть функция резервного копирования. Убедитесь, что вы сначала настроили её для создания резервных копий миниатюр в конфигурации.

Теперь, когда вы знаете, что вам не нужно выводить сайт из строя, вы должны почувствовать себя спокойнее. Вы можете использовать batch_migrate_from_s3 для миграции не более определённого количества загрузок. В данный момент ограничение касается рассматриваемых постов, а не выполненных миграций — это баг, который мне нужно исправить в будущем PR. Однако мне также нужно устранить баг с загрузкой видео, и я хотел бы добавить возможность вывода обратной связи, поскольку одна из целей ограничения — возможность подтвердить успешность миграции в затронутых постах.

Вероятно, я займусь этим в течение следующих 1–2 месяцев, поэтому, если вы хотите подождать, возможно, стоит оплатить ещё несколько месяцев использования S3. Это ваше решение, и я не даю обещаний, а лишь заявляю о своих намерениях.

@pnoeric, раз вы обеспокоены временем безотказной работы сайта, я хотел бы поделиться с вами тем, что узнал на данный момент.

Я выполнял миграцию в режиме реального времени, как уже упоминал. Если не ограничивать скорость миграции, очереди, отвечающие за такие задачи, как уведомление пользователей о активности друг друга, переполняются, и пользовательский опыт на сайте ухудшается.

Я мигрировал около 500 постов с видео и примерно 30 000 постов с изображениями, что заняло около двух недель.

Если вы хотите попробовать код, который я использовал, он находится здесь:

Вы можете скачать его и скопировать в своё приложение, заменив текущее содержимое файла lib/tasks/uploads.rake.

С этим кодом вы можете выполнить что-то вроде следующего:

bin/rake uploads:batch_migrate_from_s3[100,1000]

Это рассмотрит только 1000 постов с вложениями в общей сложности и мигрирует файлы максимум из 100 постов перед остановкой; каждый раз, когда скрипт фактически изменяет пост после миграции его вложений, он будет ждать, пока очередь не опустеет, прежде чем переходить к следующему.

Если вы скопируете этот файл, это сломает будущие обновления сайта, пока вы не отмените изменения. Самый простой способ отменить их после того, как вы останетесь довольны результатом, — это выполнить ./launcher rebuild app (хотя как разработчик я использую git checkout HEAD lib/tasks/uploads.rake, чтобы отменить свои изменения…).

Я заметил, что, по крайней мере, в случае с DigitalOcean Spaces, иногда мне приходится повторять попытку несколько раз, прежде чем миграция завершится успешно. В текущем виде скрипт не выводит никаких предупреждений при возникновении таких ситуаций, и вам просто приходится продолжать запускать его и ждать результата. У меня есть запрос на слияние (PR), ожидающий проверки, который выводит сообщения об ошибках в таких случаях, чтобы вы хотя бы знали, что что-то пошло не так.

Я добавил простой короткий цикл повторных попыток, а также вывод сообщения об ошибке, и, похоже, цикл повторных попыток решает проблему. Кроме того, валидация по текущим правилам выполнялась для исходного содержимого прошлых постов, что могло сломать миграцию и незаметно оставить посты, требующие повторной обработки; я также исправил это. Вам определённо не стоит выполнять миграцию без получения хотя бы исправления валидации, которое является одним из коммитов в моём PR, currently находящемся на рассмотрении.

Насколько мне известно, я завершил свою миграцию. Мой PR содержит весь код, который я использовал для её завершения. Он ещё не был проверен. Если хотите, рекомендую следить за обсуждением по адресу Migrate_from_s3 problems.

Спасибо! Я попробую это в ближайшие дни.

Я только что добавил примечание в тот пост о том, что сегодня мы обнаружили одну оставшуюся ошибку: у некоторых пользователей пропали аватары, и я не знаю почему. Мы пожали плечами и попросили затронутых пользователей восстановить данные, извинившись за возникшую проблему.

Я точно делал частые резервные копии в процессе! :smiling_face:

Удачи!

Честно говоря, неужели это может свести меня с ума? :crazy_face:

Вот что я сделал:

  1. Скопировал новый код lib/tasks/upload.rake в свой Discourse.
  2. Добавил ВСЕ свои переменные Amazon s3_ в config/discourse.conf.
  3. Также добавил их в app.yml (не совсем понятно, нужно ли это, но почему бы и нет).
  4. Запустил эту команду и получил…
root@:/var/www/discourse/config# rake uploads:batch_migrate_from_s3[100,1000]
You must disable S3 uploads before running that task.

И подтвердил:

Ладно. Я отредактировал файл uploads.rake и просто убрал эту проверку.

Теперь я вижу:

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...
... (lots of output here) ...
Modified 91/100: 28795: 28486/1 - https://example.com/t/topic-title-here/28486/1
... (lots of output here) ...

Кажется, всё работает! Ура!

После обработки первой партии из 100 записей я проверил Sidekiq и увидел, что мой тестовый пост в очереди, поэтому я дождался завершения…

…затем вернулся и проверил… но этот пост всё ещё подгружает изображение с Amazon S3. :frowning: Я попробовал «Пересобрать HTML» для поста, но это не помогло.

Тогда я попробовал весь процесс заново: от rake до конца, и получил тот же результат — обработаны те же 100 постов, те же задачи в очереди Sidekiq, и после завершения выполнения изображение в тестовом посте всё ещё берётся с S3.

Хм, не знаю, что попробовать дальше. :man_shrugging:t2:

@mcdanlj буду благодарен за любые предложения или советы :wink:

Это именно то, чего я ожидал, если убрать эту проверку. Не совсем понятно, почему вы решили её удалить. Она сделана намеренно. Отключите загрузку в S3 перед началом миграции.

Они были выключены — совершенно выключены. (Изображение флажка в моём посте — это правильное значение, верно?) Я даже включил их и снова выключил. Не помогло.