3
1

FaradayでHTTPリクエストのリトライ処理を実装する

Last updated at Posted at 2023-10-08

はじめに

Railsのプロジェクトに限ったことではないですが外部のAPIを呼び出すはよくあることだと思います.
RubyにはいくつかHTTPクライアントのGemがありRailsのプロジェクトで利用できますが今回はFaradayというGemを用います。
APIが構えてあるサーバやAPIまでのネットワークなど一時的な高負荷などが原因でAPIへのリクエストが失敗したときに同じ内容のリクエストをかけたいケースがあります.
Faradayを用いることでリトライの処理が簡単に記述できるので紹介していきます。

インストール

Gemfile
gem 'faraday'

or

console
gem install faraday

faraday-retry

Faradayでリトライを実装する場合faradayのとは別にfaraday-retryが必要です.

Gemfile
gem 'faraday-retry'

or

# console
gem install faraday-retry

ver 1.x vs 2.x

faradayの(2023/10/08)最新のバージョンは2.7.11ですが1系であればfaradayをインストールすればfaraday-retryがバンドルされてきますが2系の場合、別途faraday-retryをインストールする必要があるようです.
インストールするfaradayのバージョンによって設定が異なるので注意が必要です.

Gemfile.lock

v1.10.0

Gemfile.lock
# === 略 ====
    faraday (1.10.0)
      faraday-em_http (~> 1.0)
      faraday-em_synchrony (~> 1.0)
      faraday-excon (~> 1.1)
      faraday-httpclient (~> 1.0)
      faraday-multipart (~> 1.0)
      faraday-net_http (~> 1.0)
      faraday-net_http_persistent (~> 1.0)
      faraday-patron (~> 1.0)
      faraday-rack (~> 1.0)
      faraday-retry (~> 1.0)
      ruby2_keywords (>= 0.0.4)
    faraday-em_http (1.0.0)
    faraday-em_synchrony (1.0.0)
    faraday-excon (1.1.0)
    faraday-httpclient (1.0.1)
    faraday-multipart (1.0.4)
      multipart-post (~> 2)
    faraday-net_http (1.0.1)
    faraday-net_http_persistent (1.2.0)
    faraday-patron (1.0.0)
    faraday-rack (1.0.0)
    faraday-retry (1.0.3)
# === 略 ====

v2.7.11

Gemfile.lock
# === 略 ====
    faraday (2.7.11)
      base64
      faraday-net_http (>= 2.0, < 3.1)
      ruby2_keywords (>= 0.0.4)
    faraday-net_http (3.0.2)
# === 略 ====

プログラムを書く

実際にプログラムを書いてリトライの挙動を確認してみます.
今回は簡単なAPIを作成して試してみます.
(命名は適当なので気にしないでください)

リクエストする側

indexを呼ぶとfaradayでリクエスト処理が記述されたメソッドを呼びます.
リクエスト結果のステータスが408だった場合にリトライを最大5回するように設定してあります.
Faradayのインスタンスをnewする際にretry用の設定を引数として渡してやればOKです.

特定の例外が発生した場合にリトライされるようにもできます.

show_controller.rb
class ShowController < ApplicationController

  def index
    response = api_request
    render json: response
  end
  
  private 

  def api_request
    retry_options = { # リトライの設定
      max: 5,
      interval: 0.05,
      interval_randomness: 0.5,
      backoff_factor: 2,
      methods: %i[get post],
      retry_statuses: [408]
    }

    connection = Faraday.new(url: "http://localhost:3001", headers: { 'Content-Type' => 'application/json' } ) do |f|
      f.request :retry, retry_options
      f.response :logger, Rails.logger
      f.adapter Faraday.default_adapter
    end

    res = connection.post('/server/api') do |req|
      req.headers['Content-Type'] = 'application/json'
      req.body = { hoge: 100 }.to_json
    end
    res
  end
end

API側

ほぼ何もしないAPIですが408を返して強制的にタイムアウト判定させてfaradayにリトライさせます.

server_controller.rb
class ServerController < ApplicationController
  def api
    render json: { hogehoge: 'api' }, status: 408
  end
end

実行

上のウィンドウでshow/indexcurlで呼び出してFaradayにリクエストさせています.
APIは必ず408ステータスを返すのでタイムアウトになりリトライをします.
api_requestにメソッドにループや例外処理がないのにAPI側に5回リクエストされた形跡がありFaradayがリトライしたことが伺えます.

qiita_curl.gif

まとめ

Faradayを用いたHTTPリクエストのリトライ処理を紹介しました、Faradayは高機能で他にも色々な機能があります.
Faradayを導入する場合、単なるHTTPのクライアントとしてのみ使うともったいないので数ある機能を深掘りして活用してくようにしたいです。

3
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
1