-
Notifications
You must be signed in to change notification settings - Fork 4.4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
chore: expose NewClient
method to end users
#7010
Changes from 15 commits
3575d42
5455592
06bb15f
3db24a8
fec57e6
50f2e9b
20d1967
5b9e5d3
461c791
4884fef
9b16013
87a7cb7
d405471
bfcfd81
6ad5013
ed128db
5938a72
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -33,29 +33,75 @@ import ( | |
"google.golang.org/grpc/resolver" | ||
) | ||
|
||
func generateTarget(scheme string, target string) resolver.Target { | ||
return resolver.Target{URL: *testutils.MustParseURL(fmt.Sprintf("%s:///%s", scheme, target))} | ||
} | ||
|
||
func (s) TestParsedTarget_Success_WithoutCustomDialer(t *testing.T) { | ||
defScheme := resolver.GetDefaultScheme() | ||
dialScheme := resolver.GetDefaultScheme() | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I believe this should probably try to re-create the initial state in case another test calls |
||
newClientScheme := "dns" | ||
tests := []struct { | ||
target string | ||
wantParsed resolver.Target | ||
target string | ||
wantDialParse resolver.Target | ||
wantNewClientParse resolver.Target | ||
}{ | ||
// No scheme is specified. | ||
{target: "://a/b", wantParsed: resolver.Target{URL: *testutils.MustParseURL(fmt.Sprintf("%s:///%s", defScheme, "://a/b"))}}, | ||
{target: "a//b", wantParsed: resolver.Target{URL: *testutils.MustParseURL(fmt.Sprintf("%s:///%s", defScheme, "a//b"))}}, | ||
{ | ||
target: "://a/b", | ||
wantDialParse: generateTarget(dialScheme, "://a/b"), | ||
wantNewClientParse: generateTarget(newClientScheme, "://a/b"), | ||
}, | ||
{ | ||
target: "a//b", | ||
wantDialParse: generateTarget(dialScheme, "a//b"), | ||
wantNewClientParse: generateTarget(newClientScheme, "a//b"), | ||
}, | ||
|
||
// An unregistered scheme is specified. | ||
{target: "a:///", wantParsed: resolver.Target{URL: *testutils.MustParseURL(fmt.Sprintf("%s:///%s", defScheme, "a:///"))}}, | ||
{target: "a:b", wantParsed: resolver.Target{URL: *testutils.MustParseURL(fmt.Sprintf("%s:///%s", defScheme, "a:b"))}}, | ||
{ | ||
target: "a:///", | ||
wantDialParse: generateTarget(dialScheme, "a:///"), | ||
wantNewClientParse: generateTarget(newClientScheme, "a:///"), | ||
}, | ||
{ | ||
target: "a:b", | ||
wantDialParse: generateTarget(dialScheme, "a:b"), | ||
wantNewClientParse: generateTarget(newClientScheme, "a:b"), | ||
}, | ||
|
||
// A registered scheme is specified. | ||
{target: "dns://a.server.com/google.com", wantParsed: resolver.Target{URL: *testutils.MustParseURL("dns://a.server.com/google.com")}}, | ||
{target: "unix-abstract:/ a///://::!@#$%25^&*()b", wantParsed: resolver.Target{URL: *testutils.MustParseURL("unix-abstract:/ a///://::!@#$%25^&*()b")}}, | ||
{target: "unix-abstract:passthrough:abc", wantParsed: resolver.Target{URL: *testutils.MustParseURL("unix-abstract:passthrough:abc")}}, | ||
{target: "passthrough:///unix:///a/b/c", wantParsed: resolver.Target{URL: *testutils.MustParseURL("passthrough:///unix:///a/b/c")}}, | ||
{ | ||
target: "dns://a.server.com/google.com", | ||
wantDialParse: resolver.Target{URL: *testutils.MustParseURL("dns://a.server.com/google.com")}, | ||
wantNewClientParse: resolver.Target{URL: *testutils.MustParseURL("dns://a.server.com/google.com")}, | ||
}, | ||
{ | ||
target: "unix-abstract:/ a///://::!@#$%25^&*()b", | ||
wantDialParse: resolver.Target{URL: *testutils.MustParseURL("unix-abstract:/ a///://::!@#$%25^&*()b")}, | ||
wantNewClientParse: resolver.Target{URL: *testutils.MustParseURL("unix-abstract:/ a///://::!@#$%25^&*()b")}, | ||
}, | ||
{ | ||
target: "unix-abstract:passthrough:abc", | ||
wantDialParse: resolver.Target{URL: *testutils.MustParseURL("unix-abstract:passthrough:abc")}, | ||
wantNewClientParse: resolver.Target{URL: *testutils.MustParseURL("unix-abstract:passthrough:abc")}, | ||
}, | ||
{ | ||
target: "passthrough:///unix:///a/b/c", | ||
wantDialParse: resolver.Target{URL: *testutils.MustParseURL("passthrough:///unix:///a/b/c")}, | ||
wantNewClientParse: resolver.Target{URL: *testutils.MustParseURL("passthrough:///unix:///a/b/c")}, | ||
}, | ||
|
||
// Cases for `scheme:absolute-path`. | ||
{target: "dns:/a/b/c", wantParsed: resolver.Target{URL: *testutils.MustParseURL("dns:/a/b/c")}}, | ||
{target: "unregistered:/a/b/c", wantParsed: resolver.Target{URL: *testutils.MustParseURL(fmt.Sprintf("%s:///%s", defScheme, "unregistered:/a/b/c"))}}, | ||
{ | ||
target: "dns:/a/b/c", | ||
wantDialParse: resolver.Target{URL: *testutils.MustParseURL("dns:/a/b/c")}, | ||
wantNewClientParse: resolver.Target{URL: *testutils.MustParseURL("dns:/a/b/c")}, | ||
}, | ||
{ | ||
target: "unregistered:/a/b/c", | ||
wantDialParse: generateTarget(dialScheme, "unregistered:/a/b/c"), | ||
wantNewClientParse: generateTarget(newClientScheme, "unregistered:/a/b/c"), | ||
}, | ||
} | ||
|
||
for _, test := range tests { | ||
|
@@ -66,8 +112,18 @@ func (s) TestParsedTarget_Success_WithoutCustomDialer(t *testing.T) { | |
} | ||
defer cc.Close() | ||
|
||
if !cmp.Equal(cc.parsedTarget, test.wantParsed) { | ||
t.Errorf("cc.parsedTarget for dial target %q = %+v, want %+v", test.target, cc.parsedTarget, test.wantParsed) | ||
if !cmp.Equal(cc.parsedTarget, test.wantDialParse) { | ||
t.Errorf("cc.parsedTarget for dial target %q = %+v, want %+v", test.target, cc.parsedTarget, test.wantDialParse) | ||
} | ||
|
||
cc, err = NewClient(test.target, WithTransportCredentials(insecure.NewCredentials())) | ||
if err != nil { | ||
t.Fatalf("NewClient(%q) failed: %v", test.target, err) | ||
} | ||
defer cc.Close() | ||
|
||
if !cmp.Equal(cc.parsedTarget, test.wantNewClientParse) { | ||
t.Errorf("cc.parsedTarget for newClient target %q = %+v, want %+v", test.target, cc.parsedTarget, test.wantNewClientParse) | ||
} | ||
}) | ||
} | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -29,6 +29,7 @@ | |
|
||
"google.golang.org/grpc/attributes" | ||
"google.golang.org/grpc/credentials" | ||
"google.golang.org/grpc/internal" | ||
"google.golang.org/grpc/serviceconfig" | ||
) | ||
|
||
|
@@ -63,16 +64,18 @@ | |
} | ||
|
||
// SetDefaultScheme sets the default scheme that will be used. The default | ||
// default scheme is "passthrough". | ||
// scheme is "passthrough". | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. "default default" was not actually a typo. But maybe would be clearer if it said "the default scheme is initially set to ..." or something like that. |
||
// | ||
// NOTE: this function must only be called during initialization time (i.e. in | ||
// an init() function), and is not thread-safe. The scheme set last overrides | ||
// previously set values. | ||
func SetDefaultScheme(scheme string) { | ||
defaultScheme = scheme | ||
bruuuuuuuce marked this conversation as resolved.
Show resolved
Hide resolved
|
||
internal.UserSetDefaultScheme = true | ||
} | ||
|
||
// GetDefaultScheme gets the default scheme that will be used. | ||
// GetDefaultScheme gets the default scheme that will be used by grpc.Dial. If | ||
// SetDefaultScheme is never called, the default scheme used by grpc.NewClient is "dns" instead. | ||
func GetDefaultScheme() string { | ||
return defaultScheme | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just FYI / for the next reviewer's reference:
After this PR, I plan to rewrite things a little bit. I'd like this to become the primary API for users, and to call
Dial
andDialContext
both "deprecated" in preference of this. As such, this will contain a bit more documentation, and the others will state they call it and then initiate and wait for a connection.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@dfawley ok now with the newest release both are deprecated. But how do I add a timeout?
When I try the follwing:
the linter tells me that
grpc.WithTimeout
is deprecated I should usegrpc.DialContext
(which is deprecated too). So how do I usegrpc.NewClient
withgrpc.WithBlock
that doesn't block forever?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Setting a timeout when creating a client is an anti-pattern, and is not possible in any other gRPC implementations.
See https://github.com/grpc/grpc-go/blob/master/Documentation/anti-patterns.md#dialing-in-grpc for more info.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree that connection failures should always be checked, not only on start-up.
But if you're working with setups such as Kubernetes, you don't want your new pod to pass liveness/readiness checks in case it has an invalid connection string. It's way safer to have this "ping" check to confirm there are no misconfigurations in your new deployment, before you terminate your previous pods.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There are other, better, more robust ways of doing that. For example, health checking: https://github.com/grpc/proposal/blob/master/A17-client-side-health-checking.md
You can also use the connectivity state API if you just want to see if the client was able to connect: https://pkg.go.dev/google.golang.org/grpc#ClientConn.GetState and https://pkg.go.dev/google.golang.org/grpc#ClientConn.WaitForStateChange