Ошибка загрузки резервной копии из-за неинициализированного TransferManager

После обновления до v2026.8.0-latest.1 +4 мои резервные копии начали завершаться с ошибкой. Вот логи: log.txt.zip (22,1 КБ)

В частности, вот раздел, который выглядит наиболее релевантным:

[2026-08-04 03:37:52] Uploading archive...
[2026-08-04 03:37:52] EXCEPTION: uninitialized constant Aws::S3::TransferManager
[2026-08-04 03:37:52] /var/www/discourse/lib/s3_helper.rb:453:in 'S3Helper#transfer_manager'
/var/www/discourse/lib/s3_helper.rb:332:in 'S3Helper#upload_file'
/var/www/discourse/lib/backup_restore/s3_backup_store.rb:48:in 'BackupRestore::S3BackupStore#upload_file'
/var/www/discourse/lib/backup_restore/creator.rb:437:in 'BackupRestore::Creator#upload_archive'
/var/www/discourse/lib/backup_restore/creator.rb:41:in 'BackupRestore::Creator#run'
/var/www/discourse/lib/backup_restore.rb:13:in 'BackupRestore.backup!'
/var/www/discourse/app/jobs/regular/create_backup.rb:10:in 'Jobs::CreateBackup#execute'
/var/www/discourse/app/jobs/base.rb:313:in 'block (2 levels) in Jobs::Base#perform'

Я не уверен, как решить эту проблему.

Я обновился до v2026.9.0-latest +565, но столкнулся с точно такой же проблемой.

Версия Discourse, которую вы используете, включает версию aws-sdk-s3, которая должна предоставлять Aws::S3::TransferManager.

Вы используете официальную установку Discourse в Docker? Если вы используете официальный Docker-набор, был ли контейнер полностью пересобран в рамках обновления?

Да, я полагаю, что использую официальную установку Discourse через Docker. Есть ли способ убедиться в этом наверняка? Прошло довольно много времени с момента установки.

Для обновления я выполнил ./launcher rebuild app. Я предполагаю, что это означает полную пересборку контейнера, но, возможно, я ошибаюсь?

Ещё несколько деталей, которые могут быть важны:

  • Используется Ubuntu 24.04.4 LTS
  • В app.yml в хуке after_code устанавливаются официальные плагины docker_manager и discourse-doc-categories. Другие плагины в app.yml не определены.
  • Я пытаюсь хранить резервные копии в S3-совместимом хранилище, предоставляемом Backblaze, и ранее это работало.

Чтобы сузить область поиска, можно проверить, какой именно gem aws-sdk-s3 фактически загружается внутри работающего контейнера.

Изменение в Discourse, которое ввело Aws::S3::TransferManager, также повысило версию aws-sdk-s3 с 1.182.0 до 1.227.0:

В указанной вами ревизии Discourse файл Gemfile.lock по-прежнему должен использовать aws-sdk-s3 версии 1.227.0, которая предоставляет Aws::S3::TransferManager.

Можете ли вы попробовать войти в контейнер:

cd /var/discourse
./launcher enter app

Затем, внутри контейнера:

cd /var/www/discourse
bundle info aws-sdk-s3
bundle exec ruby -e '
require "aws-sdk-s3"
puts "gem: #{Gem.loaded_specs["aws-sdk-s3"]&.full_name}"
puts "path: #{Gem.loaded_specs["aws-sdk-s3"]&.full_gem_path}"
p Aws::S3.autoload?(:TransferManager)
p Aws::S3::TransferManager
'

Также может быть полезно проверить само приложение в среде Rails:

RAILS_ENV=production bundle exec rails runner '
puts "aws-sdk-s3: #{Gem.loaded_specs["aws-sdk-s3"]&.version}"
p Aws::S3.autoload?(:TransferManager)
p Aws::S3::TransferManager
'

Затем покиньте контейнер с помощью команды:

logout

Если эти команды покажут более старую версию aws-sdk-s3 или отсутствие TransferManager, это объяснит исключение при резервном копировании и укажет на то, что установленные в контейнере gems не соответствуют текущему Gemfile.lock Discourse.

Если же будет указана версия 1.227.0 и Aws::S3::TransferManager успешно резолвится, то проблема более необычна, и нам нужно будет посмотреть, чем отличается процесс резервного копирования Sidekiq от этой интерактивной среды.

Поскольку вы используете ./launcher rebuild app, это действительно похоже на стандартный рабочий процесс discourse_docker; приведенные выше команды помогут нам более точно понять, что именно оказалось в пересобранном контейнере.

Похоже, у меня устаревшая версия aws-sdk-s3.

$ bundle info aws-sdk-s3
  * aws-sdk-s3 (1.177.0)
	Summary: AWS SDK for Ruby - Amazon S3
	Homepage: https://github.com/aws/aws-sdk-ruby
	Source Code: https://github.com/aws/aws-sdk-ruby/tree/version-3/gems/aws-sdk-s3
	Changelog: https://github.com/aws/aws-sdk-ruby/tree/version-3/gems/aws-sdk-s3/CHANGELOG.md
	Path: /var/www/discourse/vendor/bundle/ruby/3.4.0/gems/aws-sdk-s3-1.177.0

Изучение этого вопроса напомнило мне, что я использовал это обходное решение, чтобы обойти проблему с тем, что AWS SDK не работает с Backblaze. Ознакомившись с обсуждением, я выяснил, что Backblaze обновила свой API, из-за чего обходное решение стало ненужным.

После того как я удалил обходное решение, резервное копирование успешно завершилось! Спасибо за помощь. :heart:

Одна мысль по этому поводу: временные шаблоны совместимости, подобные этому, могут быть безопаснее, если они имеют某种 механизм самовыключения или условия защиты, а не продолжают бесконечно переопределять зависимости Discourse.

Например, для временных бэкпортов исходного кода я планирую использовать хуки в production, которые сначала проверяют, присутствует ли уже исправление в upstream, и применяют патч только в том случае, если он всё ещё необходим.

В данном случае, что-то вроде следующего могло бы потенциально предотвратить продолжение использования закреплённой версии aws-sdk-s3 1.177.0, как только сам Discourse начал зависеть от новых функций SDK:

hooks:
  after_bundle_exec:
    - exec:
        cd: $home
        cmd:
          - |
            if grep -q "Aws::S3::TransferManager" lib/s3_helper.rb; then
              echo "Discourse теперь требует Aws::S3::TransferManager; пропускаем устаревшее понижение версии aws-sdk-s3 Backblaze"
            else
              echo "Применяем временный pin совместимости aws-sdk-s3 Backblaze"
              bundle config set frozen false
              sed -i 's/gem "aws-sdk-s3", require: false/gem "aws-sdk-s3", "1.177.0", require: false/' Gemfile
              bundle update aws-sdk-s3
              bundle add aws-sdk-core --version 3.215
            fi

Эта конкретная проверка носит лишь иллюстративный характер — более общая проверка версии или явное сбойное состояние, когда Discourse переходит к ожидаемой версии SDK, были бы, вероятно, предпочтительнее.

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

Хотя я согласен, что было бы хорошо, если бы ошибка сообщалась явно, до этого момента я хотел, чтобы версии гемов не совпадали с версиями, ожидаемыми Discourse, поскольку более новая версия aws-sdk-s3 отправляла заголовки, которые Backblaze не поддерживал, и я хотел, чтобы резервное копирование работало.

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

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