Skip to content

Commit 0417d12

Browse files
committed
address @arvindbr8's comments
1 parent 57b40ef commit 0417d12

File tree

2 files changed

+61
-61
lines changed

2 files changed

+61
-61
lines changed

Documentation/anti-patterns.md

Lines changed: 61 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,38 @@
11
## Anti-Patterns
22

33
### Dialing in gRPC
4-
[`grpc.Dial`](https://pkg.go.dev/google.golang.org/grpc#Dial) is a function in
5-
the gRPC library that creates a virtual connection from the gRPC client to the
6-
gRPC server. It takes a target URI (which can represent the name of a logical
7-
backend service and could resolve to multiple actual addresses) and a list of
8-
options, and returns a
4+
5+
[`grpc.NewClient`](https://pkg.go.dev/google.golang.org/grpc#NewClient) is a
6+
function in the gRPC library that creates a virtual connection from the gRPC
7+
client to the gRPC server. It takes a target URI (which can represent the name
8+
of a logical backend service and could resolve to multiple actual addresses) and
9+
a list of options, and returns a
910
[`ClientConn`](https://pkg.go.dev/google.golang.org/grpc#ClientConn) object that
10-
represents the connection to the server. The `ClientConn` contains one or more
11+
represents the connection to the server. The `ClientConn` contains one or more
1112
actual connections to real server backends and attempts to keep these
1213
connections healthy by automatically reconnecting to them when they break.
14+
`NewClient` is made available from gRPC-Go >v1.63.
15+
16+
`grpc.NewClient` automatically ignores `DialOptions` returned by `WithBlock`,
17+
`WithTimeout`, `WithReturnConnectionError`, and `FailOnNonTempDialError.
1318

14-
The `Dial` function can also be configured with various options to customize the
15-
behavior of the client connection. For example, developers could use options
16-
such a
19+
### Difference between Dial and NewClient
20+
21+
`grpc.Dial` uses passthrough as the default name resolver for backward
22+
compatibility while `grpc.NewClient` uses dns as its default name resolver. This
23+
subtle diffrence is crucial in legacy systems that specify a custom dialer and
24+
expect it to receive the target string directly. However, the usage of `Dial`
25+
and `DialContext` is discouraged and from gRPC-Go v1.63 users should use
26+
`grpc.NewClient` instead. But keep in mind, `Dial` and `DialContext` will be
27+
supported throughout 1.x.
28+
29+
#### Why is using grpc.Dial discouraged
30+
31+
[`grpc.Dial`](https://pkg.go.dev/google.golang.org/grpc#NewClient) is also a
32+
function in the gRPC library that creates a virtual connection from the gRPC
33+
client to the gRPC server. The `Dial` function can also be configured with
34+
various options to customize the behavior of the client connection. For example,
35+
developers could use options such a
1736
[`WithTransportCredentials`](https://pkg.go.dev/google.golang.org/grpc#WithTransportCredentials)
1837
to configure the transport credentials to use.
1938

@@ -23,7 +42,7 @@ actually perform the low-level network dialing operation like
2342
connection from the gRPC client to the gRPC server.
2443

2544
`Dial` does initiate the process of connecting to the server, but it uses the
26-
ClientConn object to manage and maintain that connection over time. This is why
45+
ClientConn object to manage and maintain that connection over time. This is why
2746
errors encountered during the initial connection are no different from those
2847
that occur later on, and why it's important to handle errors from RPCs rather
2948
than relying on options like
@@ -34,47 +53,35 @@ In fact, `Dial` does not always establish a connection to servers by default.
3453
The connection behavior is determined by the load balancing policy being used.
3554
For instance, an "active" load balancing policy such as Round Robin attempts to
3655
maintain a constant connection, while the default "pick first" policy delays
37-
connection until an RPC is executed. Instead of using the WithBlock option, which
38-
may not be recommended in some cases, you can call the
56+
connection until an RPC is executed. Instead of using the WithBlock option,
57+
which may not be recommended in some cases, you can call the
3958
[`ClientConn.Connect`](https://pkg.go.dev/google.golang.org/grpc#ClientConn.Connect)
4059
method to explicitly initiate a connection.
41-
[`WithBlock`](https://pkg.go.dev/google.golang.org/grpc#WithBlock) in an instance where WithBlock(true) is used, `Connect` and `WaitForStateChange` is invoked until either the context created via `context.WithTimeout` expires or the `ClientConn` is ready.
4260

4361
### Using `FailOnNonTempDialError`, `WithBlock`, and `WithReturnConnectionError`
4462

4563
The gRPC API provides several options that can be used to configure the behavior
46-
of dialing and connecting to a gRPC server. Some of these options, such as
64+
of dialing and connecting to a gRPC server. Some of these options, such as
4765
`FailOnNonTempDialError`, `WithBlock`, and `WithReturnConnectionError`, rely on
48-
failures at dial time. However, we strongly discourage developers from using
66+
failures at dial time. However, we strongly discourage developers from using
4967
these options, as they can introduce race conditions and result in unreliable
5068
and difficult-to-debug code.
5169

5270
One of the most important reasons for avoiding these options, which is often
53-
overlooked, is that connections can fail at any point in time. This means that
71+
overlooked, is that connections can fail at any point in time. This means that
5472
you need to handle RPC failures caused by connection issues, regardless of
5573
whether a connection was never established in the first place, or if it was
5674
created and then immediately lost. Implementing proper error handling for RPCs
5775
is crucial for maintaining the reliability and stability of your gRPC
5876
communication.
5977

60-
### Difference between Dial and NewClient
61-
[`grpc.NewClient`](https://pkg.go.dev/google.golang.org/grpc#NewClient) is a function in the grpc libaray that creates a new gRPC `channel` for the target URI that is passed in as an argument, together with a list of `DialOption`, and returns [`ClientConn`](https://pkg.go.dev/google.golang.org/grpc#ClientConn) an object representing a server connection.
62-
63-
Unlike `grpc.NewClient`, whereby using the ClientConn for RPCs will automatically cause it to connect or `Connect` may be used to manually create a connection, by default `Dial` does not always establish a connection to servers. Connection behavior is determined by the load balancing policy used.
64-
65-
`grpc.NewClient` automatically ignores `DialOptions` returned by `WithBlock`, `WithTimeout`, `WithReturnConnectionError`, and `FailOnNonTempDialError.
66-
67-
`grpc.NewClient` uses passthrough as the default name resolver for backward compatibility while `Dial` uses dns as its default name resolver. This subtle diffrence is crucial in legacy systems that specify a custom dialer and expect it to receive the target string directly.
68-
69-
Timeouts are not supported by `grpc.NewClient`.
70-
7178
### Why we discourage using `FailOnNonTempDialError`, `WithBlock`, and `WithReturnConnectionError`
7279

7380
When a client attempts to connect to a gRPC server, it can encounter a variety
7481
of errors, including network connectivity issues, server-side errors, and
75-
incorrect usage of the gRPC API. The options `FailOnNonTempDialError`,
82+
incorrect usage of the gRPC API. The options `FailOnNonTempDialError`,
7683
`WithBlock`, and `WithReturnConnectionError` are designed to handle some of
77-
these errors, but they do so by relying on failures at dial time. This means
84+
these errors, but they do so by relying on failures at dial time. This means
7885
that they may not provide reliable or accurate information about the status of
7986
the connection.
8087

@@ -87,26 +94,26 @@ network issues that are resolved shortly after the initial dial attempt.
8794
## Best practices for error handling in gRPC
8895

8996
Instead of relying on failures at dial time, we strongly encourage developers to
90-
rely on errors from RPCs. When a client makes an RPC, it can receive an error
91-
response from the server. These errors can provide valuable information about
97+
rely on errors from RPCs. When a client makes an RPC, it can receive an error
98+
response from the server. These errors can provide valuable information about
9299
what went wrong, including information about network issues, server-side errors,
93100
and incorrect usage of the gRPC API.
94101

95102
By handling errors from RPCs correctly, developers can write more reliable and
96-
robust gRPC applications. Here are some best practices for error handling in
103+
robust gRPC applications. Here are some best practices for error handling in
97104
gRPC:
98105

99-
- Always check for error responses from RPCs and handle them appropriately.
100-
- Use the `status` field of the error response to determine the type of error that
101-
occurred.
106+
- Always check for error responses from RPCs and handle them appropriately.
107+
- Use the `status` field of the error response to determine the type of error
108+
that occurred.
102109
- When retrying failed RPCs, consider using the built-in retry mechanism
103110
provided by gRPC-Go, if available, instead of manually implementing retries.
104111
Refer to the [gRPC-Go retry example
105112
documentation](https://github.com/grpc/grpc-go/blob/master/examples/features/retry/README.md)
106113
for more information.
107114
- Avoid using `FailOnNonTempDialError`, `WithBlock`, and
108-
`WithReturnConnectionError`, as these options can introduce race conditions and
109-
result in unreliable and difficult-to-debug code.
115+
`WithReturnConnectionError`, as these options can introduce race conditions
116+
and result in unreliable and difficult-to-debug code.
110117
- If making the outgoing RPC in order to handle an incoming RPC, be sure to
111118
translate the status code before returning the error from your method handler.
112119
For example, if the error is an `INVALID_ARGUMENT` error, that probably means
@@ -118,7 +125,7 @@ gRPC:
118125
The following code snippet demonstrates how to handle errors from an RPC in
119126
gRPC:
120127

121-
```go
128+
```go
122129
ctx, cancel := context.WithTimeout(context.Background(), time.Second)
123130
defer cancel()
124131

@@ -130,7 +137,7 @@ if err != nil {
130137
return nil, err
131138
}
132139

133-
// Use the response as appropriate
140+
// Use the response as appropriate
134141
log.Printf("MyRPC response: %v", res)
135142
```
136143

@@ -139,25 +146,25 @@ the error response:
139146

140147

141148
```go
142-
resp, err := client.MakeRPC(context.Background(), request)
149+
resp, err := client.MakeRPC(context.Background(), request)
143150
if err != nil {
144-
status, ok := status.FromError(err)
151+
status, ok := status.FromError(err)
145152
if ok {
146-
// Handle the error based on its status code
153+
// Handle the error based on its status code
147154
if status.Code() == codes.NotFound {
148155
log.Println("Requested resource not found")
149156
} else {
150157
log.Printf("RPC error: %v", status.Message())
151158
}
152159
} else {
153-
//Handle non-RPC errors
160+
// Handle non-RPC errors
154161
log.Printf("Non-RPC error: %v", err)
155162
}
156163
return
157-
}
164+
}
158165

159-
// Use the response as needed
160-
log.Printf("Response received: %v", resp)
166+
// Use the response as needed
167+
log.Printf("Response received: %v", resp)
161168
```
162169

163170
### Example: Using a backoff strategy
@@ -167,7 +174,7 @@ When retrying failed RPCs, use a backoff strategy to avoid overwhelming the
167174
server or exacerbating network issues:
168175

169176

170-
```go
177+
```go
171178
var res *MyResponse
172179
var err error
173180

@@ -177,16 +184,16 @@ defer cancel()
177184

178185
// Retry the RPC call a maximum number of times
179186
for i := 0; i < maxRetries; i++ {
180-
187+
181188
// Make the RPC call
182189
res, err = client.MyRPC(ctx, &MyRequest{})
183-
190+
184191
// Check if the RPC call was successful
185192
if err == nil {
186193
// The RPC was successful, so break out of the loop
187194
break
188195
}
189-
196+
190197
// The RPC failed, so wait for a backoff period before retrying
191198
backoff := time.Duration(i) * time.Second
192199
log.Printf("Error calling MyRPC: %v; retrying in %v", err, backoff)
@@ -212,7 +219,7 @@ The
212219
[`WithBlock`](https://pkg.go.dev/google.golang.org/grpc#WithBlock), and
213220
[`WithReturnConnectionError`](https://pkg.go.dev/google.golang.org/grpc#WithReturnConnectionError)
214221
options are designed to handle errors at dial time, but they can introduce race
215-
conditions and result in unreliable and difficult-to-debug code. Instead of
216-
relying on these options, we strongly encourage developers to rely on errors
217-
from RPCs for error handling. By following best practices for error handling in
218-
gRPC, developers can write more reliable and robust gRPC applications.
222+
conditions and result in unreliable and difficult-to-debug code. Instead of
223+
relying on these options, we strongly encourage developers to use
224+
`grpc.NewClient`. By following best practices for error handling in gRPC,
225+
developers can write more reliable and robust gRPC applications.

examples/features/orca/client/main.go

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -97,14 +97,7 @@ type orcaLB struct {
9797
}
9898

9999
func (o *orcaLB) UpdateClientConnState(ccs balancer.ClientConnState) error {
100-
// We assume only one update, ever, containing exactly one address, given
101-
// the use of the "passthrough" (default) name resolver.
102-
103100
addrs := ccs.ResolverState.Addresses
104-
// if len(addrs) != 1 {
105-
// return fmt.Errorf("orcaLB: expected 1 address; received: %v", addrs)
106-
// }
107-
108101
// Create one SubConn for the address and connect it.
109102
var sc balancer.SubConn
110103
sc, err := o.cc.NewSubConn(addrs, balancer.NewSubConnOptions{

0 commit comments

Comments
 (0)