由于 S3 迁移失败导致恢复失败

我们自行托管 Discourse 数据库,并正尝试迁移到新服务器。

两端(旧服务器和新服务器)均已更新至最新版本的 Discourse(两端的应用程序重建仅相隔几分钟),且几天前已在旧服务器上成功完成了向新 PostgreSQL 的迁移。因此,我可以排除这些因素作为问题的根源。

我们所有的上传文件都存储在 S3 兼容的对象存储(DigitalOcean Spaces)中,因此从理论上讲,迁移应该很容易。我原以为,如果恢复过程中的“帖子和分类”部分运行正常,那么指向 S3 上传文件的链接应该就能正常工作,对吧?

然而事实并非如此。每当我在新服务器上执行备份恢复时,“帖子”部分都能 100% 顺利完成,但随后在 S3 部分却失败了。

以下是我们看到的错误信息。

正在重新连接数据库...
正在重新加载站点设置...
正在为非员工用户禁用出站邮件...
正在运行 seed fu...
正在禁用只读模式...
正在清除分类缓存...
正在重新加载翻译...
正在重新映射上传文件...
正在恢复上传文件,这可能需要一些时间...
正在将上传文件迁移到 'default' 的 S3...
正在将文件上传至 S3...
 - 列出本地文件
 => 3 个文件
 - 列出 S3 文件
..................................................................................................................................................... => 148892 个文件
 - 将文件同步至 S3
...
正在更新数据库中的 URL...
正在移除旧的优化图片...
正在标记所有包含灯箱效果的帖子以进行重新烘焙...
29368 个帖子被标记为需要重新烘焙
异常:rake posts:missing_uploads 识别出 2274 个问题。数据库 'default' 的 S3 迁移失败。
/var/www/discourse/lib/file_store/to_s3_migration.rb:132:in 'FileStore::ToS3Migration#raise_or_log'
/var/www/discourse/lib/file_store/to_s3_migration.rb:104:in 'FileStore::ToS3Migration#migration_successful?'
/var/www/discourse/lib/file_store/to_s3_migration.rb:384:in 'FileStore::ToS3Migration#migrate_to_s3'
/var/www/discourse/lib/file_store/to_s3_migration.rb:59:in 'FileStore::ToS3Migration#migrate'
/var/www/discourse/lib/file_store/s3_store.rb:372:in 'FileStore::S3Store#copy_from'
/var/www/discourse/lib/backup_restore/uploads_restorer.rb:69:in 'BackupRestore::UploadsRestorer#restore_uploads'
/var/www/discourse/lib/backup_restore/uploads_restorer.rb:49:in 'BackupRestore::UploadsRestorer#restore'
/var/www/discourse/lib/backup_restore/restorer.rb:179:in 'BackupRestore::Restorer#restore_uploads'
/var/www/discourse/lib/backup_restore/restorer.rb:72:in 'BackupRestore::Restorer#run'
script/discourse:242:in 'DiscourseCLI#restore'
/var/www/discourse/vendor/bundle/ruby/3.4.0/gems/thor-1.5.0/lib/thor/command.rb:28:in 'Thor::Command#run'
/var/www/discourse/vendor/bundle/ruby/3.4.0/gems/thor-1.5.0/lib/thor/invocation.rb:127:in 'Thor::Invocation#invoke_command'
/var/www/discourse/vendor/bundle/ruby/3.4.0/gems/thor-1.5.0/lib/thor.rb:538:in 'Thor.dispatch'
/var/www/discourse/vendor/bundle/ruby/3.4.0/gems/thor-1.5.0/lib/thor/base.rb:585:in 'Thor::Base::ClassMethods#start'
script/discourse:396:in '<top (required)>'
/usr/local/lib/ruby/gems/3.4.0/gems/bundler-4.0.11/lib/bundler/cli/exec.rb:61:in 'Kernel.load'
/usr/local/lib/ruby/gems/3.4.0/gems/bundler-4.0.11/lib/bundler/cli/exec.rb:61:in 'Bundler::CLI::Exec#kernel_load'
/usr/local/lib/ruby/gems/3.4.0/gems/bundler-4.0.11/lib/bundler/cli/exec.rb:24:in 'Bundler::CLI::Exec#run'
/usr/local/lib/ruby/gems/3.4.0/gems/bundler-4.0.11/lib/bundler/cli.rb:504:in 'Bundler::CLI#exec'
/usr/local/lib/ruby/gems/3.4.0/gems/bundler-4.0.11/lib/bundler/vendor/thor/lib/thor/command.rb:28:in 'Bundler::Thor::Command#run'
/usr/local/lib/ruby/gems/3.4.0/gems/bundler-4.0.11/lib/bundler/vendor/thor/lib/thor/invocation.rb:127:in 'Bundler::Thor::Invocation#invoke_command'
/usr/local/lib/ruby/gems/3.4.0/gems/bundler-4.0.11/lib/bundler/vendor/thor/lib/thor.rb:538:in 'Bundler::Thor.dispatch'
/usr/local/lib/ruby/gems/3.4.0/gems/bundler-4.0.11/lib/bundler/cli.rb:35:in 'Bundler::CLI.dispatch'
/usr/local/lib/ruby/gems/3.4.0/gems/bundler-4.0.11/lib/bundler/vendor/thor/lib/thor/base.rb:584:in 'Bundler::Thor::Base::ClassMethods#start'
/usr/local/lib/ruby/gems/3.4.0/gems/bundler-4.0.11/lib/bundler/cli.rb:29:in 'Bundler::CLI.start'
/usr/local/lib/ruby/gems/3.4.0/gems/bundler-4.0.11/exe/bundle:28:in 'block in <top (required)>'
/usr/local/lib/ruby/gems/3.4.0/gems/bundler-4.0.11/lib/bundler/friendly_errors.rb:118:in 'Bundler.with_friendly_errors'
/usr/local/lib/ruby/gems/3.4.0/gems/bundler-4.0.11/exe/bundle:20:in '<top (required)>'
/usr/local/bin/bundle:25:in 'Kernel#load'
/usr/local/bin/bundle:25:in '<main>'
正在尝试回滚...
正在回滚...
正在清理...
正在从 discourse_functions 架构中删除函数...
正在移除临时目录 '/var/www/discourse/tmp/restores/default/2026-08-11-075958'...
正在取消暂停 sidekiq...
正在标记恢复为已完成...
正在通知 'system' 恢复结束...
完成!
[失败]
恢复完成。

我有几个问题:

  • 既然我们保存在数据库中的 S3 环境设置未变,为什么它会失败?
  • 为什么它会崩溃,而不是生成一份它发现的 2274 个上传文件问题列表,以便我进行处理?
  • 为什么它会自动回滚到空数据库,让我陷入孤立无援的境地?
  • 是否有办法让我接管,让它成功完成恢复,或者至少不回滚,让我自行处理它发现的上传文件问题?

提前非常感谢任何帮助!