メインコンテンツへスキップ

Go Proposal Weekly Digest

Go言語のproposal更新を毎週お届け

#79040accepted

net/http: drop support for Transport.CancelRequest

ステータス変更: likely_accept accepted

要約

AIによる要約であり、誤りを含む場合があります。

概要

Go の net/http パッケージにある、長らく非推奨とされてきた Transport.CancelRequest メソッドを実質的に廃止(no-op化)する提案です。今後は NewRequestWithContext によるコンテキストベースのキャンセルのみをサポートします。

ステータス変更

likely_acceptaccepted
2026年7月1日・7月8日のレビュー会議で技術的な論点(GODEBUGのデフォルト挙動、ログ出力の是非、段階的opt-in導入の要否)が議論され、7月8日時点で「likely accept」と判断されました。その後1週間のコメント期間で合意内容に変化がなかったため、7月15日に正式にacceptedとなりました。

技術的背景

現状の問題点

CancelRequest は2016年(Go 1.6)に Request.Cancel によって非推奨化され、さらに2013年(Go 1.13)の NewRequestWithContext 導入によって二重に時代遅れとなっています。加えて公式ドキュメントには「HTTP/2リクエストはキャンセルできない」と明記されており、実質的に壊れた機能です。それでもなお、Transport は「いつか CancelRequest が呼ばれるかもしれない」という前提で、実行中の全リクエストを管理するマップを維持し続ける必要があり、これがこの関数を一切使わないユーザーにも常にコストを課しています。また *Request を値コピーして使うコードがある(newReq := *req)ため、リクエスト自体にキャンセル状態を持たせることもできず、根本的に設計上の無理があります。

提案された解決策

Transport.CancelRequest を no-op(何もしないメソッド)に変更し、初回呼び出し時のみ一度だけ警告ログを出力します。

var cancelRequestOnce sync.Once
func (*Transport) CancelRequest(req *Request) {
  cancelRequestOnce.Do(func() {
    log.Println("Use of unsupported Transport.CancelRequest. Use NewRequestWithContext instead.")
  })
}

互換性維持のため GODEBUG=httptransportcancelrequest=1 で従来の挙動に戻せるようにし、GODEBUG削除ポリシー(#76163)に従い4リリースサイクル後に完全撤去します。

これによって何ができるようになるか

利用者側の直接的なAPI追加はありませんが、Transport 内部で「呼ばれるかもしれないキャンセル」に備えたインフライトリクエスト管理を撤廃できるため、全てのHTTPリクエストの処理コストがわずかに軽減されます。また、実質機能しない古いAPIが整理されることで、標準ライブラリの保守性・コードの単純化にも寄与します。

コード例

// Before: 非推奨のCancelRequestに依存する古いコード(HTTP/2では動作しない)
tr := &http.Transport{}
req, _ := http.NewRequest("GET", url, nil)
go func() {
    time.Sleep(timeout)
    tr.CancelRequest(req) // no-opになり警告ログが出る
}()
resp, err := tr.RoundTrip(req)
// After: contextベースの正しいキャンセル方法
ctx, cancel := context.WithTimeout(context.Background(), timeout)
defer cancel()
req, _ := http.NewRequestWithContext(ctx, "GET", url, nil)
resp, err := tr.RoundTrip(req) // ctx完了時に自動的にキャンセルされる

議論のハイライト

  • 警告ログの必要性について議論があり、mateusz834 は「no-opにするだけで十分では」と疑問を呈したが、neild は「サイレントに失敗するより、バグとして検出可能な形(ログ出力)にする方が安全」と反論し、ログ出力は維持する方向となった。
  • 段階的なopt-in導入(まず任意で有効化させる期間を設ける案)も検討されたが、neild が「実際にopt-inする利用者がいるとは考えにくく、価値が薄い」と指摘し、見送られた。
  • GODEBUGのデフォルト値は言語バージョン(go.modgo ディレクティブ)に紐づけることで合意。
  • 「CancelRequestを技術的に完全サポートするオラクル(呼び出し可能性判定)を作ることは可能」との指摘もあったが、複雑すぎて永続的に保守コストを負うことになるため却下された。
  • 本提案はそもそも CancelRequest の実利用がほぼ皆無であるという前提に立っており、ログ出力に対する懸念は残るものの、既に net パッケージ内に同種のログ出力の前例があることも許容の一因となった。

関連リンク