За годы мы столкнулись с множеством проблем при миграции на S3, включая неявные миграции при восстановлении резервной копии.
EXCEPTION: 8 posts are not remapped to new S3 upload URL. S3 migration failed for db 'default'.
Вот лишь некоторые примеры:
- False positives on "posts are not remapped to new S3 upload URL"
- Restore process cancelled at migrating uploads to S3 step
- Restore to New Host
Сегодня я столкнулся с ещё одним таким случаем, и, поскольку был пятница, решил разобраться в проблеме, вместо того чтобы просто закомментировать проверку.
Итак, у нас следующая ситуация:
- у нас мульти-сайт
- предположим, что имя базы данных —
dbname - у нас установлен параметр
S3_CDN_URL - у нас не установлен параметр
CDN_URL
Вот что происходит в файле /lib/file_store/to_s3_migration.rb.
Сначала определяется префикс:
prefix = @migrate_to_multisite ? "uploads/#{@current_db}/original/" : "original/"
Затем файлы загружаются в S3, и после этого выполняется переназначение ссылок, что по сути выглядит так (с некоторыми вариациями):
from = "/uploads/#{@current_db}/original/"
to = "#{SiteSetting.Upload.s3_base_url}/#{prefix}"
Таким образом, в случае мульти-сайта переназначение происходит:
- с
/uploads/dbname/original/ - на
https://bucket-location-url.com/uploads/dbname/original/
И, наконец, выполняется проверка:
cdn_path = SiteSetting.cdn_path("/uploads/#{@current_db}/original").sub(/https?:/, "")
count = Post.where("cooked LIKE '%#{cdn_path}%'").count
if count > 0
error_message = "#{count} posts are not remapped to new S3 upload URL. #{failure_message}"
raise_or_log(error_message, should_raise)
success = false
end
Теперь SiteSetting.cdn_path берётся из lib/global_path.rb и выглядит так:
def cdn_path(p)
GlobalSetting.cdn_url.blank? ? p : "#{GlobalSetting.cdn_url}#{path(p)}"
end
Итак, если у нас есть CDN для S3, но нет обычного CDN, то SiteSetting.cdn_path("/uploads/#{@current_db}/original") будет просто /uploads/dbname/original.
А согласно нашему переназначению, новые пути — https://bucket-location-url.com/uploads/dbname/original/.
Это означает:
cdn_pathявляется подстрокой нового целевого пути;- следовательно,
Post.where("cooked LIKE '%#{cdn_path}%'").countвсегда будет находить посты; - система ложно сработает и прервёт процесс
