TLDR;如果我的Go gRPC双向流媒体服务器无限循环Recv
/ Send
,当我的客户stream
超出范围并获得GC时,如何关闭连接? #39; d
我们假设我正在使用Go进行gRPC双向流媒体通话:
syntax = "proto3";
package mystical;
service Unicorn {
rpc RainbowStream(stream Rainbow) returns (stream Rainbow);
}
我有一个服务器实现,我将在我的gRPC服务器上注册:
type Server struct {}
func (serv *Server) RainbowStream(stream proto.Unicorn_RainbowStreamServer) error {
// Stub implementation
// Just sends the rainbows back
for {
msg, err := stream.Recv()
if err != nil {
return err
}
if err := stream.Send(msg); err != nil {
return err
}
}
}
然后我有一个客户,忽略了gRPC的一些细节:
type Client struct {
proto.UnicornClient
}
func (c *Client) TastyColors() (stream proto.Unicorn_RainbowStreamClient, err error) {
return c.RainbowStream()
}
我这样做:
func somewhereDeepInMyCode() {
stream, err := aClient.TastyColors()
// ...
go func() {
stream.Send(msg)
// ...
// eventually this goroutine ends
// and `stream` would get GC'd
}
}
当stream
超出范围时,gRPC流媒体呼叫会自行清理吗?通常,根据我的理解,服务器必须返回其RainbowStream
调用以关闭连接。如果它没有自我清理,我怎么能实现这个目标呢?
答案 0 :(得分:1)
使用取消(https://golang.org/pkg/context/#WithCancel)上下文从客户端取消:
func somewhereDeepInMyCode() {
ctx, cancel := context.WithCancel(context.Background())
stream, err := aClient.TastyColors(ctx)
// ...
go func() {
defer cancel()
stream.Send(msg)
// ...
// eventually this goroutine ends
// and `stream` would get GC'd
}
}
服务器可以根据需要处理客户端取消以进行清理:
for {
select {
...
case <-stream.Context().Done():
// cleanup
...
}
}