0️⃣
grpc-goのNewClient()を使うとbufconnを使ったテストがUnavailableでコケる件の対処法
TL;DR
- grpc-go v1.64.0からDial()やDialContext()がDeprecatedとなった
- 代わりに推奨されたNewClient()を使うとbufconnを使っているテストがUnavailable(
name resolver error: produced zero addresses
)で落ちる - 初期化として
resolver.SetDefaultScheme("passthrough")
を突っ込むと動くよ
原因
gRPCクライアントを作成する際、従来のDial(), DialContext()ではデフォルトのネームリゾルバーは passthrough
として作成されます。
これがNewClient()からは dns
になったためです。
bufconnは passthrough
であることが前提で作られているためエラーになります。
rpc error: code = Unavailable desc = name resolver error: produced zero addresses
対処法
従来通りに戻してやれば動きます。具体的にはNewClient()より前に
resolver.SetDefaultScheme("passthrough")
の記述を入れます。もしくは引数として渡すtargetにURLスキームとして "passthrough://"+
のように手で追加しても大丈夫ですが、せっかく変更用の関数が提供されているのでデフォルトを変更する方が素直だと思います。
但しこの関数はスレッドセーフではないのでinit()に入れたりsync.Mutexやsync.Once等でレースコンディションを防止した方がよいでしょう
サンプル
従来のコード
ln := bufconn.Listen(1024 * 1024)
dialOpts := []grpc.DialOption{
grpc.WithTransportCredentials(insecure.NewCredentials()),
grpc.WithContextDialer(func(_ context.Context, _ string) (net.Conn, error) {
return ln.Dial()
}),
}
conn, _ := grpc.Dial(ln.Addr().String(), dialOpts...)
コケるコード
ln := bufconn.Listen(1024 * 1024)
dialOpts := []grpc.DialOption{
grpc.WithTransportCredentials(insecure.NewCredentials()),
grpc.WithContextDialer(func(_ context.Context, _ string) (net.Conn, error) {
return ln.Dial()
}),
}
conn, _ := grpc.NewClient(ln.Addr().String(), dialOpts...) // 単純に置き換えただけ
通るコード
ln := bufconn.Listen(1024 * 1024)
dialOpts := []grpc.DialOption{
grpc.WithTransportCredentials(insecure.NewCredentials()),
grpc.WithContextDialer(func(_ context.Context, _ string) (net.Conn, error) {
return ln.Dial()
}),
}
resolver.SetDefaultScheme("passthrough") // これで従来と同じ設定になる
conn, _ := grpc.NewClient(ln.Addr().String(), dialOpts...)
もしくは
ln := bufconn.Listen(1024 * 1024)
dialOpts := []grpc.DialOption{
grpc.WithTransportCredentials(insecure.NewCredentials()),
grpc.WithContextDialer(func(_ context.Context, _ string) (net.Conn, error) {
return ln.Dial()
}),
}
//resolver.SetDefaultScheme("passthrough")
conn, _ := grpc.NewClient("passthrough://"+ln.Addr().String(), dialOpts...) // 手でスキーム追加しても一応動く
Discussion