Giter VIP home page Giter VIP logo

unknownconnect-go's Introduction

unknownconnect-go

Go Go Report Card Go Reference

unknownconnect-go is an interceptor for ConnectRPC clients and servers that tells you if you are receiving protobuf messages with unknown fields. This is useful to know when you should upgrade your gRPC clients or servers to the latest version.

go get -u github.com/sudorandom/unknownconnect-go

Docs

package unknownconnect // import "github.com/sudorandom/unknownconnect-go"

// Interceptors
func NewInterceptor(opts ...option) *interceptor
func WithCallback(callback UnknownCallback) option
func WithDrop() option
type UnknownCallback func(context.Context, connect.Spec, proto.Message) error

// Helpers
func DropUnknownFields(msg protoreflect.Message)
func ForEachUnknownField(msg protoreflect.Message, cb func(msg protoreflect.Message) bool)
func MessageHasUnknownFields(msg protoreflect.Message) bool

Server Examples

Short example (logging):

unknownconnect.NewInterceptor(
    unknownconnect.WithCallback(func(ctx context.Context, spec connect.Spec, msg proto.Message) error {
        slog.Warn("received a protobuf message with unknown fields", slog.Any("spec", spec), slog.Any("msg", msg))
        return nil
    }),
)

Dropping unknown fields:

unknownconnect.NewInterceptor(unknownconnect.WithDrop())

Full example (returning an error):

import (
    "log/slog"

    "connectrpc.com/connect"
    unknownconnect "github.com/sudorandom/unknownconnect-go"
)

func main() {
    greeter := &GreetServer{}
    mux := http.NewServeMux()
    path, handler := greetv1connect.NewGreetServiceHandler(greeter, connect.WithInterceptors(
        unknownconnect.NewInterceptor(
            unknownconnect.WithCallback(func(ctx context.Context, spec connect.Spec, msg proto.Message) error {
                return connect.NewError(connect.InvalidArgument, err)
            }),
    )))
    mux.Handle(path, handler)
    http.ListenAndServe("localhost:8080", h2c.NewHandler(mux, &http2.Server{}))
}

The first example simply emits a warning log and the second example will fail the request if the server receives a message with unknown fields. You can decide what to do. Here are some ideas:

  • Add to a metric that counts how often this happens
  • Drop the unknown fields
  • Fail the request/response; maybe the most useful in non-production integration environments
  • Emit a log
  • Add an annotation to the context to be used in the handler
  • ???

Client Examples

And it works the same for clients, too:

package main

import (
    "context"
    "log/slog"
    "net/http"

    greetv1 "example/gen/greet/v1"
    "example/gen/greet/v1/greetv1connect"

    "connectrpc.com/connect"
)

func main() {
    client := greetv1connect.NewGreetServiceClient(
        http.DefaultClient,
        "http://localhost:8080",
        connect.WithInterceptors(
            unknownconnect.NewInterceptor(
                unknownconnect.WithCallback(func(ctx context.Context, spec connect.Spec, msg proto.Message) error {
                    slog.Warn("received a protobuf message with unknown fields", slog.Any("spec", spec), slog.Any("msg", msg))
                    return nil
                }),
        )),
    )
    res, err := client.Greet(
        context.Background(),
        connect.NewRequest(&greetv1.GreetRequest{Name: "Jane"}),
    )
    if err != nil {
        slog.Error(err.Error())
        return
    }
    slog.Info(res.Msg.Greeting)
}

Why?

gRPC systems can be quite complex. When making additions to protobuf files the server or the client often gets updated at different times. In a perfect world, this would all be synchronized. But we live in reality. Sometimes release schedules differ between components. Sometimes you just forget to update a component. Many times you might be consuming a gRPC service managed by another team and they don't tell you that they're changing things. I believe this interceptor helps with all of these cases. It allows you to raise the issue before it becomes a problem.

unknownconnect-go's People

Contributors

sudorandom avatar

Stargazers

Adam Shaw avatar

Watchers

 avatar

unknownconnect-go's Issues

Add optional sampling percentage

Since it can be very expensive to use reflection to traverse messages and look for unknown fields there should be an option to only look for unknown fields a percentage of the time. This would make it more reasonable to run this in production while also giving the ability to (eventually) detect mismatched clients/servers. Maybe the interface looks like this:

unknownconnect.NewInterceptor(
    unknownconnect.WithCallback(func(ctx context.Context, spec connect.Spec, msg proto.Message) error {
        slog.Warn("received a protobuf message with unknown fields", slog.Any("spec", spec), slog.Any("msg", msg))
        return nil
    }),
    unknownconnect.WithSampleRate(0.1),
)

This would sample 10% of requests for unknown fields.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.