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 Retry の実装
Search
Shota Iwami
November 06, 2023
Programming
1.8k
0
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
HTTP Retry の実装
社内勉強会でのLTです
Shota Iwami
November 06, 2023
More Decks by Shota Iwami
See All by Shota Iwami
モノレポにおけるエラー管理 ~Runbook自動生成とチームメンションの最適化
biwashi
2
1k
OpenTelemetry の Log を使いこなそう
biwashi
7
2.1k
Monorepo Error Management: Automated Runbooks and Team-Targeted Alert Distribution
biwashi
2
1.2k
スタートアップ創業期を支えるオブザーバビリティ基盤のこれまでとこれから
biwashi
10
1.7k
モノレポ開発のエラー、誰が見る?Datadog で実現する適切なトリアージとエスカレーション
biwashi
7
1.8k
k6を活用した再現性・拡張性の高い負荷試験基盤の構築
biwashi
13
4.4k
Datadogマニアック機能活用術
biwashi
7
4.5k
feature flag と OpenTelemetry
biwashi
7
2.4k
OpenFeatureと自動生成を活用したフィーチャーフラグの宣言的集約管理
biwashi
20
7.5k
Other Decks in Programming
See All in Programming
AWS DevOps AgentのAzure接続機能を検証して見えた活用法/Use Cases Verified for the AWS DevOps Agent's Azure Connectivity Feature
masakiokuda
1
260
Webエンジニアなのにブラウザの仕組みがわからないので、Pythonで自作してみた
tatsuki12
4
990
仕様駆動開発へのトライを機に チームに適合する手法を模索し続けている話
freee
PRO
0
590
FastAPI の並行処理モデルを完全に理解する
hoto17296
8
2.7k
人間の目はかわらない、だからJPEGは30年もつ
yuzneri
12
19k
不幸な GC
chencmd
0
610
承認済みなのに差戻しできてしまうバグ、型で潰せます
shinchit
0
100
go-spidermonkeyでAIエージェントのCode Modeを実装する
syumai
0
210
PyConJP2026_wat_Python × Signal Processing: How to Draw Pictures with Sound Using Spectrogram Art
wat
0
170
AIに既存システムを理解させる技術 ~レガシーを見捨てないハーネスエンジニアリング入門~
ochtum
0
140
S3 を使うアプリケーションをローカル完結で動かすことに全力を注いでみた / Running S3 Apps Offline
contour_gara
0
580
Hono + Inertia + React で LP を構築した話
oukayuka
2
140
Featured
See All Featured
XXLCSS - How to scale CSS and keep your sanity
sugarenia
249
1.3M
Visualization
eitanlees
152
17k
sira's awesome portfolio website redesign presentation
elsirapls
0
340
KATA
mclloyd
PRO
35
15k
SERP Conf. Vienna - Web Accessibility: Optimizing for Inclusivity and SEO
sarafernandez
2
1.6k
How People are Using Generative and Agentic AI to Supercharge Their Products, Projects, Services and Value Streams Today
helenjbeal
1
280
svc-hook: hooking system calls on ARM64 by binary rewriting
retrage
2
520
The MySQL Ecosystem @ GitHub 2015
samlambert
251
13k
Making the Leap to Tech Lead
cromwellryan
135
10k
How to Ace a Technical Interview
jacobian
281
24k
Templates, Plugins, & Blocks: Oh My! Creating the theme that thinks of everything
marktimemedia
31
2.9k
Fight the Zombie Pattern Library - RWD Summit 2016
marcelosomers
234
17k
Transcript
HTTP Retryの実装 AI事業本部 アプリ運用センター 岩見彰太
自己紹介 岩見 彰太 趣味:サックス・ドローン・カメラ AI事業本部 小売DX アプリ運用センター 22卒バックエンドエンジニア B_Sardine
事の発端 とあるAPIに対して特定のステータスコードの時に Exponential Backoffによるリトライを実装したい
最初こんな感じで実装してみた ということで…
client.Do(req)を実行する responseのステータスコードが429なら エラーを返す エラーだった時にリトライする cenkalti/backoff 用メソッド maxRetryNumberで設定 した回数だけリトライする
最初の1回目以降、Request Bodyが空だと怒られて Do がエラーになる 適当なサーバを立てて叩いて見ると…
こんな感じで、Bodyを入れ直すと通る Bodyの巻き戻し. 入れ直しが必要 先に結論
Requestの構造体を見てみる Bodyはio.ReadCloserというインターフェース型 今回入れた具象型はbytes.Buffer 複数回リトライする場合, これが複数回実行される bytes.Bufferの構造体を見てみる lastReadという読み切った場所を内部で保存してる なぜなくなる? リトライする場合は Request.Bodyを初期状態に戻す必要がある
つまり…
http.Clientの中のTrasport.roundTripがリトライ処理し てる ネットワークエラーとかになった時にリトライしてる rewindBodyというメソッドを呼んでる Request.Bodyを閉じる body, err := req.GetBody()でRequst.Bodyのコピーを取 り出す
取り出したものをもう一度reqに入れる rewindBodyの流れ 1. 2. 3. 実はnet/httpもリトライしてる コネクションの確立とかコネクションプールの管理を行なってる Transport
*bytes.Buffer <----- 今回の場合 *bytes.Reader *strings.Reader Request.Bodyの具象型が以下の時に GetBodyがセットされる io.NopCloser は何もしない io.ReadCloser
(Bodyで指定されているinterface型)を実装できる req.GetBody()は Request作成時に作られる
Transport.roundTripでも終了判定している リトライをする場合、呼び出し元のcontextを伝播す る必要がある 同じように判定する必要がある Contextの終了を確認する
レスポンス内容はio.ReadCloserの Response.Bodyから読み取れる 呼び出し側で最後まで読み取ってから Close しな いと keep-aliveの TCPコネクションが再利用さ れない レスポンスを返した後に接続を維持し、次のリク
エストを送るときにその接続を再利用して送ること ができる Keep-AliveはResponseが読み切られてCloseした タイミングで再利用できるようになる > Bodyを閉じるのは呼び出し側の責任である。 > デフォルトの HTTP クライアントの Transport は、Body を最後まで読んで閉じな いと、 HTTP/1.x の "keep-alive" TCP コネクションを再利用しないかもしれません。 Keep-Alive http.Response.Bodyを 読み切ってから閉じる
Transport 内部では、connectMethodKey(接続先) 単位で idel 状態のTCPコネクションや 確立待ちのキューが管理されている これがデフォルトの場合はDefaultTransportが使用される 90s: IdleConnTimeout(リクエストが終わってもコネクションが維持される時間) 2:
MaxIdleConnsPerHost(接続先ごとのKeep-Aliveの最大数) TransportでのTCPコネクションの管理
CloseIdleConnections()でコネクションプールを 一括で閉じることができる リトライ終了後に意図的に解放したい場合は使える (これを呼ばない場合、IdleConnTimeoutが過ぎると 自動的に解放される) コネクションプールを閉じる
リトライが必要となる場面(429 Too Many Requests)では、短期間で同じ宛先にリクエスト する場合 そうなると、 MaxIdleConnsPerHost だと少ない可能性が高い リトライしている期間中占有してしまい、解放まで時間がかかる可能性があるから 場合によっては専用の
Transport を作成した方がいい この場合、使わないのに IdleConnTimeout で設定されている時間分 Keep-Alive が保持 されて、コネクションリソースを消費してしまうので、リトライが終了した後は CloseIdleConnections を読んでコネクションプールを開放するべき (終了したらコネクションプールを閉じる) リトライ用のTransportを別で用意するべき?
ただリトライしたいだけなのに 考えること多くてめんどくさい… ここら辺まるっとやってくれる便利なライブラリないのか……
今まで説明してきたようなことが考慮されてる TransportはMaxIdleConnsPerHostを増やし て、リトライ後には閉じるようになっている net/httpと同じように使えて直感的 -> 結局これを使いました Hashicorp製 hashicorp/go-retryablehttp ありました
まとめ リクエストの内容(Request.Body)をリトライ前に巻き戻す Request.Context()の終了を確認する リトライ前にResponse.Bodyを全て読み切ってから閉じる デフォルトのTransportを使用してコネクションプール管理するか検討する hashicorp/go-retryablehttpの使用を検討する ちなみに、AWS SDK for GoとかでAPIコールする場合は、勝手にリトライしてくれるようになってる