Skip to content

Commit e3528e3

Browse files
authored
Merge branch 'grpc:master' into master
2 parents 49df4f7 + 0e5421c commit e3528e3

File tree

82 files changed

+4226
-7743
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

82 files changed

+4226
-7743
lines changed

Documentation/server-reflection-tutorial.md

Lines changed: 61 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,9 @@
22

33
gRPC Server Reflection provides information about publicly-accessible gRPC
44
services on a server, and assists clients at runtime to construct RPC requests
5-
and responses without precompiled service information. It is used by gRPC CLI,
6-
which can be used to introspect server protos and send/receive test RPCs.
5+
and responses without precompiled service information. It is used by
6+
[gRPCurl](https://github.com/fullstorydev/grpcurl), which can be used to
7+
introspect server protos and send/receive test RPCs.
78

89
## Enable Server Reflection
910

@@ -39,36 +40,41 @@ make the following changes:
3940
An example server with reflection registered can be found at
4041
`examples/features/reflection/server`.
4142

42-
## gRPC CLI
43+
## gRPCurl
4344

44-
After enabling Server Reflection in a server application, you can use gRPC CLI
45-
to check its services. gRPC CLI is only available in c++. Instructions on how to
46-
build and use gRPC CLI can be found at
47-
[command_line_tool.md](https://github.com/grpc/grpc/blob/master/doc/command_line_tool.md).
45+
After enabling Server Reflection in a server application, you can use gRPCurl
46+
to check its services. gRPCurl is built with Go and has packages available.
47+
Instructions on how to install and use gRPCurl can be found at
48+
[gRPCurl Installation](https://github.com/fullstorydev/grpcurl#installation).
4849

49-
## Use gRPC CLI to check services
50+
## Use gRPCurl to check services
5051

5152
First, start the helloworld server in grpc-go directory:
5253

5354
```sh
54-
$ cd <grpc-go-directory>
55-
$ go run examples/features/reflection/server/main.go
55+
$ cd <grpc-go-directory>/examples
56+
$ go run features/reflection/server/main.go
5657
```
5758

58-
Open a new terminal and make sure you are in the directory where grpc_cli lives:
59-
59+
output:
6060
```sh
61-
$ cd <grpc-cpp-directory>/bins/opt
61+
server listening at [::]:50051
6262
```
6363

64-
### List services
64+
After installing gRPCurl, open a new terminal and run the commands from the new
65+
terminal.
66+
67+
**NOTE:** gRPCurl expects a TLS-encrypted connection by default. For all of
68+
the commands below, use the `-plaintext` flag to use an unencrypted connection.
6569

66-
`grpc_cli ls` command lists services and methods exposed at a given port:
70+
### List services and methods
71+
72+
The `list` command lists services exposed at a given port:
6773

6874
- List all the services exposed at a given port
6975

7076
```sh
71-
$ ./grpc_cli ls localhost:50051
77+
$ grpcurl -plaintext localhost:50051 list
7278
```
7379

7480
output:
@@ -78,72 +84,88 @@ $ cd <grpc-cpp-directory>/bins/opt
7884
helloworld.Greeter
7985
```
8086

81-
- List one service with details
87+
- List all the methods of a service
8288

83-
`grpc_cli ls` command inspects a service given its full name (in the format of
84-
\<package\>.\<service\>). It can print information with a long listing format
85-
when `-l` flag is set. This flag can be used to get more details about a
86-
service.
89+
The `list` command lists methods given the full service name (in the format of
90+
\<package\>.\<service\>).
8791

8892
```sh
89-
$ ./grpc_cli ls localhost:50051 helloworld.Greeter -l
93+
$ grpcurl -plaintext localhost:50051 list helloworld.Greeter
9094
```
9195

9296
output:
9397
```sh
94-
filename: helloworld.proto
95-
package: helloworld;
96-
service Greeter {
97-
rpc SayHello(helloworld.HelloRequest) returns (helloworld.HelloReply) {}
98-
}
98+
helloworld.Greeter.SayHello
99+
```
100+
101+
### Describe services and methods
102+
103+
- Describe all services
99104

105+
The `describe` command inspects a service given its full name (in the format
106+
of \<package\>.\<service\>).
107+
108+
```sh
109+
$ grpcurl -plaintext localhost:50051 describe helloworld.Greeter
100110
```
101111

102-
### List methods
112+
output:
113+
```sh
114+
helloworld.Greeter is a service:
115+
service Greeter {
116+
rpc SayHello ( .helloworld.HelloRequest ) returns ( .helloworld.HelloReply );
117+
}
118+
```
103119

104-
- List one method with details
120+
- Describe all methods of a service
105121

106-
`grpc_cli ls` command also inspects a method given its full name (in the
107-
format of \<package\>.\<service\>.\<method\>).
122+
The `describe` command inspects a method given its full name (in the format of
123+
\<package\>.\<service\>.\<method\>).
108124

109125
```sh
110-
$ ./grpc_cli ls localhost:50051 helloworld.Greeter.SayHello -l
126+
$ grpcurl -plaintext localhost:50051 describe helloworld.Greeter.SayHello
111127
```
112128

113129
output:
114130
```sh
115-
rpc SayHello(helloworld.HelloRequest) returns (helloworld.HelloReply) {}
131+
helloworld.Greeter.SayHello is a method:
132+
rpc SayHello ( .helloworld.HelloRequest ) returns ( .helloworld.HelloReply );
116133
```
117134

118135
### Inspect message types
119136

120-
We can use`grpc_cli type` command to inspect request/response types given the
137+
We can use the `describe` command to inspect request/response types given the
121138
full name of the type (in the format of \<package\>.\<type\>).
122139

123140
- Get information about the request type
124141

125142
```sh
126-
$ ./grpc_cli type localhost:50051 helloworld.HelloRequest
143+
$ grpcurl -plaintext localhost:50051 describe helloworld.HelloRequest
127144
```
128145

129146
output:
130147
```sh
148+
helloworld.HelloRequest is a message:
131149
message HelloRequest {
132-
optional string name = 1[json_name = "name"];
150+
string name = 1;
133151
}
134152
```
135153

136154
### Call a remote method
137155

138-
We can send RPCs to a server and get responses using `grpc_cli call` command.
156+
We can send RPCs to a server and get responses using the full method name (in
157+
the format of \<package\>.\<service\>.\<method\>). The `-d <string>` flag
158+
represents the request data and the `-format text` flag indicates that the
159+
request data is in text format.
139160

140161
- Call a unary method
141162

142163
```sh
143-
$ ./grpc_cli call localhost:50051 SayHello "name: 'gRPC CLI'"
164+
$ grpcurl -plaintext -format text -d 'name: "gRPCurl"' \
165+
localhost:50051 helloworld.Greeter.SayHello
144166
```
145167

146168
output:
147169
```sh
148-
message: "Hello gRPC CLI"
170+
message: "Hello gRPCurl"
149171
```

balancer/balancer.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -279,6 +279,14 @@ type PickResult struct {
279279
// type, Done may not be called. May be nil if the balancer does not wish
280280
// to be notified when the RPC completes.
281281
Done func(DoneInfo)
282+
283+
// Metadata provides a way for LB policies to inject arbitrary per-call
284+
// metadata. Any metadata returned here will be merged with existing
285+
// metadata added by the client application.
286+
//
287+
// LB policies with child policies are responsible for propagating metadata
288+
// injected by their children to the ClientConn, as part of Pick().
289+
Metatada metadata.MD
282290
}
283291

284292
// TransientFailureError returns e. It exists for backward compatibility and

balancer/rls/balancer.go

Lines changed: 47 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -91,14 +91,16 @@ func (rlsBB) Name() string {
9191

9292
func (rlsBB) Build(cc balancer.ClientConn, opts balancer.BuildOptions) balancer.Balancer {
9393
lb := &rlsBalancer{
94-
done: grpcsync.NewEvent(),
95-
cc: cc,
96-
bopts: opts,
97-
purgeTicker: dataCachePurgeTicker(),
98-
lbCfg: &lbConfig{},
99-
pendingMap: make(map[cacheKey]*backoffState),
100-
childPolicies: make(map[string]*childPolicyWrapper),
101-
updateCh: buffer.NewUnbounded(),
94+
closed: grpcsync.NewEvent(),
95+
done: grpcsync.NewEvent(),
96+
cc: cc,
97+
bopts: opts,
98+
purgeTicker: dataCachePurgeTicker(),
99+
dataCachePurgeHook: dataCachePurgeHook,
100+
lbCfg: &lbConfig{},
101+
pendingMap: make(map[cacheKey]*backoffState),
102+
childPolicies: make(map[string]*childPolicyWrapper),
103+
updateCh: buffer.NewUnbounded(),
102104
}
103105
lb.logger = internalgrpclog.NewPrefixLogger(logger, fmt.Sprintf("[rls-experimental-lb %p] ", lb))
104106
lb.dataCache = newDataCache(maxCacheSize, lb.logger)
@@ -110,11 +112,13 @@ func (rlsBB) Build(cc balancer.ClientConn, opts balancer.BuildOptions) balancer.
110112

111113
// rlsBalancer implements the RLS LB policy.
112114
type rlsBalancer struct {
113-
done *grpcsync.Event
114-
cc balancer.ClientConn
115-
bopts balancer.BuildOptions
116-
purgeTicker *time.Ticker
117-
logger *internalgrpclog.PrefixLogger
115+
closed *grpcsync.Event // Fires when Close() is invoked. Guarded by stateMu.
116+
done *grpcsync.Event // Fires when Close() is done.
117+
cc balancer.ClientConn
118+
bopts balancer.BuildOptions
119+
purgeTicker *time.Ticker
120+
dataCachePurgeHook func()
121+
logger *internalgrpclog.PrefixLogger
118122

119123
// If both cacheMu and stateMu need to be acquired, the former must be
120124
// acquired first to prevent a deadlock. This order restriction is due to the
@@ -167,7 +171,18 @@ type controlChannelReady struct{}
167171
// on to a channel that this goroutine will select on, thereby the handling of
168172
// the update will happen asynchronously.
169173
func (b *rlsBalancer) run() {
170-
go b.purgeDataCache()
174+
// We exit out of the for loop below only after `Close()` has been invoked.
175+
// Firing the done event here will ensure that Close() returns only after
176+
// all goroutines are done.
177+
defer func() { b.done.Fire() }()
178+
179+
// Wait for purgeDataCache() goroutine to exit before returning from here.
180+
doneCh := make(chan struct{})
181+
defer func() {
182+
<-doneCh
183+
}()
184+
go b.purgeDataCache(doneCh)
185+
171186
for {
172187
select {
173188
case u := <-b.updateCh.Get():
@@ -194,7 +209,7 @@ func (b *rlsBalancer) run() {
194209
default:
195210
b.logger.Errorf("Unsupported update type %T", update)
196211
}
197-
case <-b.done.Done():
212+
case <-b.closed.Done():
198213
return
199214
}
200215
}
@@ -203,10 +218,12 @@ func (b *rlsBalancer) run() {
203218
// purgeDataCache is a long-running goroutine which periodically deletes expired
204219
// entries. An expired entry is one for which both the expiryTime and
205220
// backoffExpiryTime are in the past.
206-
func (b *rlsBalancer) purgeDataCache() {
221+
func (b *rlsBalancer) purgeDataCache(doneCh chan struct{}) {
222+
defer close(doneCh)
223+
207224
for {
208225
select {
209-
case <-b.done.Done():
226+
case <-b.closed.Done():
210227
return
211228
case <-b.purgeTicker.C:
212229
b.cacheMu.Lock()
@@ -215,19 +232,21 @@ func (b *rlsBalancer) purgeDataCache() {
215232
if updatePicker {
216233
b.sendNewPicker()
217234
}
218-
dataCachePurgeHook()
235+
b.dataCachePurgeHook()
219236
}
220237
}
221238
}
222239

223240
func (b *rlsBalancer) UpdateClientConnState(ccs balancer.ClientConnState) error {
224241
defer clientConnUpdateHook()
225-
if b.done.HasFired() {
242+
243+
b.stateMu.Lock()
244+
if b.closed.HasFired() {
245+
b.stateMu.Unlock()
226246
b.logger.Warningf("Received service config after balancer close: %s", pretty.ToJSON(ccs.BalancerConfig))
227247
return errBalancerClosed
228248
}
229249

230-
b.stateMu.Lock()
231250
newCfg := ccs.BalancerConfig.(*lbConfig)
232251
if b.lbCfg.Equal(newCfg) {
233252
b.stateMu.Unlock()
@@ -405,10 +424,9 @@ func (b *rlsBalancer) UpdateSubConnState(sc balancer.SubConn, state balancer.Sub
405424
}
406425

407426
func (b *rlsBalancer) Close() {
408-
b.done.Fire()
409-
410-
b.purgeTicker.Stop()
411427
b.stateMu.Lock()
428+
b.closed.Fire()
429+
b.purgeTicker.Stop()
412430
if b.ctrlCh != nil {
413431
b.ctrlCh.close()
414432
}
@@ -418,6 +436,8 @@ func (b *rlsBalancer) Close() {
418436
b.cacheMu.Lock()
419437
b.dataCache.stop()
420438
b.cacheMu.Unlock()
439+
440+
<-b.done.Done()
421441
}
422442

423443
func (b *rlsBalancer) ExitIdle() {
@@ -479,8 +499,11 @@ func (b *rlsBalancer) sendNewPickerLocked() {
479499

480500
func (b *rlsBalancer) sendNewPicker() {
481501
b.stateMu.Lock()
502+
defer b.stateMu.Unlock()
503+
if b.closed.HasFired() {
504+
return
505+
}
482506
b.sendNewPickerLocked()
483-
b.stateMu.Unlock()
484507
}
485508

486509
// The aggregated connectivity state reported is determined as follows:

balancer/rls/balancer_test.go

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1048,6 +1048,43 @@ func (s) TestUpdateStatePauses(t *testing.T) {
10481048
// Make sure an RLS request is sent out.
10491049
verifyRLSRequest(t, rlsReqCh, true)
10501050

1051+
// Wait for the control channel to become READY, before reading the states
1052+
// out of the wrapping top-level balancer.
1053+
//
1054+
// makeTestRPCAndExpectItToReachBackend repeatedly sends RPCs with short
1055+
// deadlines until one succeeds. See its docstring for details.
1056+
//
1057+
// The following sequence of events is possible:
1058+
// 1. When the first RPC is attempted above, a pending cache entry is
1059+
// created, an RLS request is sent out, and the pick is queued. The
1060+
// channel is in CONNECTING state.
1061+
// 2. When the RLS response arrives, the pending cache entry is moved to the
1062+
// data cache, a child policy is created for the target specified in the
1063+
// response and a new picker is returned. The channel is still in
1064+
// CONNECTING, and retried pick is again queued.
1065+
// 3. The child policy moves through the standard set of states, IDLE -->
1066+
// CONNECTING --> READY. And for each of these state changes, a new
1067+
// picker is sent on the channel. But the overall connectivity state of
1068+
// the channel is still CONNECTING.
1069+
// 4. Right around the time when the child policy becomes READY, the
1070+
// deadline associated with the first RPC made by
1071+
// makeTestRPCAndExpectItToReachBackend() could expire, and it could send
1072+
// a new one. And because the internal state of the LB policy now
1073+
// contains a child policy which is READY, this RPC will succeed. But the
1074+
// RLS LB policy has yet to push a new picker on the channel.
1075+
// 5. If we read the states seen by the top-level wrapping LB policy without
1076+
// waiting for the channel to become READY, there is a possibility that we
1077+
// might not see the READY state in there. And if that happens, we will
1078+
// see two extra states in the last check made in the test, and thereby
1079+
// the test would fail. Waiting for the channel to become READY here
1080+
// ensures that the test does not flake because of this rare sequence of
1081+
// events.
1082+
for s := cc.GetState(); s != connectivity.Ready; s = cc.GetState() {
1083+
if !cc.WaitForStateChange(ctx, s) {
1084+
t.Fatal("Timeout when waiting for connectivity state to reach READY")
1085+
}
1086+
}
1087+
10511088
// Cache the state changes seen up to this point.
10521089
states0 := wb.getStates()
10531090

0 commit comments

Comments
 (0)