1. Home
  2. Golang
  3. GuideToBecomingGoDeveloper
  4. APIClients
  5. Heimdall - Golang learning step 8-1

Heimdall - Golang learning step 8-1

  • 公開日
  • カテゴリ:APIClients
  • タグ:Golang,roadmap.sh,学習メモ
Heimdall - Golang learning step 8-1

roadmap.sh > Go > API Clients > REST > Heimdall の学習を進めていきます。

※ 学習メモとしての記録ですが、後にこのセクションを学ぶ道しるべとなるよう、ですます調で記載しています。

contents

  1. 開発環境
  2. 参考 URL
  3. Heimdall
    1. Heimdall の特徴
  4. Heimdall のインストール
  5. 基本的な使い方
    1. 1. GET リクエストの送信例
    2. POST リクエストの送信例
  6. バックオフを使ったリトライ
    1. 固定バックオフを使ったリトライ
    2. 指数バックオフを使ったリトライ

開発環境

  • チップ: Apple M2 Pro
  • OS: macOS Sonoma
  • go version: go1.23.2 darwin/arm64

参考 URL

Heimdall

Heimdall は、Go で堅牢な HTTP クライアントを構築するためのライブラリです。リトライ機能やカスタムバックオフ戦略などをサポートしており、信頼性の高い API 呼び出しを簡単に実現できます。ここでは Heimdall の基本的な使い方を解説します。

Heimdall の特徴

Heimdall は以下のような機能を提供します。

  1. リトライ機能:失敗した HTTP リクエストを指定回数再試行します。
  2. バックオフ戦略:リトライ時の待機時間を制御できます(例: 固定、指数、Jitter)。
  3. タイムアウトの設定:HTTP リクエストにタイムアウトを設定できます。
  4. カスタマイズ可能:独自のバックオフ戦略や HTTP クライアントを実装可能です。

Heimdall のインストール

Heimdall をプロジェクトに追加するには、以下のコマンドを実行します:

go get -u github.com/gojek/heimdall/v7

基本的な使い方

以下に Heimdall を使ったシンプルな例を示します。

1. GET リクエストの送信例

GET リクエストは最も基本的な HTTP リクエストで、サーバーからデータを取得するために使用されます。Heimdall を使用すると、リトライやタイムアウトを簡単に設定できます。

package main

import (
  "fmt"
  "io"
  "log"
  "time"

  "github.com/gojek/heimdall/v7/httpclient"
)

func main() {
  // Heimdall HTTP クライアントを作成
  client := httpclient.NewClient(
    httpclient.WithHTTPTimeout(10*time.Second), // 10秒のタイムアウトを設定
    httpclient.WithRetryCount(3),              // リトライ回数を3回に設定
  )

  // GET リクエストを送信
  resp, err := client.Get("https://httpbin.org/get", nil)
  if err != nil {
    log.Fatalf("リクエスト失敗: %v", err)
  }
  defer resp.Body.Close()

  // レスポンスの内容を出力
  body, _ := io.ReadAll(resp.Body)
  fmt.Printf("ステータスコード: %d\n", resp.StatusCode)
  fmt.Printf("レスポンスボディ: %s\n", string(body))
}

実行結果:

ステータスコード: 200
レスポンスボディ: {
  "args": {}, 
  "headers": {
    "Accept-Encoding": "gzip", 
    "Host": "httpbin.org", 
    "User-Agent": "Go-http-client/2.0", 
    "X-Amzn-Trace-Id": "Root=1-67849d2b-4d02c15a4caca51b640a9756"
  }, 
  "origin": "124.215.81.43", 
  "url": "https://httpbin.org/get"
}

POST リクエストの送信例

POST リクエストは、データをサーバーに送信するために使用されます。例えば、JSON データをサーバーに送信する際に使用します。

package main

import (
  "bytes"
  "fmt"
  "io"
  "log"
  "net/http"
  "time"

  "github.com/gojek/heimdall/v7/httpclient"
)

func main() {
  // Heimdall HTTP クライアントを作成
  client := httpclient.NewClient(
    httpclient.WithHTTPTimeout(10*time.Second), // 10秒のタイムアウトを設定
    httpclient.WithRetryCount(3),              // リトライ回数を3回に設定
  )

  // JSON データを送信
  data := []byte(`{"message": "Hello, Heimdall!"}`)
  headers := http.Header{
    "Content-Type": []string{"application/json"},
  }

  // POST リクエストを送信
  resp, err := client.Post("https://httpbin.org/post", bytes.NewBuffer(data), headers)
  if err != nil {
    log.Fatalf("リクエスト失敗: %v", err)
  }
  defer resp.Body.Close()

  // レスポンスの内容を出力
  body, err := io.ReadAll(resp.Body)
  if err != nil {
    log.Fatalf("レスポンス読み取り失敗: %v", err)
  }

  fmt.Printf("ステータスコード: %d\n", resp.StatusCode)
  fmt.Printf("レスポンスボディ: %s\n", string(body))
}

実行結果:

ステータスコード: 200
レスポンスボディ: {
  "args": {}, 
  "data": "{\"message\": \"Hello, Heimdall!\"}", 
  "files": {}, 
  "form": {}, 
  "headers": {
    "Accept-Encoding": "gzip", 
    "Content-Length": "31", 
    "Content-Type": "application/json", 
    "Host": "httpbin.org", 
    "User-Agent": "Go-http-client/2.0", 
    "X-Amzn-Trace-Id": "Root=1-67849d7f-3764380445ce957652576dd5"
  }, 
  "json": {
    "message": "Hello, Heimdall!"
  }, 
  "origin": "124.215.81.43", 
  "url": "https://httpbin.org/post"
}

