возможно ли сообщение nil server с помощью gRPC? - PullRequest
2 голосов
/ 13 мая 2019

В следующем gRPC -клиенте, необходим ли второй if?

status, err := cli.GetStatus(ctx, &empty.Empty{})
if err != nil {
    return err
}

if status == nil {
    // this should NEVER happen - right?
    return fmt.Errorf("nil Status result returned") 
}

Интуитивно, всегда нужно проверять ноль в go на всякий случай . Тем не менее, существует проверка во время выполнения для отслеживания любого использования клиент-сервер nil, например,

status, err := cli.GetStatus(ctx, nil) // <- runtime error

if err != nil {
    // "rpc error: code = Internal desc = grpc: error while marshaling: proto: Marshal called with nil"
    return err
}

Так есть ли аналогичная гарантия времени выполнения между серверами и, таким образом, устраняется необходимость проверки status == nil?

Ответы [ 2 ]

1 голос
/ 14 мая 2019

Дальнейшее расследование на примере искусственного сервера:

func (s *mygRPC) GetStatus(context.Context, *empty.Empty) (*pb.Status, error) {
    log.Println("cli: GetStatus()")

    //return &pb.Status{}, nil
    return nil, nil // <- can server return a nil status message (with nil error)
}

и тестирование реакций клиент / сервер:

КЛИЕНТ:

ERROR: rpc error: code = Internal desc = grpc: error while marshaling: proto: Marshal called with nil

SERVER:

2019/05/14 16:09:50 cli: GetStatus()
ERROR: 2019/05/14 16:09:50 grpc: server failed to encode response:  rpc error: code = Internal desc = grpc: error while marshaling: proto: Marshal called with nil

Таким образом, даже если кто-то хочет законно вернуть нулевое значение, транспорт gRPC не допустит его.

Примечание: код на стороне сервера все еще выполняется - как и ожидалось, - но, что касается клиента, вызов gRPC не удался.

Вывод: действительный (err==nil) ответ сервера всегда вернет правильное (не nil) сообщение.


РЕДАКТИРОВАТЬ:

Проверка источника gRPC показывает, где перехвачено сообщение nil:

server.go

func (s *Server) sendResponse(t transport.ServerTransport, stream *transport.Stream, msg interface{}, cp Compressor, opts *transport.Options, comp encoding.Compressor) error {
    data, err := encode(s.getCodec(stream.ContentSubtype()), msg)
    if err != nil {
        grpclog.Errorln("grpc: server failed to encode response: ", err)
        return err
    }
    // ...
}

rpc_util.go

func encode(c baseCodec, msg interface{}) ([]byte, error) {
    if msg == nil { // NOTE: typed nils will not be caught by this check
        return nil, nil
    }
    b, err := c.Marshal(msg)
    if err != nil {
        return nil, status.Errorf(codes.Internal, "grpc: error while marshaling: %v", err.Error())
    }
    // ...
}

Комментарий в этой строке является ключевым:

if msg == nil { // NOTE: typed nils will not be caught by this check }

Так что, если бы кто-то использовал отражение на нашем набранном нуле, reflect.ValueOf(msg).IsNil() вернул бы true.Следующие c.Marshal(msg) ошибок - и вызов не может отправить ответное сообщение клиенту.

1 голос
/ 14 мая 2019

Да, этого никогда не должно случиться.GRPC несет ответственность за это.

...