Go gRPC Stream Scope - PullRequest
       28

Go gRPC Stream Scope

0 голосов
/ 10 июня 2018

TLDR;Если мой сервер двунаправленной потоковой передачи Go gRPC бесконечно зацикливается на Recv / Send, как я могу закрыть соединение, когда stream моего клиента выходит из области действия и получает GC'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 вызов, чтобы закрыть соединение.Если это не самоочищается, как я могу этого достичь?

1 Ответ

0 голосов
/ 10 июня 2018

Используйте контекст отмены (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
    ...
    }
}
...