Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

[インデックス 11870] ファイルの概要

コミット

  • コミットハッシュ: 569ef7d49e36048aeca92e387e934d5a53276949
  • 作者: Russ Cox rsc@golang.org
  • コミット日時: Mon Feb 13 22:23:04 2012 -0500

GitHub上でのコミットページへのリンク

https://github.com/golang/go/commit/569ef7d49e36048aeca92e387e934d5a53276949

元コミット内容

net/http: disable buggy test

Generates an infinite stream (at least >1GB) of:

=== RUN TestTransportPersistConnLeak
2012/02/13 22:20:19 http: Accept error: accept tcp 127.0.0.1:63972:
too many open files
2012/02/13 22:20:19 http: Accept error: accept tcp 127.0.0.1:63972:
too many open files
... (以下同様のエラーが続く)

R=bradfitz
CC=golang-dev
https://golang.org/cl/5661052

変更の背景

このコミットは、Go言語の標準ライブラリであるnet/httpパッケージ内のテストTestTransportPersistConnLeakが、バグによって無限に「too many open files」エラーを発生させ、大量のログ(1GB以上)を出力するという問題に対応するために行われました。このテストは、ファイルディスクリプタ(FD)のリークを引き起こしており、テスト実行環境のリソースを枯渇させる可能性がありました。

開発プロセスにおいて、テストが不安定であったり、予期せぬ副作用(この場合はリソースリーク)を引き起こしたりする場合、そのテストを一時的に無効化することは一般的な対応策です。これにより、CI/CDパイプラインの安定性を保ち、他の重要なテストの実行を妨げないようにします。このコミットは、根本的なバグ修正ではなく、問題のあるテストを一時的に隔離するための措置です。

前提知識の解説

  • Go言語のnet/httpパッケージ: Go言語でHTTPクライアントおよびサーバーを実装するための標準ライブラリです。Webアプリケーション開発において中心的な役割を担います。
  • Transport: net/httpパッケージにおけるTransportインターフェースは、HTTPリクエストの送信とレスポンスの受信に関する低レベルの詳細を扱います。これには、接続の確立、プロキシの処理、TLSハンドシェイク、接続の再利用(永続接続)などが含まれます。http.DefaultTransportは、デフォルトのTransport実装であり、通常はHTTP/1.1の永続接続をサポートします。
  • 永続接続 (Persistent Connections / Keep-Alive): HTTP/1.1で導入された機能で、複数のHTTPリクエスト/レスポンスを単一のTCP接続上で送受信できるようにします。これにより、接続の確立と切断のオーバーヘッドが削減され、パフォーマンスが向上します。
  • ファイルディスクリプタ (File Descriptors, FDs): オペレーティングシステムがファイルやソケットなどのI/Oリソースを識別するために使用する抽象的なハンドルです。プログラムがファイルを開いたり、ネットワーク接続を確立したりするたびに、FDが割り当てられます。システムには利用可能なFDの数に上限があり、これを使い果たすと「too many open files」エラーが発生します。
  • too many open filesエラー: プロセスがオペレーティングシステムから割り当てられるファイルディスクリプタの最大数を超過した際に発生するエラーです。これは、ファイルやネットワークソケットが適切に閉じられていない(リークしている)場合に頻繁に見られます。
  • Goのテストフレームワーク (testingパッケージ): Go言語には、標準でテストを記述するためのtestingパッケージが用意されています。テスト関数はTestで始まり、*testing.T型の引数を取ります。
  • httptest.NewServer: net/http/httptestパッケージに含まれる関数で、テスト目的でHTTPサーバーを簡単に起動できます。実際のネットワークポートをリッスンし、テスト対象のHTTPクライアントからのリクエストを受け付けることができます。
  • t.Logf: *testing.T型のメソッドで、テスト中にログメッセージを出力するために使用されます。fmt.Printfと同様のフォーマット文字列をサポートします。
  • return文によるテストの無効化: Goのテスト関数内でreturn文を使用すると、その時点以降のテストコードの実行が停止します。このコミットでは、テストの冒頭でreturnすることで、実質的にテスト全体を無効化しています。より慣用的なテストのスキップ方法としてはt.Skip()がありますが、このコミットでは単純なreturnが選択されています。

技術的詳細

このコミットで無効化されたTestTransportPersistConnLeakテストは、net/httpパッケージのTransportが永続接続を適切に管理し、リソース(特にファイルディスクリプタ)をリークしないことを検証することを目的としていたと考えられます。しかし、テスト自体にバグがあり、意図せずファイルディスクリプタのリークを引き起こしていました。

リークの症状は、テスト実行中に大量の「http: Accept error: accept tcp 127.0.0.1:63972: too many open files」というエラーメッセージが無限に(または非常に大量に)出力されることでした。これは、テスト内でHTTPサーバーが多数の接続を確立しようとしているにもかかわらず、それらの接続に関連するファイルディスクリプタが適切に閉じられず、OSがプロセスに割り当てられるFDの上限に達してしまったことを示しています。結果として、新しい接続を受け入れることができなくなり、Accept errorが発生し続けていました。

この問題は、テストが実行されるたびにシステムリソースを消費し、テスト環境を不安定にするため、早急な対応が必要でした。根本原因の特定と修正には時間がかかる可能性があるため、一時的な措置として、テストを無効化することが選択されました。これにより、CIシステムや開発者のローカル環境でのテスト実行が妨げられることなく、他の開発作業を進めることが可能になります。

テストを無効化することは、そのテストがカバーしていた機能の回帰テストが行われなくなるというリスクを伴いますが、この場合はテスト自体がバグの原因となっていたため、一時的な無効化が最善の選択でした。

コアとなるコードの変更箇所

--- a/src/pkg/net/http/transport_test.go
+++ b/src/pkg/net/http/transport_test.go
@@ -635,6 +635,9 @@ func TestTransportGzipRecursive(t *testing.T) {
 
 // tests that persistent goroutine connections shut down when no longer desired.
 func TestTransportPersistConnLeak(t *testing.T) {
+\tt.Logf("test is buggy - appears to leak fds")
+\treturn
+\n
 \tgotReqCh := make(chan bool)
 \tunblockCh := make(chan bool)
 \tts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {

コアとなるコードの解説

変更はsrc/pkg/net/http/transport_test.goファイルのTestTransportPersistConnLeak関数内で行われています。

  1. t.Logf("test is buggy - appears to leak fds")

    • この行は、テストが実行された際に、テストログに「test is buggy - appears to leak fds」(テストにバグがあり、ファイルディスクリプタをリークしているようです)というメッセージを出力します。これは、このテストが無効化された理由を明確にするためのものです。
    • t.Logfは、Goのtestingパッケージが提供するロギング機能で、テストの実行中に情報を出力する際に使用されます。
  2. return

    • この行が追加されたことで、TestTransportPersistConnLeak関数は、t.Logfの呼び出し直後に実行を終了します。
    • これにより、このテスト関数内の残りのコード(永続接続のリークをテストする本来のロジック)は一切実行されなくなります。
    • 結果として、バグのあるテストが引き起こしていたファイルディスクリプタのリーク問題が回避されます。

この変更は、テストのロジック自体を修正するものではなく、単にその実行を停止させることで、問題の発生を防ぐための暫定的な措置です。

関連リンク

  • Go CL 5661052: https://golang.org/cl/5661052 (このコミットに対応するGoのコードレビューシステム上のチェンジリスト)

参考にした情報源リンク

  • Go言語公式ドキュメント: net/httpパッケージ: https://pkg.go.dev/net/http
  • Go言語公式ドキュメント: testingパッケージ: https://pkg.go.dev/testing
  • Go言語公式ドキュメント: net/http/httptestパッケージ: https://pkg.go.dev/net/http/httptest
  • ファイルディスクリプタに関する一般的な情報 (例: Wikipedia, OSのドキュメントなど)
  • HTTP永続接続 (Keep-Alive) に関する一般的な情報 (例: MDN Web Docs, RFCなど)