Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
Httpリクエストを自動リトライ・ポーリングするイテレータを作ってみた
Search
miyamo2
September 04, 2024
Programming
180
0
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
Httpリクエストを自動リトライ・ポーリングするイテレータを作ってみた
2024/09/04 Go Connect #2
https://gotalk.connpass.com/event/327544/
miyamo2
September 04, 2024
More Decks by miyamo2
See All by miyamo2
Go 1.24 tool directiveは何を変えるのか
miyamo2
1
260
AWS Cloud Formation Git Syncで始める 頑張らない自動デプロイ
miyamo2
0
180
Other Decks in Programming
See All in Programming
AI がコードを書く時代における新卒エンジニアの仕事風景 (2026) / New Graduate Engineers in the Era of AI Coding (2026)
sushichan044
0
220
スマートグラスで並列バイブコーディング
hyshu
0
290
The Bowling Game- From Imperative to Functional Programming - Part 1
philipschwarz
PRO
0
310
SREは、MCPとSRE Agentをこう使え!
kazumax55
0
150
過去最大のMCPアップデート! 2026-07-28 RC版の謎に迫る
licux
6
460
エンジニアにデザインハーネスを 〜デザインプロセスを規定するためのハーネス〜 / Design harness from an engineer's perspective
rkaga
2
1.4k
Hunting Vulnerabilities in Symfony with LLMs
vinceamstoutz
0
580
symfony/aiとlaravel/boost
77web
0
120
act2-costs.pdf
sumedhbala
0
110
SREの積み重ねがAI駆動開発のガードレールになった ― 7つの実践/SRE Guardrails The 7
tomoyakitaura
8
4k
Skillsは効率化、Agentsは"自分の拡張"——Builder時代のエージェント編成(CC Night 2026)
wemra
1
210
Creating Composable Callables in Contemporary C++
rollbear
0
200
Featured
See All Featured
Making the Leap to Tech Lead
cromwellryan
135
10k
What the history of the web can teach us about the future of AI
inesmontani
PRO
1
630
The SEO identity crisis: Don't let AI make you average
varn
0
510
Helping Users Find Their Own Way: Creating Modern Search Experiences
danielanewman
31
3.2k
Java REST API Framework Comparison - PWX 2021
mraible
34
9.5k
GraphQLの誤解/rethinking-graphql
sonatard
75
12k
Principles of Awesome APIs and How to Build Them.
keavy
128
18k
I Don’t Have Time: Getting Over the Fear to Launch Your Podcast
jcasabona
34
2.8k
Optimizing for Happiness
mojombo
378
71k
Ten Tips & Tricks for a 🌱 transition
stuffmc
0
150
Done Done
chrislema
186
16k
How to train your dragon (web standard)
notwaldorf
97
6.7k
Transcript
Httpリクエストを自動リトライ・ポーリングす るイテレータを作ってみた 2024/09/04 Go Connect #2 @miyamo2
話すこと・話さないこと 話すこと 作ったものの概要とその使い方 話さないこと イテレータの概要や実装方法 作ったパッケージの内部実装について
作ったもの できること ステータスコードに応じた自動リトライ レスポンスボディとエラーに応じた自動リトライ(ポーリング処理) 上記の結果のイテレーション
サンプルコード url := "http://example.com" ctx, cancel := context.WithTimeout(context.Background(), time.Second*10) defer
cancel() opts := []r2.Option{ r2.WithMaxRequestAttempts(3), r2.WithPeriod(time.Second), } for resp, err := range r2.Get(ctx, url, opts...) { if err != nil { slog.WarnContext(ctx, "something happened.", slog.Any("error", err)) // Note: continueを使用してもイテレータが終了する場合がある continue } if resp == nil { slog.WarnContext(ctx, "response is nil") continue } if resp.StatusCode != http.StatusOK { slog.WarnContext(ctx, "unexpected status code.", slog.Int("expect", http.StatusOK), slog.Int("got", resp.StatusCode)) continue } buf, err := io.ReadAll(resp.Body) if err != nil { slog.ErrorContext(ctx, "failed to read response body.", slog.Any("error", err)) continue } slog.InfoContext(ctx, "response", slog.String("response", string(buf))) // r2ではデフォルトでリクエストボディが自動クローズするため明示的にクローズ処理を行う必要がない }
r2がイテレータを終了する条件 リクエストが成功(ステータスコードが200 ~ 399)、 かつ WithTerminateIf が指定されていない場合 WithTerminateIf で指定された条件が満たされた場合 429:
Too Many Requests以外の4xx クライアントエラーが返された 場合 WithMaxRequestAttempts によって指定されたリクエストの最大回数 を超えた場合 引数で渡された context.Context がキャンセルされた場合 for rangeループがbreakによって中断された場合
Get 以外にr2で用意されている関数 func Head(ctx context.Context, url string, options ...Option) (*http.Response,
error) func Post(ctx context.Context, url string, body io.Reader, options ...Option) (*http.Response, error) func Put(ctx context.Context, url string, body io.Reader, options ...Option) (*http.Response, error) func Patch(ctx context.Context, url string, body io.Reader, options ...Option) (*http.Response, error) func Delete(ctx context.Context, url string, body io.Reader, options ...Option) (*http.Response, error) func PostForm(ctx context.Context, url string, data url.Values, options ...Option) (*http.Response, error)
r2で用意されているオプション WithMaxRequestAttempts WithPeriod WithInterval WithTerminateIf WithHttpClient WithHeader WithContentType WithAspect WithAutoCloseResponseBody
r2で用意されているオプション WithMaxRequestAttempts WithPeriod WithInterval WithTerminateIf WithHttpClient WithHeader WithContentType WithAspect WithAutoCloseResponseBody
WithMaxRequestAttempts func WithMaxRequestAttempts(maxRequestTimes int) Option r2.WithMaxRequestAttempts(3) リクエストの最大回数を指定する デフォルト、もしくは0が設定された場合は回数無制限でリクエスト を行う リトライではなく、リクエストの回数を指定するオプションなので注
意
WithPeriod func WithPeriod(period time.Duration) Option r2.WithPeriod(time.Second) 各リクエストのタイムアウト時間を指定する デフォルト、もしくは0が設定された場合はタイムアウトしない http.Client.Timeout を使用せず
r2 独自で context.WithTimeout を用い たハンドリングを行う http.Client.Timeout と併用して同じ値が設定された場合にどちらのタ イムアウトが適用されるかの動作は未定義
WithInterval func WithInterval(interval time.Duration) Option r2.WithInterval(time.Second) 各リクエストの間隔を指定する デフォルト、もしくは0が設定された場合は以下のどちらかで算出さ れる Backoff
And Jitterアルゴリズム 'Retry-After'ヘッダーを参照 (Too Many Requestsが返された場合に限り)
WithTerminateIf func WithTerminateIf(terminationCondition func(resp *http.Response, err error) bool) Option r2.WithTerminateIf(
func(resp *http.Response, _ error) bool { buf, err := io.ReadAll(resp.Body) if err != nil { return true } data := map[string]any{} if err := json.Unmarshal(buf, data); err != nil { return false } return data["foo"] == "bar" }) ユーザー独自の終了条件を指定する レスポンスボディの巻き戻しは r2 側で対応
WithAutoCloseResponseBody func WithAutoCloseResponseBody(autoCloseResponseBody bool) Option r2.WithAutoCloseResponseBody(false) リクエストボディを r2 側で自動でクローズする デフォルト、もしくはtrueが設定された場合は有効
参考 イテレータによってGoはどう変わるのか https://audience.ahaslides.com/cl965inb88/review?lookback-tab=slides Go の iter パッケージを使ってみよう https://zenn.dev/mattn/articles/641f1d86fffdc9 Goのリトライ処理で考慮すること https://zenn.dev/imamura_sh/articles/retry-46aa586aeb5c3c28244e
mattn/go-for-range-experiment-example https://github.com/mattn/go-for-range-experiment-example avast/retry-go https://github.com/avast/retry-go