Generating missing optimized images with S3

After our migration (back) to Amazon S3, we appear to have quite a few images where the optimized versions are missing, but the full-size ones are there (example).

There is a Rake task for regenerating optimized images, but it only appears to work with local storage. How would I do this with remote images?

A question for @zogstrip I think!

Still waiting for an update on this.

We have some quite noticeable missing post images, and had at least one broken scaled avatar…

I’m afraid you’ll have to write your own rake task for that. Here’s some pseudo code on how I’d start

FOR EACH oi IN optimized_images
   IF file_exists_on_s3?(oi.upload.url) AND NOT file_exists_on_s3?(oi.url) THEN
       OptimizedImage.create_for(oi.upload, oi.width, oi.height)
   END IF 
END FOR

@uppfinnarn Did you manage to solve this?

I just migrated to S3, and indeed the /optimized/ folder is not transferred in the migration. I’d like to get rid of the /optimized/ folder, as it adds significant weight to my daily backup.

I’m not sure if the following is complete, but this rails console command removes all optimized images then regenerates the ones used for avatars:

OptimizedImage.destroy_all
UserAvatar.all.each {|ua| uaid = ua.gravatar_upload_id || ua.custom_upload_id; Jobs::CreateAvatarThumbnails.perform_async(upload_id: uaid) if uaid }

В дополнение к команде выше, выполнение rake posts:rebake позволит заново сгенерировать все (или почти все) остальные отсутствующие оптимизированные изображения.

Команда, я застрял в ситуации, связанной с аватаром профиля, и это отняло у меня около 6 часов :frowning: но я нашёл идеальное решение, поэтому делюсь им здесь.

ХРАНИЛИЩЕ: Используем AWS S3 с CDN перед ним.

Проблема 1: Я мог загружать аватар профиля через раздел изменения аватара, но он не отображался в профиле. Я обновил свой код до последней версии Discourse, и аватар профиля начал отображаться в интерфейсе :slight_smile:

СТАРЫЙ КОД — аватар профиля не отображался


module FileStore

  class S3Store < BaseStore
     ...
    def path_for(upload)
      url = upload&.url
      if url && url[/^\/[^\/]/]
        FileStore::LocalStore.new.path_for(upload)
      else
        url
      end
    end
     ...
  end
end

РЕШЕНИЕ: ПОСЛЕДНИЙ КОД — аватар профиля начал отображаться для новых загрузок

module FileStore

  class S3Store < BaseStore
     ...
    def path_for(upload)
      url = upload&.url
      FileStore::LocalStore.new.path_for(upload) if url && url[/^\/[^\/]/]
    end
     ...
  end
end

Примечание: Пожалуйста, ребята, регулярно обновляйте свой код относительно ветки upstream Discourse, это будет поддерживать наш код в актуальном состоянии с исправлениями безопасности и без ошибок.

Проблема 2: Я и моя команда пытались менять аватары профиля до исправления вышеупомянутой ошибки в Проблеме 1. Это привело к созданию множества записей в таблице uploads со значением unknown в столбце extension. Код некорректно обрабатывал аватар профиля в процессе оптимизации изображений (МОДЕЛЬ: OptimizedImage) из-за неверного пути к файлу в S3.

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

Решение

Мульти-сайт
Мы можем запустить следующий код непосредственно в продакшн-консоли Rails — или используя rake-задачу.

RailsMultisite::ConnectionManagement.each_connection do |db|
  Upload.where(extension: "unknown").each do |upload|
    upload.update(extension: File.extname(upload.url).gsub(".",""))
  end
  OptimizedImage.destroy_all
  UserAvatar.all.each {|ua| uaid = ua.gravatar_upload_id || ua.custom_upload_id; 
  Jobs::CreateAvatarThumbnails.perform_async(upload_id: uaid) if uaid }
end

Обычный — Одиночный сайт
Мы можем запустить следующий код непосредственно в продакшн-консоли Rails — или используя rake-задачу.

Upload.where(extension: "unknown").each do |upload|
  upload.update(extension: File.extname(upload.url).gsub(".",""))
end
OptimizedImage.destroy_all
UserAvatar.all.each {|ua| uaid = ua.gravatar_upload_id || ua.custom_upload_id; 
Jobs::CreateAvatarThumbnails.perform_async(upload_id: uaid) if uaid }

Думаю, это поможет многим людям :slight_smile:

Спасибо

@supermathie Спасибо за совет. Если кажется, что все оптимизированные изображения для аватаров отсутствуют, достаточно ли, вероятно, просто выполнить вторую строку?

UserAvatar.all.each {|ua| uaid = ua.gravatar_upload_id || ua.custom_upload_id; Jobs::CreateAvatarThumbnails.perform_async(upload_id: uaid) if uaid }

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

вероятно, но код вполне мог измениться; я давно не смотрел это.

Я уточню…

Спасибо @supermathie, я ценю это! :slight_smile:

Я попробовал (только вторую строку), но, похоже, это не работает. Было возвращено много записей, например:

id: 1234,
user_id: 1234,
custom_upload_id: nil,
gravatar_upload_id: nil,
last_gravatar_download_attempt: Thu, 07 May 2015 09:40:35 UTC +00:00,
created_at: Thu, 07 May 2015 09:40:35 UTC +00:00,
updated_at: Thu, 07 May 2015 09:40:36 UTC +00:00>,

Я нашёл одну запись, где custom_upload_id был установлен в идентификатор, и нашёл профиль пользователя с помощью: User.find_by(id: 123456)

Однако при просмотре его профиля аватар всё ещё пустой. Кроме того, я вижу, что за последние 6 часов на S3 не было новых загрузок. Поэтому я не думаю, что оптимизированные изображения генерируются в результате этого.


Хорошая новость: когда я ищу аватар через команду rails:

User.find_by_username('username').uploaded_avatar

source

Записи выглядят корректно, и все проверенные мной URL-адреса S3 работают. Записи согласуются с другой инстанцией, которая использовала S3 с самого начала.

Затем, когда я использую:
OptimizedImage.where(upload_id: upload_id).where(version: 2)

В предыдущей инстанции я вижу множество оптимизированных изображений. Но в новой инстанции записей нет. Это кажется правильным. Для пользователя с установленным custom_upload_id на S3, похоже, есть оптимизированные изображения, но эти записи датированы несколькими днями назад.

Похоже, мне просто нужно найти способ запустить генерацию оптимизированных изображений аватара.

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


Редактирование: я вижу много заданий в sidekiq для создания миниатюр аватаров :slight_smile:

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

Я вижу, что в Sidekiq выполняется Jobs::CreateAvatarThumbnails. Однако в бакет S3 ничего не загружалось уже 9 часов. Поэтому непонятно, как это интерпретировать.