我接下来要解决两个问题:首先是,限制是有帮助的,但它仅限制搜索空间;接下来,我希望能够指定要修改的帖子数量上限。因此,我打算同时添加要修改的帖子数量上限以及查询的限制。此外,在指定 max 时,为了调试目的,详细说明正在处理的内容是合理的,因此如果 max 不为 nil,我希望让输出变得详细——这将允许人们在继续之前验证处理过程,因为这是此项工作的主要用例。
我认为我会将 max 作为第一个参数,将可选的 limit 作为第二个参数,因为实际上 max 是最重要的;limit 只是为了让“仅一次请求”更便宜。
第二个问题是关于非上传内容的:上传。大约一年前,当我在尝试弄清楚如何编写从 Google+ 到 Discourse 的迁移脚本时,曾尝试将视频上传到我即将加入的 Discourse 站点,当时看到的 URL 格式是 https://#{SiteSettings.absolute_base_url}/original/3X/b/a/ba9e06ebc2f4397f26793bb5cd4e169308dd371d.mp4。
而今天,当我上传视频时,得到的却是类似  的格式。
至少在我最近的测试中,migrate_from_s3 完全搞乱了这些 URL,使它们甚至不再成为有效的 URL,因此这绝对需要修复。然后,我认为在实际操作中,这项任务不太可能遇到  这种情况,所以作为初步方案,我打算直接在神奇的 upload 协议周围添加链接 Markdown,而不是让正则表达式同时处理两种情况,从而导致代码更难阅读。不过,我可能会改变主意。
看起来 video 或 audio 标签是通过 JavaScript 中的正则表达式匹配添加的,因此我必须将 app/assets/javascripts/discourse/app/lib/uploads.js 中的正则表达式复制到任务中,以便正确识别它们。我会包含这些正则表达式的来源,以便下一个发现它们的人知道从哪里更新它们。![]()
…
今晚,我抽出了一些时间来做这项工作,目前已经有了一个草稿 PR。它尚未完成;我知道其中还存在一些 bug。我认为目前为止我还没有改变 upload: 伪协议 URL(通常用于图片)的任何行为,尽管我添加了一项健全性检查。
https://github.com/discourse/discourse/pull/10093
通过此 PR 中的更改,我已经成功迁移了正常的 upload: 伪协议上传内容,以及目前通过 S3 引用(在我的情况下是 Digital Ocean Spaces)明确引用的视频。我使用以下命令一次只修改一个帖子:
bin/rake uploads:batch_migrate_from_s3[1,1000]
请注意,这不会超过数据库查询返回的前 1000 个帖子( somewhat 随机);设置较低的限制只是为了在逐个迁移帖子、检查其行为正确性然后重新开始寻找下一个帖子时加快查询速度。此命令仅在我当前正在开发的 PR 中按此方式工作!
…
随着工作的推进,我继续添加诊断输出,并且我开始认为这对于开发之外的用途也很重要。我发现来自 Digital Ocean Spaces 的许多临时下载失败,其中帖子中的某些下载成功迁移,而另一些则失败,在原始情况下这只会打印一个 . 并继续,然后显示 Done,但实际上任务并未完成。我对一个帖子进行了大约五到六次操作,才成功迁移所有文件。(我当时没有计数,因为起初我以为是在调试本地 bug。)我预计需要重复运行此迁移,使用相同的限制,直到诊断结果干净为止。因此,我仅在设置了 max 时才打印详细的进度信息,但无论如何都会打印有用的警告消息。
目前,我正在使用以下针对 Discourse Spaces 间歇性下载失败的变通方法,在实践中这极大地提高了我的成功率(到目前为止,在数百个迁移帖子中,3 次重试已完全足够)。
https://github.com/johnsonm/discourse/commit/7dfac12a2ea6ec04ba4e0616b4e0dbd1d806cff7
此外,我还发现,不知何故,我们在从 Google+ 导入时设置的限制内出现了超过限制的视频——在进行一些超大视频的单次迁移时,我不得不临时增加 SiteSettings.max_image_size_kb 和 SiteSettings.max_attachment_size_kb,因为这些视频是如何出现在站点上尚不清楚,但我不想现在破坏它们……我不知道允许超大上传的 bug 是出在我的导入脚本、Discourse 本身,还是仅仅是对我随时间对设置所做的更改的记忆有误。![]()
由于我迁移的许多内容是从 G+ 导入的,因此我的某些帖子未能通过当前的验证。我遇到了一些 Unhandled failure: Validation failed: Sorry, new users can only put one image in a post 错误,起初我不明白为什么它们没有再次出现。事实证明,上传已成功移动到本地,并且它们都使用了 upload: 伪协议,因此原始内容并未改变。然而,post.save! 仍然因验证失败而报错,这阻止了 post.rebake! 的执行,因此在我迁移的 3 万个帖子中,有少数帖子包含需要重新烘焙的图片;遗憾的是,我没有记录哪些帖子是这些。我现在已改用 post.save!(validate: false) 作为另一种修复方法,因此这个问题应该不会再次发生。我很高兴我在迁移开始时设置了遇到未处理错误即退出的机制,否则这可能会造成比几个帖子更多的损害。
…
为了在运行迁移期间保持站点可用(包括发送通知),我不想向 Sidekiq 队列发送大量垃圾消息。我知道命名是计算机科学中最难的两个问题之一,另外两个是缓存失效和差一错误,但我提议使用环境变量 DISCOURSE_MIGRATION_MAX_ENQUEUED 来控制在迁移过程中,在执行 rebake 后迁移下一个项目时,允许填充的总队列槽位(不是作业槽位)数量,以避免向队列发送垃圾消息,从而确保站点继续正常运行。我有一个补丁添加了此功能,默认值为零,用于 lib/tasks/uploads.rake 中所有每个帖子的重新烘焙操作。我已在生产环境的迁移中使用此功能。