Best practice for defining gRPC metadata about a stream

Viewed 1807

I have to send a stream of messages to a gRPC server, but I also have to send a significant amount of metadata about the stream. Is there a way to define the metadata message and make it part of the interface contract between the client and the server? As far as I can tell, it looks like marshaling another message into metadata is completely outside the interface definition in my .proto file.

Really, I'd love for gRPC to allow streaming calls to have two parameters like:

service DataServer {
    rpc AddData(DataScope, stream MyData) returns (Reply) {}
}

Is there a right, or at least a generally accepted way to approach this?

3 Answers

It's not possible as you want (as you know) but, it's functionally equivalent to:

service DataServer {
    rpc AddStream(AddStreamRequest) returns (AddStreamResponse) {}
    rpc AddData(stream MyData) returns (Reply) {}
}

Where AddStreamResponse includes a unique (stream) identifier that is referenced within MyData.

We decided to embed an optional stream definition "header" message in the MyData stream message. We only populate that header message in the first MyData message of the stream.

message StreamBlock {
    DataScope header = 1;
    MyData    data   = 2;
}

When the data is short enough to all fit in a single MyData protobuf message, it allows us to send the header and data in a single gRPC roundtrip call. When the data is longer and broken up into several MyData messages, the unused header field in subsequent messages uses no space, so there is no extra overhead.

Unfortunately, this is not possible. But here is an equivalent:

You can use the oneof keyword to specify that the request should contain the configuration (scope) or the data. Your client will easily understand that the first object in their AddDataRequest stream must contain the scope and the following objects must contain data. Your server implementation have to assert this behavior.

service DataServer {
    rpc AddData(stream AddDataRequest) returns (AddDataReply) {}
}

message AddDataRequest {
    oneof request {
        AddDataConfiguration configuration = 1;
        Data data = 2;
    }
}
Related