CarrierWaveでリトライを実装する
CarrierWave経由でS3にファイルをアップロードしているとたまにS3から503が返ることがあります。
呼び出し元でリトライ処理を行っても良いのですがリトライの範囲を間違うと大変なのと毎回呼び出し元でリトライを意識させるのも難しいと思いCarrierWave側でリトライするようにできないか試してみました。
ソースコード
fukata/study-carrierwave-retryable
使い方
CarrierWave::Storage::Fog
を継承して必要なメソッドでリトライさせるようにしました。
リトライの条件などはアプリケーションに合わせて変更した方が良いと思います。
class RetryableStorageFog < CarrierWave::Storage::Fog
def store!(file)
retryable(__method__) { super }
end
def cache!(new_file)
retryable(__method__) { super }
end
def retrieve_from_cache!(identifier)
retryable(__method__) { super }
end
def retrieve!(identifier)
retryable(__method__) { super }
end
private
def retryable(method_name)
retryable_options = {
tries: 5,
sleep: lambda{|retries|
retries += 1
sleep_seconds = 2**retries
Rails.logger.warn("[RetryableStorageFog##{method_name}] sleep=#{sleep_seconds}, retries=#{retries}")
sleep_seconds
},
on: [StandardError],
}
Retryable.retryable(retryable_options) do |retries, e|
if retries > 0
Rails.logger.warn("[RetryableStorageFog##{method_name}] retries=#{retries}, e=#{e}")
end
yield
end
end
end
あとはUploaderに指定するだけです。
class ImageUploader < CarrierWave::Uploader::Base
storage RetryableStorageFog
cache_storage RetryableStorageFog
end
fog-aws v3.19.0 以上の場合
fog-aws v3.19.0 からリトライに関するデフォルトのオプションが追加されたのでアプリ側で対応する必要はなさそうです。
https://t.co/GVQimrXqhT
— rajyan (@rajyan_k) May 18, 2023
carrierwaveのS3へのアップロードに失敗することがあって、リトライの実装について調べてhttps://t.co/73xvDuZb67
やhttps://t.co/ABqLoFdtNu
を見ていたが、よくよく調べてみると実はfogのクライアントですでにリトライされていたのでリトライを改善した話