バックオフを使ったリトライ

固定バックオフを使ったリトライ

固定バックオフとは、リトライ間隔を一定時間に設定する戦略です。たとえば、失敗したリクエストを 2 秒間隔で再試行するといった設定が可能です。この戦略はリトライ間隔が一定で予測可能であるため、シンプルなケースで効果的です。

以下は、固定バックオフを利用してリトライを実装するコード例です。この例では、2 秒間隔でリトライを行い、HTTP リクエストにタイムアウトを設定しています。

package main

import (
  "fmt"
  "net/http"
  "time"

  "github.com/gojek/heimdall/v7/httpclient"
  "github.com/gojek/heimdall/v7/plugins"
)

func main() {
  // 固定バックオフを設定(リトライ間隔: 2秒)
  backoff := heimdall.NewConstantBackoff(2*time.Second, 1*time.Second)

  // HTTP クライアントを作成
  client := httpclient.NewClient(
    httpclient.WithHTTPTimeout(10*time.Second), // タイムアウトを10秒に設定
    httpclient.WithRetrier(heimdall.NewRetrier(backoff)), // リトライ機能を設定
  )

  // リクエストを実行
  response, err := client.Get("https://example.com", nil)
  if err != nil {
    fmt.Printf("リクエスト失敗: %v\n", err)
    return
  }

  fmt.Printf("レスポンスコード: %d\n", response.StatusCode)
}
  1. 固定バックオフの設定
    • heimdall.NewConstantBackoff を使用して固定バックオフを作成しています。2 秒の間隔と 1 秒の jitter を設定しており、リトライ間隔にランダムな要素を加えることで、全リクエストが同時に再試行される「スパイク」を回避できます。
  2. タイムアウトの設定
    • httpclient.WithHTTPTimeout を使い、リクエストが 10 秒を超えた場合にタイムアウトするよう設定しています。これにより、無限に待機することを防ぎます。
  3. リトライの実行
    • HTTP クライアントの Get メソッドを使用してリクエストを送信しています。失敗した場合は、指定した固定バックオフの設定に基づいて再試行されます。

指数バックオフを使ったリトライ

指数バックオフは、リトライ間隔を段階的に増やす戦略です。たとえば、最初は 500 ミリ秒後に再試行し、次は 1 秒、次は 2 秒というように、間隔を倍増させていきます。この戦略は、リソースへの負荷を抑えつつ、再試行による成功の可能性を高めたい場合に有効です。

以下は、指数バックオフを利用してリトライを実装するコード例です。この例では、初期間隔 500 ミリ秒から最大 5 秒間隔まで、リトライを繰り返す設定になっています。

package main

import (
  "fmt"
  "net/http"
  "time"

  "github.com/gojek/heimdall/v7/httpclient"
)

func main() {
  // 指数バックオフを設定
  backoff := heimdall.NewExponentialBackoff(
    500*time.Millisecond,    // 初期待機時間(リトライの最初の間隔)
    5*time.Second,           // 最大待機時間(リトライ間隔の上限)
    float64(15*time.Second), // 最大経過時間(リトライ全体の制限時間)
    2.0,                     // 指数増加率(リトライ間隔を倍々に増加)
  )

  // HTTP クライアントを作成
  client := httpclient.NewClient(
    httpclient.WithHTTPTimeout(10*time.Second), // タイムアウトを 10 秒に設定
    httpclient.WithRetrier(heimdall.NewRetrier(backoff)), // リトライ機能を設定
  )

  // GET リクエストを実行
  response, err := client.Get("https://example.com", nil)
  if err != nil {
    fmt.Printf("リクエスト失敗: %v\n", err)
    return
  }

  // レスポンスコードを出力
  fmt.Printf("レスポンスコード: %d\n", response.StatusCode)
}
  1. 指数バックオフの設定
    • heimdall.NewExponentialBackoff を使用して、初期の待機時間を 500 ミリ秒、最大待機時間を 5 秒、最大リトライ時間を 15 秒に設定しています。リトライごとに待機時間が増加するため、短時間での連続的なリトライを防ぎ、サーバー負荷の軽減に役立ちます。
  2. リトライの管理
    • heimdall.NewRetrier を使って、バックオフ戦略を持つリトライ機能を HTTP クライアントに設定しています。これにより、サーバーの過負荷やネットワークエラーが原因の失敗時に適切な再試行が行われます。
  3. タイムアウトの設定
    • httpclient.WithHTTPTimeout により、10 秒を超えるリクエストは失敗として処理されます。これにより、長いリトライ待機による無限ループを防止します。

まとめ

  • Heimdall は Go 言語向けの堅牢な HTTP クライアントライブラリ
  • リトライ機能やバックオフ戦略を簡単に実装可能
  • 固定バックオフや指数バックオフを活用した信頼性の高い API 呼び出しの実現
  • HTTP クライアントのタイムアウトやカスタム設定の柔軟性
  • 初心者でも理解しやすい API デザインと豊富な拡張性


[Next] Step 8-2: Grequests

[Prev] Step 7-1: Melody

Author

rito

  • Backend Engineer
  • Tokyo, Japan
  • PHP 5 技術者認定上級試験 認定者
  • 統計検定 3 級