テック技報最新号へ →
コード

Go: http.Get / http.DefaultClient はタイムアウトなし。自前の http.Client に Timeout を付ける

http.DefaultClient の Timeout はゼロ(無制限)なので、接続を受けたまま応答しないサーバーに当たるとゴルーチンが永遠に止まる。&http.Client{Timeout: ...} を作るか、リクエストに期限付きの context を渡す。

@amitsinha__07 · 投稿 2026-10-24
#go#http#timeout

何が起きるか

http.Get / http.Post / http.Head は内部で http.DefaultClient を使う。Timeout が 0 なので、

  • TCP 接続はできたがレスポンスヘッダが返ってこない
  • ボディを少しずつしか送ってこない

といった相手に当たると、呼び出し元のゴルーチンが待ち続ける。バッチやワーカーでこれが積み重なると、ゴルーチンと接続が漏れて詰まる。

書き方

go
// パッケージ単位で 1 つ作って使い回す(Transport の接続プールを共有するため)
var httpClient = &http.Client{
    Timeout: 10 * time.Second, // 接続〜ボディを読み終えるまでの合計
}

resp, err := httpClient.Get(url)

リクエストごとに期限を変えたいときは context を使う。

go
ctx, cancel := context.WithTimeout(ctx, 3*time.Second)
defer cancel()
req, _ := http.NewRequestWithContext(ctx, http.MethodGet, url, nil)
resp, err := httpClient.Do(req)

注意点

出典

X の元の投稿を開く