Skip to content

リトライとフォールトトレランス

デフォルトリトライ

go
cfg := httpc.DefaultConfig()
cfg.Retry.MaxRetries = 3           // 最大 3 回
cfg.Retry.Delay = 1 * time.Second  // 初期遅延 1s
cfg.Retry.BackoffFactor = 2.0      // 指数バックオフ 2x
cfg.Retry.EnableJitter = true      // ジッターを有効化

client, err := httpc.New(cfg)
if err != nil {
    log.Fatal(err)
}
defer client.Close()

デフォルトリトライ遅延シーケンス:1s → 2s → 4s(ランダムジッター含む)

リトライ条件

デフォルトでは、以下のエラーがリトライをトリガーします:

条件リトライ
ネットワークエラー(接続拒否、一時的/タイムアウト系 DNS 失敗など)はい
タイムアウトエラーはい
5xx サーバーエラー(500/502/503/504)はい
408 Request Timeout / 429 Too Many Requestsはい
その他の 4xx クライアントエラーいいえ
コンテキストキャンセルいいえ
設定検証エラーいいえ

カスタムリトライポリシー

RetryPolicy インターフェースを実装してリトライ動作を完全に制御します:

内部タイプ

RetryPolicy.ShouldRetry の resp パラメータのタイプ ResponseReader は内部インターフェース(internal/types パッケージに定義)であり、外部パッケージからは直接参照できません。カスタム RetryPolicyhttpc と同じモジュール内のパッケージで実装する必要があります。ほとんどのシナリオでは RetryConfig フィールドの設定で要件を満たせます。

go
// 注意:ResponseReader は内部タイプ(internal/types パッケージ)です。
// このコードは github.com/cybergodev/httpc モジュール内でのみコンパイル可能です。
// ほとんどのユーザーは RetryConfig と WithMaxRetries でリトライを設定してください。

type MyRetryPolicy struct {
    maxAttempts int
}

// リトライするかどうかを判定
func (p *MyRetryPolicy) ShouldRetry(resp ResponseReader, err error, attempt int) bool {
    if attempt >= p.maxAttempts {
        return false
    }
    // ネットワークエラーはリトライ
    if err != nil {
        return true
    }
    // 502、503、504 のみリトライ
    return resp.StatusCode() == 502 || resp.StatusCode() == 503 || resp.StatusCode() == 504
}

// リトライ遅延を返す
func (p *MyRetryPolicy) GetDelay(attempt int) time.Duration {
    return time.Second * time.Duration(attempt+1)
}

// 最大リトライ回数
func (p *MyRetryPolicy) MaxRetries() int {
    return p.maxAttempts
}

// カスタムポリシーを適用
cfg := httpc.DefaultConfig()
cfg.Retry.CustomPolicy = &MyRetryPolicy{maxAttempts: 5}

リクエストごとの制御

go
// 個別リクエストで 5 回リトライ
result, err := client.Get(url, httpc.WithMaxRetries(5))

// リトライを無効化
result, err := client.Get(url, httpc.WithMaxRetries(0))

// コンテキストタイムアウトと組み合わせ
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel()
result, err := client.Request(ctx, "GET", url, httpc.WithMaxRetries(3))

Retry-After サポート

HTTPC はサーバーが返す Retry-After レスポンスヘッダーを自動的に解析します:

go
// サーバーが返す:Retry-After: 120
// HTTPC は最大 60 秒待機してからリトライ(サーバー指定の 120s は安全上限の 60s に切り詰められます)

// サーバーが返す:Retry-After: Fri, 25 Apr 2026 12:00:00 GMT
// HTTPC は指定された時刻まで待機してからリトライ(現在時刻から 60s 超の場合は 60s に切り詰められます)

TIP

Retry-After はリトライ可能なすべてのレスポンス(408、429、500、502、503、504)で有効になり、指数バックオフ遅延より優先されます。

バックオフ戦略

指数バックオフ

go
cfg.Retry.BackoffFactor = 2.0
// 遅延シーケンス:delay, delay*2, delay*4, delay*8...

固定遅延

go
cfg.Retry.BackoffFactor = 1.0
// 遅延シーケンス:delay, delay, delay...

線形増加

go
// カスタム RetryPolicy の実装が必要:
// delay * (attempt + 1)
// 高度な例のカスタムリトライポリシーを参照

ランダムジッター

ジッターを有効にして「Thundering Herd」問題を回避:

go
cfg.Retry.EnableJitter = true
// 基本遅延にランダムなオフセットを追加し、全クライアントが同時にリトライするのを防止

エラー処理とリトライ

go
result, err := client.Get(url)
if err != nil {
    var clientErr *httpc.ClientError
    if errors.As(err, &clientErr) {
        if clientErr.Type == httpc.ErrorTypeRetryExhausted {
            log.Printf("%d 回リトライ後も失敗", clientErr.Attempts)
        }
    }
    return err
}

ベストプラクティス

シナリオ推奨設定
API 呼び出しMaxRetries=3, Delay=1s, Backoff=2.0
マイクロサービス通信MaxRetries=2, Delay=500ms
ファイルダウンロードMaxRetries=5, Delay=2s, Backoff=2.0
冪等な操作リトライ可能
非冪等な操作(POST)ネットワークエラー時のみリトライを推奨(デフォルトは 5xx/408/429 もリトライするため、カスタム RetryPolicy で範囲を絞る必要があります)

WARNING

非冪等な POST リクエストもデフォルトでリトライされます。正確な制御が必要な場合は、カスタム RetryPolicy を実装してください。

次のステップ