grpcConst

package module
v0.0.0-...-7d797cb Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Mar 8, 2021 License: Unlicense Imports: 9 Imported by: 0

README

gRPC constant

grpcConst is a slim reflection based tool to populate the client side data of gRPC messages without having to send that data in every message. This is useful to reduce the data transported between services where the stream messages share data.

An example could be for spatiotemporal data where you may send several thousand data points that all share the same location, because a user queried a specific datatype (e.g temperature), at a specific location. And want to have a timeseries displayed. This data may share location, maybe a location name and you could have other fields that are added as convenience to the data, but those fields are constant across the request.

Specification

Client side sends a header of key x-grpc-const this signals the server that it implements this feature.

For a given message returned by an RPC server side stream. The server sends a defaulting proto marshal'ed base64 URLencoded header x-grpc-const this object of the same type of the message will be the default values for the client side to add to all messages.

The client side does the most of the work, decoding, unmarshaling and padding the message with this data.

Overriding

Any message sent with a value in the same place as the default constant message will override the default.
You cannot override the default by setting the value to 0, null, empty string or empty list as they are considered empty, you cannot set these values as default, and that wouldn't make sense as they are default already. This is an important limitation; if you expect to be able to send actual data of value 0, don't set a default on that value! This is a limitation of simple data types.

Implementation

This is a golang implementation. The client side is made as an interceptor that decorates the streams' grpc.ClientStream, overriding the method RecvMsg.

A client simply initiate it's client connection with an interceptor grpcConst.StreamClientInterceptor.

A convenience method grpcConst.HeaderSetConstant can be used to construct the header that can be sent using your server-side stream.SendHeader before sending messages.

For the full automatic experience on the server-side wrap your stream using grpcConst.ServerStreamWrapper to reduce the default data before sending your messages

see examples

Testing the overhead

This is tested vs. the gRPC example route_guide.proto. In this example the unmarshalling and figuring the fields to set takes about 1 µs. Handling these (two) values on each message takes 45 ns (whether you set a value or not). When no header is sent, the overhead of the clientStream is 7 ns pr. message (tested on my local pc).

BenchmarkDataAddingClientStream_RecvMsgSimple           # This merges two values into an object
BenchmarkDataAddingClientStream_RecvMsgSimple-8       	15383833            67.5 ns/op
BenchmarkDataAddingClientStream_RecvMsgNil              # This doesn't initiate anything
BenchmarkDataAddingClientStream_RecvMsgNil-8          	86265670            14.2 ns/op
BenchmarkDataAddingClientStream_RecvMsgNeverWrite       # This checks for the values but never writes them
BenchmarkDataAddingClientStream_RecvMsgNeverWrite-8   	16704519            67.8 ns/op
BenchmarkDataAddingClientStream_RecvMsgLarger           # This merges 12 default values
BenchmarkDataAddingClientStream_RecvMsgLarger-8       	5098196             231 ns/op
BenchmarkInitiation                                     # Initiation and merge one message
BenchmarkInitiation-8                                   239176              4349 ns/op

Locally using this specification does not make much sense, but this should help you if your network/ infrastructure is network I/O limited. As a side-note (anecdotal evidence), when in a video-conference the local clients that uses this library (and one that does not) starts performing more evenly (to see this example check example/ogc_ish).
To compare with imdario/mergo (which is not at all fair, as the focus is on safety and configurability, not performance) a benchmark on my computer, says (this is the same result as BenchmarkInitiation):

BenchmarkMergo
BenchmarkMergo-8   	  159506	      6740 ns/op

TODO

  • possibly write reflection merger using protoreflect
  • benchmark reducer
  • remove reflect from generated code (probably have to do equality-methods)

Documentation

Overview

grpcConst is a package that allow you to communicate defaulting values of your protobuf messages and communicate this default and set it before your client side code interacts with the messages. example server-side:

header, err := grpcConst.HeaderSetConstant(
		&proto.Feature{
			Name: "some constant name",
			Location: &proto.Point{Latitude: 10}
})
stream.SetHeader(header)
	... your normal routine but you could
	... fx send &proto.Feature{Location: &proto.Point{Longitude: 20}}
	... this will yield - name: "some constant name", location: {10, 20}
	... while sending less data in the message

or:

     stream = grpcConst.ServerStreMWrapper(
				&proto.Feature{
					Name: "some constant name",
					Location: &proto.Point{Latitude: 10}
		})
			... using stream.Send() now removes the default values from your objects; sending less data

example client-side: initiate your client with a grpc.StreamClientInterceptor this way:

conn, err := grpc.Dial(...,  grpc.WithStreamInterceptor(grpcConst.StreamClientInterceptor()))

Index

Constants

View Source
const XgRPCConst = "x-grpc-const"

XgRPCConst is the HTTP header passed between server and client

Variables

This section is empty.

Functions

func HeaderSetConstant

func HeaderSetConstant(v interface{}) (metadata.MD, error)

HeaderSetConstant is a convenience method for the server side to add a metadata.MD with the correct content given your gRPC struct v, the user is returned the metadata to send. that the user can send using `grpc.ServerStream:SendHeader(metadata.MD) or :SetHeader(metadata.MD)`. v must be passed by reference.

func ServerStreamWrapper

func ServerStreamWrapper(reference interface{}) (stream grpc.ServerStream, err error)

ServerStreamWrapper wraps your stream object and returns the decorated stream with a SendMsg method, that removes items that are equal a reference object. The stream remains untouched if the client did not send an XgRPCConst header

func StreamClientInterceptor

func StreamClientInterceptor(mergerCreator ...MergerCreator) grpc.StreamClientInterceptor

StreamClientInterceptor is an interceptor for the client side (for unidirectional server-side streaming rpc's) The client side Stream interceptor intercepts the stream when it is initiated. This method decorates the actual ClientStream adding data to each message where applicable this variadic function accepts none or one argument. defaulting the method for constructing the merge.Merger to use merge.NewMerger. for a more safe alternative

Types

type Merger

type Merger interface {
	Merge(interface{})
}

Merger is the interface of a type that can merge into itself

type MergerCreator

type MergerCreator func(interface{}) merge.Merger

MergerCreator is a proxy for a function returning a merge.Merger from an interface{}

type MessageMergerReducer

type MessageMergerReducer struct {
	ConstantMessage interface{}
}

func (MessageMergerReducer) RemoveFields

func (m MessageMergerReducer) RemoveFields(msg interface{}) error

func (MessageMergerReducer) SetFields

func (m MessageMergerReducer) SetFields(msg interface{}) error

type Reducer

type Reducer interface {
	Reduce(interface{})
}

Reducer is the interface of a type that can reduce itself from a reference

Directories

Path Synopsis
cmd
examples
merge is a package with support functionality for grpcConst this helps add default values from one object to many objects the code skips a lot of reflection because much can be assumed at initiation There may be some issues with this package, it is meant for mapping structs compiled via protoc/gRPC.
merge is a package with support functionality for grpcConst this helps add default values from one object to many objects the code skips a lot of reflection because much can be assumed at initiation There may be some issues with this package, it is meant for mapping structs compiled via protoc/gRPC.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL