TL;DR
grpc v1.63.0でDialContext関数がdeprecatedになったため、NewClient関数に置き換えたことが原因。
targetに与えるURLのスキームとしてpassthroughを明示的に与えることで解決する。
//v1.63.0以前
conn, err := grpc.DialContext(
context.Background(),
"bufnet",
grpc.WithContextDialer(dial),
grpc.WithTransportCredentials(insecure.NewCredentials()),
)
//v1.63.0以降
conn, err := grpc.NewClient(
"passthrough://bufnet",
grpc.WithContextDialer(dial),
grpc.WithTransportCredentials(insecure.NewCredentials()),
)
経緯
Goで書いたgRPCサーバーのインターセプターのテストを行うため、bufconnを用いてサーバーのモックを行っている。grpcライブラリをv1.63.0にアップデートすると、クライアント部分のDialContext()
がdeprecatedになっていたため,ドキュメントの指示通りNewClient()
に置き換えた。この変更をした後テストが通らなくなったため調べたところ、リクエスト結果がUnavailableになっていることが分かった。
client := pb.NewTestServiceClient(conn)
_, err = client.EmptyCall(context.Background(), &pb.Empty{})
slog.Error(err.Error())
//->rpc error: code = Unavailable desc = name resolver error: produced zero addresses
DialContextとNewClientの違い
二つの関数の違いを知るため、ドキュメントを参照した。これによると
One subtle difference between NewClient and Dial and DialContext is that the former uses "dns" as the default name resolver, while the latter use "passthrough" for backward compatibility. This distinction should not matter to most users, but could matter to legacy users that specify a custom dialer and expect it to receive the target string directly.
つまり、bufconnを利用する場合ネームリゾルバがpassthroughである必要があり、NewClient()
ではデフォルトのネームリゾルバがdnsとなっているため正常に通信できなくなっている可能性が高い。
次に、ソースコードを見てみると
func DialContext(ctx context.Context, target string, opts ...DialOption) (conn *ClientConn, err error) {
// At the end of this method, we kick the channel out of idle, rather than
// waiting for the first rpc.
opts = append([]DialOption{withDefaultScheme("passthrough")}, opts...)
cc, err := NewClient(target, opts...)
//略
このように、DialContext()
も内部ではNewClient()
を呼び出しており、その呼び出しの前にwithDefaultScheme("passthrough")
でpassthroughを設定していることがわかる。withDefaultScheme()
はプライベートであるためpassthroughを指定する方法を他に捜したところ、URLをpassthrough://address
のようにすることでリゾルバを設定できることが分かった。
参考
https://github.com/grpc/grpc-go/blob/master/clientconn.go
https://github.com/grpc/grpc-go/blob/master/clientconn_parsed_target_test.go