@RGJ, точно так же, я искренне считаю: если кто-то точно знает, как избежать бессмысленной траты времени на пересборку всех изображений, я только «за». И если бы я был опытным разработчиком Discourse и знал, как сделать это легко, я бы, скорее всего, сделал это изначально.
Мне кажется, что миграция с S3 — не частый случай для тех, у кого много изображений, поэтому это редко стоит затраченного времени по сравнению с добавлением более универсально полезных функций в Discourse. У меня было примерно 100 ГБ загрузок при импорте из Google+ в MakerForums. Мы выбрали S3, предполагая, что многие пользователи переместятся из тех сообществ в MakerForums, но в итоге активно перешли лишь несколько сообществ, так что дальнейший рост не оправдал пребывания на S3. Думаю, это довольно крайний случай, а повторная обработка изображений — это разовая затрата.
Наконец, я очень благодарен вам за то, что вы открыли эту тему, иначе я мог бы легко пропустить загрузки, не связанные с постами.
…
@RGJ, вы совершенно правы: уничтожение и повторное создание — это плохо. Я добавил проверку: raise "Ошибка: URL загрузки #{url} изменился на #{new_upload.short_url}, должен остаться без изменений." if url != new_upload.short_url, которая хотя бы сообщает о проблемах с повреждённым источником. Сегодняшнее сбой в Digital Ocean Spaces привёл к тому, что мне были переданы повреждённые данные, и это вызвало эту ошибку для множества загрузок — не знаю, для скольких. Но поскольку старая загрузка уже была уничтожена, у меня теперь есть повреждённые страницы, и я не заметил этого до тех пор, пока не потерял историю вывода логов, где было указано, какие страницы повреждены. Поэтому я даже не могу зайти и исправить их вручную из резервной копии.
Так что, хотя моя работа является улучшением по сравнению со старым способом, поскольку она хотя бы сообщает об ошибках, было бы гораздо лучше скачивать файлы, проверять SHA1 скачанных файлов и записывать их в локальные файлы. Тем временем я модифицировал свой PR, чтобы миграция останавливалась при любой необработанной ошибке, что хотя бы ограничивает потерю данных.
Я всё ещё считаю, что мою работу следует объединить, так как это улучшение по Парето: она не делает хуже, но делает лучше. Однако было бы гораздо лучше сделать это правильно. Я думаю, что правильным подходом было бы написать lib/file_store/from_s3_migration.rb, параллельно lib/file_store/to_s3_migration.rb, но у меня нет на это сил.
Поскольку мой PR ещё не был рассмотрен, я добавил в него ещё больше. Я добавил задачу uploads:report_missing_uploads, которая просматривает raw на наличие вхождений upload://..., где объект загрузки отсутствует. По крайней мере в моём случае, благодаря резервным копиям, я смогу просмотреть их, найти потерянные файлы и восстановить их на сайте, а затем пересобрать соответствующие посты, чтобы вернуть отсутствующие изображения. Я нашёл 678 таких случаев для поиска в резервных копиях, из которых пока нашёл все, кроме 10, так что рад, что написал этот тест! Мне нужно разобраться с этим, прежде чем переходить к этапу пересборки оставшихся постов.
…
Я завершил первый этап миграции, не включая пересборку затронутых постов с общими загрузками и не включая загрузки, не связанные с постами. После создания ещё одной удалённой резервной копии я планирую протестировать эти функции и добавить их в свой PR.
…
Теперь я начал тестирование следующих этапов миграции: пересборки и миграции загрузок, не связанных с постами. Первый урок: пересборка на следующем этапе не удаётся из-за аватаров, не связанных с постами, в цитируемых постах, поэтому пересборка постов должна быть последним шагом.
Следующее открытие: спасибо ограничениям внешнего ключа! При миграции загрузок, не связанных с постами, я обнаружил, что нужно мигрировать хотя бы профили перед общей миграцией таких загрузок.
ActiveRecord::InvalidForeignKey: PG::ForeignKeyViolation: ERROR: update or delete on table "uploads" violates foreign key constraint "fk_rails_1d362f2e97" on table "user_profiles"
Миграция профилей была сложной, потому что мне пришлось мигрировать две загрузки, привязанные к профилю, но в некоторых случаях люди использовали одно и то же изображение для обоих, поэтому эту работу пришлось выполнять в три этапа. Я успешно мигрировал все профили на моём сайте, используя URL S3.
Я мигрировал все загрузки, не связанные с постами и профилями. @RGJ, если вы хотите попробовать ветку, которую я опубликовал, она обновлена с учётом моей работы. Всё, что в ней есть, уже использовалось для завершённой миграции сайта.
…
@cvx, я не знаю, когда у вас появится возможность провести обзор, но без моего PR migrate_from_s3 определённо полон ошибок, ведущих к тихому уничтожению данных. То, что я сделал, не идеально, но это защищает от многих ошибок, с которыми я столкнулся на практике.
Я выполнил всю работу, которую планировал сделать здесь. Я мигрировал свой сайт, поэтому даже не могу эффективно оценить запрошенные изменения. Если вы отклоните этот PR, я настоятельно рекомендую вместо этого удалить существующую миграцию, так как она будет тихо уничтожать данные пользователей.
Что касается PR: иногда у меня возникают сбои тестов в CI (в текущей версии), что-то вроде этого:
7867 examples, 0 failures, 11 pending, 1 error occurred outside of examples
##[error]Process completed with exit code 1.
Это не воспроизводится у меня локально (пока), и в логах CI нет никакой информации о том, что не так, поэтому я не собираюсь тратить больше времени на попытки разобраться в скрытой информации в выводе CI.
Последнее замечание: после завершения миграции мы обнаружили, что некоторые аватары пользователей были утеряны в процессе миграции, и они восстанавливают их вручную. Я предполагаю, что для успешного выполнения этого потребовался бы дополнительный код, но поскольку я понял это слишком поздно, у меня нет тестового случая для проверки этого. Таким образом, это остающаяся ошибка, которая может проявиться в некоторых конфигурациях, но я больше не в состоянии написать соответствующее исправление.