0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

GoにおけるGoogle Sheets APIのリトライ処理

Last updated at Posted at 2024-09-23

要約

  1. リトライ処理には、github.com/hashicorp/go-retryablehttpを使う
  2. ただし、直接利用できないので、StandardClientからTransportを取得して、NewTransport()を使ってGoogle APIsで利用可能な状態に変換する
  3. Sheetsサービスには、WithHTTPClient()でリトライ可能なクライアントを設定する

本文

Google Sheets APIには、当然ながら呼び出し回数の制限がある。1分毎に呼び出し可能回数が回復するので、適切にリトライを行うことで、処理の失敗を抑えることができる。

リトライ間隔の戦略としては、Exponential backoffが挙げられていた
有名なパッケージでは、github.com/cenkalti/backoff/v4を使うことで、Exponential backoffを使ったリトライ処理を書くことができる。
今回は、github.com/hashicorp/go-retryablehttp(以下、retryablehttp)を利用する。理由としては以下。

  • http.Clientを設定するだけで、リトライが行われるので簡単
  • HTTPのステータスコードが理解されてリトライが行われる
  • Retry-Afterヘッダーをサポートしている

retryablehttpを使う際の注意点としては、StandardClient()で生成したhttp.ClientをそのままSheets APIのサービスに利用できない。
option.WithHTTPClient(retryClient.StandardClient())のように渡してしまうと、シークレットが正しく設定されないためAPIを利用することができなくなるためである。
対策としては、StandardClientからTransportを取り出し、google.golang.org/api/transport/httpパッケージのNewTransport()を使って、Google APIsで利用可能な状態にする。

サンプルコード

package main

import (
	"context"
	"fmt"
	"net/http"

	"github.com/cockroachdb/errors"
	"github.com/hashicorp/go-retryablehttp"
	"github.com/samber/mo"
	"google.golang.org/api/option"
	"google.golang.org/api/sheets/v4"
	googlehttp "google.golang.org/api/transport/http"
)

const (
	spreadsheetID = ""
	sheetID       = 0
)

type Client struct {
	srv *sheets.Service
}

func main() {
	ctx := context.Background()
	retryClient := retryablehttp.NewClient()
	retryClient.RetryMax = 5
	standardClient := retryClient.StandardClient()
	transport, err := googlehttp.NewTransport(context.Background(), standardClient.Transport)
	if err != nil {
		panic(err)
	}
	service, err := sheets.NewService(ctx, option.WithHTTPClient(&http.Client{
		Transport: transport,
	}))
	if err != nil {
		panic(err)
	}
	c := Client{srv: service}
	res := c.getSheetTitle(ctx, spreadsheetID, sheetID)
	if res.IsError() {
		panic(res.Error())
	}
	fmt.Println(res.Get())
}

// getSheetTitle シート名を取得
func (c Client) getSheetTitle(ctx context.Context, spreadsheetID string, sheetID int64) mo.Result[string] {
	s, err := c.srv.Spreadsheets.Get(spreadsheetID).Context(ctx).Do()
	if err != nil {
		return mo.Err[string](errors.Wrap(err, "get spreadsheet"))
	}
	for _, v := range s.Sheets {
		if v.Properties.SheetId == sheetID {
			return mo.Ok(v.Properties.Title)
		}
	}
	return mo.Err[string](fmt.Errorf("sheet not found"))
}
0
0
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
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?