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?

「いいね!」 2

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…

「いいね!」 1

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
「いいね!」 1

@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 }
「いいね!」 4

上記のコマンドの続きとして、rake posts:rebake を実行すると、他の欠落している最適化された画像がすべて(?)再生成されます。

「いいね!」 4

チームの皆様、プロフィール写真に関する状況でつまずき、約 6 時間を無駄にしてしまいました :frowning: ですが、完璧な解決策を見つけましたので共有します。

ストレージ: AWS S3を使用し、その前面にCDNを配置。

問題 1: プロフィール写真変更画面からプロフィール写真をアップロードすることはできましたが、プロフィールに反映されませんでした。コードを最新のDiscourseに更新したところ、UI 上でプロフィール写真が表示されるようになりました :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

注意: 皆様、定期的に自身のコードをDiscourse のアップストリームに更新してください。そうすることで、セキュリティ修正やバグ修正が常に反映され、コードが最新の状態に保たれます。

問題 2: 上記の問題 1で述べたバグを修正する前に、私と私のチームはプロフィール写真の変更を試みました。その結果、uploads テーブルに多数のエントリが作成され、extension カラムの値がunknownとなっていました。コードが誤った S3 ファイルパスのため、画像最適化プロセス**(MODEL: OptimizedImage)プロフィール写真**を正しく処理できていなかったのです。

そのため、コード修正前に発生したこのようなエントリを修正するための回避策も発見しました。

解決策

マルチサイト
以下のコードを本番環境の 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:

ありがとうございました

「いいね!」 2

@supermathie ご助言ありがとうございます。アバターの最適化画像がすべて欠落しているように見える場合、2 行目を実行するだけで十分でしょうか?

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

すでに投稿のリベイクは完了しており、それにはかなり時間がかかりました。可能であれば、既存の投稿画像の最適化ファイルを削除したくないと考えています。

「いいね!」 2

おそらくですが、コードが変更されている可能性も十分にあります。私はしばらく見ていませんでした。

周りにも聞いてみます…

「いいね!」 1

@supermathie さん、ありがとうございます!:slight_smile:

早速試してみましたが(2 行目のみ)、うまくいかないようです。以下のようなレコードが多数返ってきました:

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 に ID が設定されているレコードを 1 つ見つけ、User.find_by(id: 123456) でそのユーザーのプロフィールを取得しました。

しかし、プロフィールを表示するとアバターはまだ空のままです。また、S3 には最近(過去 6 時間以内)に新しいアップロードが行われていないことも確認できました。つまり、最適化された画像が生成されていないようです。


良い知らせとしては、Rails コマンドでアバターを検索すると以下のようになります:

User.find_by_username('username').uploaded_avatar

source

レコードは正しく、確認したすべての S3 URL も機能しています。これらのレコードは、最初から S3 を使用していた別のインスタンスと一致しているようです。

次に、以下のコマンドを実行しました:
OptimizedImage.where(upload_id: upload_id).where(version: 2)

以前のインスタンスでは最適化された画像が多数表示されますが、新しいインスタンスではレコードがありません。これは正しいようです。custom_upload_id が設定されているユーザーについては、S3 上に最適化された画像が存在するようですが、それらのレコードは数日前のものです。

つまり、最適化されたアバター画像の生成をトリガーする方法を見つける必要があるようです。

新しいインスタンスは現在読み取り専用モードになっていますが、これが要因かもしれません。読み取り専用モードでも投稿の再構築は正常に動作していました。


追記:Sidekiq にアバターサムネイル作成のジョブが多数あることに気づきました :slight_smile:

もしかすると、読み取り専用モードを解除して処理を許可するだけで済むかもしれません。追記します。

Jobs::CreateAvatarThumbnails が Sidekiq で実行されているようですが、S3 バケットには9時間以上アップロードが行われていません。この状況についてどう判断すればよいのか、わかりません。