Migrate_from_s3 problems

When migrating from S3 to local storage, we see a number of issues.

The main issue is that the migrate_from_s3 rake task is not taking the Uploads table as a starting point, but the posts. This causes it to skip a lot of uploads which are being left on S3.

  • uploads used as logo’s because they are not referenced in a post
  • uploads for avatars because they are not referenced in a post
  • uploads that are (for some reason) referenced by their CDN URL in raw because they do not match the regex that is being used to identify the uploads
  • uploads that are on non-AWS S3 storage because they do not match the regex because it requires amazonaws in the URL
  • uploads that for some reason do not match the second, different regex (we’re seeing this with non-image uploads like mp3 files, not sure why this is happening)
2 лайка

We’re working on improving the way we associate uploads to posts (by using the upload:// scheme) that will make these storage migrations much more bulletproof. There’s little point to fixing these rake tasks before that’s done.

7 лайков

Недавно я создал новый PR, позволяющий мигрировать посты меньшими порциями (например, по одному для тестирования), и добавил тесты для этой задачи.

Кажется логичным начать с постов, поскольку после каждой миграции необходимо пересоздавать посты (re-bake), чтобы обновить URL в скомпилированном содержимом. Если сначала мигрировать все вложения, а затем запускать пересоздание, сайт может оставаться неработоспособным в течение длительного времени, особенно для крупных проектов (мне нужно перенести около 100 ГБ из S3 на локальное хранилище, поэтому для меня это важно). Однако написанное мной может помочь начать разработку задачи migrate_uploads_from_s3, которую следует запускать после migrate_from_s3, чтобы очистить вложения, не связанные с постами.

@zogstrip Каков текущий статус фразы «Мы работаем над…» — всё ещё всё меняется или эта миграция уже заслуживает внимания?

5 лайков

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

Эти задачи миграции можно улучшать по желанию :+1:

2 лайка

Я узнаю, стоит ли мне тратить время на изучение загрузки не-постов, после того как смогу использовать пакетную загрузку для миграции моего сайта в нерабочее время! :smiling_face: Спасибо за ревью PR!

1 лайк

Далее у меня есть два вопроса: во-первых, лимит полезен, но он ограничивает только пространство поиска; во-вторых, я хочу иметь возможность указывать максимальное количество сообщений для изменения. Поэтому я планирую добавить ограничение на максимальное число сообщений для изменения, а также лимит для запроса.

Кроме того, при указании max имеет смысл подробно описывать, что именно обрабатывается, в целях отладки. Поэтому я хочу сделать вывод подробным, если max не равен nil — это позволит пользователям проверять процесс перед продолжением, так как это основной сценарий использования данной работы.

Я думаю, что буду передавать max как первый аргумент, а опциональный limit — как второй, потому что max действительно является наиболее важным параметром; limit же нужен лишь для того, чтобы сделать «один запрос» дешевле.

Второй вопрос касается не-загрузок: загрузок. Более года назад я пытался загрузить видео на сайт Discourse, к которому присоединился, пока путался в попытках разобраться, как написать миграцию с Google+ на Discourse, и увидел, что сгенерированная ссылка выглядела так: https://#{SiteSettings.absolute_base_url}/original/3X/b/a/ba9e06ebc2f4397f26793bb5cd4e169308dd371d.mp4.

Сегодня же при загрузке видео я получаю что-то вроде: ![file_example_MP4_480_1_5MG|video](upload://caJ9ykkpshw3PFK4464VUIPWJ4l.mp4).

По крайней мере, в моём последнем тесте migrate_from_s3 полностью исказил эти URL-адреса, превратив их даже не в URL, так что это определённо нужно исправить. Затем, я считаю, что на практике эта задача вряд ли столкнётся с ![text](non-upload-url-to-migrate), поэтому на первом этапе я хочу просто добавить разметку ссылки вокруг магического протокола upload, вместо того чтобы заставлять регулярное выражение обрабатывать оба случая, что ещё больше усложнило бы его чтение. Хотя я могу передумать.

Похоже, что тег video или audio добавляется в JavaScript через соответствие регулярному выражению, поэтому мне придётся скопировать регулярные выражения из app/assets/javascripts/discourse/app/lib/uploads.js в задачу, чтобы правильно их идентифицировать. Я включу исходный код регулярных выражений, чтобы следующий человек, который их найдёт, знал, откуда их обновлять. :stuck_out_tongue:

Сегодня вечером я выделил время на эту работу и начал работу над черновиком PR. Он ещё не завершён; я знаю, что в нём остались ошибки. На данный момент я не изменил поведение для URL-адресов псевдопротокола upload: (обычно для изображений), хотя добавил проверку на корректность.

Благодаря изменениям в этом PR я успешно мигрировал как обычные загрузки псевдопротокола upload:, так и видео, которые в настоящее время явно ссылаются на S3 (в моём случае — на DigitalOcean Spaces). Я использую это для изменения только одного сообщения за раз с помощью следующей команды:

bin/rake uploads:batch_migrate_from_s3[1,1000]

Обратите внимание, что эта команда не перейдёт дальше первых 1000 сообщений, возвращаемых somewhat случайно из запроса к базе данных; низкий лимит установлен лишь для ускорения выполнения запроса при миграции одного сообщения за раз, проверке корректности поведения этого сообщения и последующем повторном запуске для поиска следующего. Эта команда работает таким образом только с моим текущим PR!

Я продолжаю добавлять диагностический вывод по мере работы над этим и начинаю думать, что это важно не только для разработки. Я наблюдаю множество временных сбоев загрузки из DigitalOcean Spaces, когда часть файлов в сообщении мигрируется, а часть — нет. В оригинале это просто печатает . и продолжает работу, затем говорит Done, но на самом деле задача не выполнена. Мне пришлось сделать около пяти-шести проходов по одному сообщению, прежде чем все файлы были мигрированы. (Я не считал, потому что сначала думал, что отлаживаю локальную ошибку.) Я ожидаю, что мне придётся запускать эту миграцию неоднократно с тем же лимитом, пока диагностические данные не станут чистыми. Поэтому я делаю подробный вывод прогресса только если установлен max, но вывожу полезные предупреждающие сообщения в любом случае.

В настоящее время я использую следующий обходной путь для периодических сбоев загрузки в Discourse Spaces, который на практике значительно повысил мой процент успеха (трёх повторных попыток оказалось вполне достаточно для сотен мигрированных сообщений).

https://github.com/johnsonm/discourse/commit/7dfac12a2ea6ec04ba4e0616b4e0dbd1d806cff7

Также я обнаружил, что somehow у нас оказались видео больше установленного мной лимита при импорте с Google+. Мне пришлось временно увеличить SiteSettings.max_image_size_kb и SiteSettings.max_attachment_size_kb во время одноразовой миграции нескольких видео с избыточным размером, хотя мне неясно, как они вообще оказались на сайте. Я не хочу ломать их сейчас… Не знаю, была ли ошибка, позволявшая загружать файлы избыточного размера, в моём скрипте импорта, в Discourse или просто в моей памяти о том, какие изменения я вносил в настройки со временем. :wink:

Поскольку значительная часть того, что я мигрирую, была импортирована с Google+, некоторые мои сообщения не прошли текущие проверки валидации. Я получил несколько ошибок Unhandled failure: Validation failed: Sorry, new users can only put one image in a post и сначала не понял, почему они не повторяются. Оказалось, что загрузки успешно перемещены на локальное хранилище, и все они использовали псевдопротокол upload:, поэтому сырое содержимое не изменилось. Однако post.save! всё равно завершался ошибкой валидации, что предотвращало вызов post.rebake!, поэтому у меня есть несколько сообщений из 30 тысяч с изображениями, которые требуют повторной обработки; к сожалению, у меня нет записи о том, какие именно это сообщения. Теперь я перешёл на post.save!(validate: false) как ещё одно исправление, так что эта конкретная проблема больше не должна возникать. Я очень рад, что миграция начала прерываться при необработанных ошибках, иначе это могло бы нанести гораздо больший ущерб, чем несколько сообщений.

Чтобы мой сайт оставался работоспособным, включая отправку уведомлений, во время выполнения миграции, я не хочу перегружать очереди Sidekiq. Я знаю, что именование — одна из двух самых сложных задач в информатике, наряду с инвалидацией кэша и ошибками off-by-one, но я предлагаю использовать переменную окружения DISCOURSE_MIGRATION_MAX_ENQUEUED для ограничения общего числа заполненных слотов очереди (не слотов задач), которые могут быть заняты при переходе к миграции следующего элемента после rebake во время миграции, чтобы избежать перегрузки очередей и обеспечить продолжение работы сайта. У меня есть патч, добавляющий это значение по умолчанию равным нулю для всех операций повторной обработки сообщений в lib/tasks/uploads.rake. Я использую это в своей производственной миграции.

https://github.com/discourse/discourse/blob/59a761851b9c8786d3a9692f8c595372b0534f77/lib/tasks/uploads.rake

4 лайка

@zogstrip Не могли бы вы просмотреть этот PR, так как у вас есть контекст от недавнего ревью моего предыдущего PR в этой области? FIX: Make migrations from S3 more robust; fix bare URL migration by johnsonm · Pull Request #10093 · discourse/discourse · GitHub

Я включил в него исправления, которые я внедрял во время выполнения этой относительно крупной миграции. Я не пытался добавить тесты для каждого исправления; я не уверен, как внедрить каждую форму ошибки. Но по крайней мере новая функциональность протестирована.

@RGJ Мне кажется, что мой PR в текущем виде может решить все, кроме ваших первых двух пунктов, за исключением того, что я не уверен насчет CDN. Мой сайт использовал CDN и мигрировал видео с URL-адресами CDN, но это могло быть побочным эффектом именования с Discourse Spaces. Если у вас есть дополнительные случаи, надеюсь, мой PR даст вам простую основу для добавления в регулярное выражение и добавления тестовых случаев для дополнительных вариантов.

Я считаю, что правильно сначала мигрировать по постам, потому что после миграции загрузок в посте пост нужно перекомпилировать (re-bake), чтобы в обработанном посте были правильные URL-адреса. После того как я закончу миграцию своих постов (что может занять менее двух недель, теперь, когда я изменил ограничение скорости, чтобы проверять длину очереди напрямую), я займусь любой оставшейся работой по очистке.

Поскольку несколько постов могут содержать ссылки на один и тот же контент, если более одного человека загрузили один и тот же файл, необходим второй проход, который проверит обработанные данные на наличие старых URL-адресов и перекомпилирует эти посты, чтобы получить новые расположения. Он может использовать то же ограничение скорости, чтобы не перегружать очереди.

Вероятно, я не увижу сломанных логотипов на MakerForums, так как мы изменили брендинг после того, как перестали добавлять новый контент в “s3” (для нас это DigitalOcean Spaces), но, скорее всего, я увижу множество загрузок, все еще находящихся в S3, по крайней мере для аватаров. Миграция загрузок, не связанных с постами, должна быть начата только после миграции всех постов, и, вероятно, мне придется описать это после завершения миграции загрузок в постах.

@pfaffman Я вижу Bizarre Problems with migrate_from_s3 - #5, где описываются ошибки, которые не повторялись. Без моих исправлений в текущем PR ошибки молча поглощаются, включая сбои валидации. Я думаю, что работа здесь решит хотя бы некоторые из проблем, которые вы тогда наблюдали.

@hosna Проблемы, которые вы подняли в https://meta.discourse.org/t/what-does-rake-uploads-migrate-from-s3-exactly-do/97285, частично или полностью решены в этом PR. Если они решены не полностью, я добавил тесты, которые упростят добавление дальнейших тестов для проверки дополнительных исправлений.

@sam Поскольку вы поставили метку 2.6 на PR, я предполагаю, что он не будет слит как минимум в течение нескольких дней; мне ли перенести свою работу по функции ограничения скорости в этот PR вместе с исправлениями? Или у вас есть предпочтение держать исправления и работу над функциями в отдельных PR? Я могу сделать любым способом. Функция ограничения скорости работает очень хорошо; я мигрирую примерно в три раза быстрее, без влияния на доступность сайта, теперь, когда я жду, пока очередь Sidekiq опустеет, поэтому, думаю, имеет смысл включить её, если это обычно принимается в PR. В противном случае мне придется ждать слияния PR, на котором основана эта работа, так что в любом случае было бы хорошо услышать ваше мнение.

..

Я убрал дублирование в своем патче ограничения скорости миграции и включил его в PR. Он работает на практике, и sar показывает, что я наблюдаю почти нулевое время простоя непрерывно, в то время как сайт продолжает функционировать во время живой миграции. Одним из преимуществ режима пакетной обработки является то, что я могу проверять наличие новых версий Discourse после каждой полной партии миграций; я обновил свой сайт до 2.6.0beta1 при первой возможности после его выпуска и успешно выполнял миграции на 2.6.0beta1 с моим PR миграции поверх него с момента обновления.

Я считаю, что PR готов к ревью сейчас; я планирую отправить еще один PR для последних нескольких этапов, но внедрение этого улучшит общий опыт миграции для всех еще до того, как я завершу последние части.

5 лайков

Что ж, это было очень давно…

Я с нетерпением жду решения этой проблемы. В данный момент у меня есть несколько сайтов в мультисайтовой сети, которым нужно извлекать изображения из S3 (сейчас, кажется, некоторые изображения локальные, а другие находятся в S3), а затем загружать их в S3.

1 лайк

@pfaffman Вероятно, это к лучшему, что когда я начинал свой проект миграции, я не знал того, что, как мне теперь кажется, я уже понял. Похоже, если бы я использовал minio client для копирования всего ведра S3 в локальную папку uploads, изменил все Upload.url на nil в консоли Rails и пересобрал сайт, вся миграция заняла бы часы без необходимости заново генерировать все изображения. (Вместо этого я ограничен скоростью из-за повторного выполнения всех конвертаций изображений, словно локальный процессор дешевле, чем простое копирование всех обработанных изображений из S3.)

И если бы всё было так просто, я бы не проделывал эту работу, чтобы сделать миграции в целом более надёжными, и никто другой не получил бы от этого пользы. :smiling_face:

4 лайка

Ох. Похоже, это именно то, что мне нужно знать. Возможно, я попробую это сделать.

1 лайк

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

О, и ещё один момент: это полностью не сработало бы для загрузки аудио и видео, и я бы не заметил этого до поры до времени, а потом мне пришлось бы разбираться и писать собственный код. Так что, если у вас есть загрузка аудио и видео, вам определённо стоит начать с этого. Без открытого PR, который не будет принят до релиза версии 2.5, так как @sam пометил его как 2.6, всё не будет работать правильно.

2 лайка

Приношу извинения за то, что присоединился к обсуждению так поздно. Я только что посмотрел ваш PR и хотел бы узнать, почему вы воссоздаете модель Upload вместо того, чтобы просто изменить её URL? И почему бы не пройтись по OptimizedImages и не сделать то же самое?

2 лайка

@RGJ Я вообще ничего не менял; переделка Upload — это исправление ошибки от @zogstrip, описанное здесь: Cannot execute the rake uploads:migrate_from_s3 - #11

Я просто пытаюсь заставить работать код, который уже был, но плохо знаком с внутренним устройством Discourse; я долго действовал вслепую. Мой опыт работы с Ruby ограничивается несколькими моими PR для Discourse. Следование паттернам существующего кода, как мне кажется, не самый эффективный путь (см. мою переписку с @pfaffman выше о коротком замыкании), и я полностью согласен. Как видно из того, что даже сегодня утром я не сразу понял, что OptimizedImages.url тоже нужно изменить на путь /uploads, а etag установить в nil (и, возможно, ещё что-то), я всё ещё действовал вслепую.

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

По вашим первым двум замечаниям, касающимся обновлений, не связанных с постами, вот моя работа в процессе, ещё не протестированная на рабочем сайте (коммит), которая, возможно, поможет. Однако я приступлю к тестированию на своём рабочем сайте только после завершения миграции загрузок в постах.

Я хотел лишь немного подправить то, что раньше работало. Если вы хотите реализовать более быструю миграцию — я только «за». Возможно, имеет смысл сначала объединить мою более медленную, но всё же улучшенную версию как парето-улучшение, а затем полностью заменить её на что-то гораздо лучшее. Я буду первым, кто порадуется этому, даже если к тому моменту я уже не смогу использовать это решение.

1 лайк

@mcdanlj Спасибо за ваше объяснение. Я, правда, задавал вопрос, а не намекал на наличие каких-либо проблем сейчас. Не знаю, лучше ли предложенный мной способ — возможно, он создаст много новых проблем. Я полагаю, что код в его нынешнем виде, независимо от того, кто его написал, существует так по какой-то причине.

3 лайка

@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.

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

5 лайков

Поскольку мой PR, исправляющий тихое повреждение данных в migrate_from_s3, даже не был просмотрен, можно хотя бы документировать migrate_to_s3 как односторонний процесс?

Сейчас это, честно говоря, ловушка для новичков.

@cvx @zogstrip, что вы предпочитаете? Посмотреть на PR или просто полностью удалить migrate_from_s3 и честно заявить, что это односторонний процесс?

5 лайков

Извините, это моя ошибка. Я изучу PR на этой неделе.

7 лайков

Содержание ревью сводилось к тому, что текущий подход настолько ошибочен, что систему нужно полностью переписать с нуля и иначе; что попытка исправить её так, как было написано ранее, неприемлема. Я не готов к этому, поэтому считаю, что migrate_from_s3 следует удалить полностью, а для migrate_to_s3 явно указать, что это односторонний процесс, к которому вы должны быть готовы навсегда. Сейчас наличие migrate_from_s3 в исходном коде является нарушением целостности данных в Discourse.

Я не получил своевременного ревью во время работы над процессом миграции, а теперь, когда миграция уже завершена (с некоторыми ошибками, например, сломанными аватарами), у меня нет рабочей тестовой среды. У меня нет уверенности, что я смогу сделать это правильно, поэтому я отказался от этой борьбы. Теперь это задача следующего несчастного человека, который подумал, что хорошая идея — разместить изображения в каком-либо объектном хранилище, похожем на S3, чтобы решить проблему. Извините!

2 лайка

@CxV Поскольку вы отклонили предыдущую миграцию как выполненную полностью неверно и требующую начать заново, пожалуйста, проверьте и примите это исправление ошибки искажения данных:

2 лайка

Как уже отмечалось, я столкнулся с проблемами при выполнении миграции. Это подтверждает точку зрения @cvx о том, что я написал миграцию совершенно неправильно, и пока кто-то не исправит это, удаление существующей миграции, содержащей скрытую порчу данных, действительно должно быть объединено. (Это очень простой патч, проверка должна быть тривиальной. Чем раньше он будет объединён, тем меньше вероятность того, что кто-то разрушит свой сайт, пытаясь пройти назад через одностороннюю дверь. Не знаю, как ещё сильнее настоять на объединении; если бы знал — сделал бы. Редакция: Спасибо @cvx за одобрение, объединение и последующие действия, чтобы массовая миграция была помечена как необратимая.)

Вот известные проблемы, с которыми я столкнулся:

  • По крайней мере, аватар discobot не отображался; все участия discobot показывали общий аватар человека (светло-серая голова и плечи на белом фоне).
  • Аватары некоторых других пользователей были перенесены неправильно. Многие были исправлены вручную.
  • При настройке сайта первоначальный администратор экспериментировал с изменениями конфигурации «S3» (в нашем случае — DigitalOcean Spaces, с CDN и без), что привело к появлению некоторых сиротских оптимизированных изображений, которые не были исправлены в ходе миграции.

Для тех, кто пытался использовать мою ветку и столкнулся с исчезновением изображений, я применил хак в консоли Rails, который исправил некоторые вещи. Это не правильный способ сделать это, я просто недостаточно хорошо знаком с моделью, чтобы сделать это правильно. Мой уровень владения Ruby очень слаб; я не работаю с Ruby вне своих небольших вкладов в Discourse.

Тем не менее, этот ужасный хак исправил повреждённые изображения (из-за ошибок первоначальной конфигурации) и, по крайней мере, вернул аватар discobot (и, возможно, другие, но все те, о которых я знал ранее, уже были исправлены).

Здесь не показано всё, что я делал между шагами, просматривая каждый набор по мере продвижения. Это было частью сессии «изучить, что есть в консоли Rails», а не скриптом, который я написал и выполнил. В нём нет обработки ошибок, и я сделал полную резервную копию сайта перед началом любой этой работы.

Я не знаю, как ещё сильнее подчеркнуть, что этот код не является идиоматическим способом выполнения такого ремонта в Ruby on Rails. Я просто хотел поделиться тем, как я исправил хотя бы часть ущерба, который нанёс себе при предыдущей попытке мигрировать свой сайт с DigitalOcean Spaces.

require 'set'

uploadids = Set.new
optimizedimages = Set.new
OptimizedImage.where("url like '%UNIQUEPARTOFS3URL%'").each do |oi|
  uploadids.add(oi.upload_id)
  optimizedimages.add(oi)
end

postids = Set.new
uploadids.each do |u|
  PostUpload.where(upload_id: u).each do |pu|
    postids.add(pu.post_id)
  end
end

optimizedimages.each do |oi|
  oi.delete
end

postids.each do |pid|
  Post.where(id: pid).each do |p|
    p.rebake!
  end
end
2 лайка