I am trying to add values to the context being passed into the service methods using the request_context option when generating. The generated code seems to be doing the right thing, and the code for the runtime appears that it should do the right thing too, but I am not getting the modified context in the service handlers.
- $GOPATH/src/test
- pb
test.proto
main.go
test.proto
syntax = "proto3";
package pb;
import "google/api/annotations.proto";
message TestRequest {
string data = 1;
}
message TestResponse {
string data = 1;
}
service TestSvc {
rpc GetTest(TestRequest) returns (TestResponse) {
option (google.api.http) = {
get: "/test",
};
}
}
main.go
package main
import (
"github.com/grpc-ecosystem/grpc-gateway/runtime"
"golang.org/x/net/context"
"google.golang.org/grpc"
"log"
"net"
"net/http"
"test/grpc-gateway-context-issue/pb"
)
type ctxKey struct{}
func main() {
ctx := context.Background()
ctx, cancel := context.WithCancel(ctx)
defer cancel()
// start grpc service in background
go startService()
mux := runtime.NewServeMux()
opts := []grpc.DialOption{grpc.WithInsecure()}
err := pb.RegisterTestSvcHandlerFromEndpoint(ctx, mux, "localhost:10000", opts)
if err != nil {
log.Fatal(err)
}
handler := http.NewServeMux()
handler.Handle("/", contextWrap(mux))
if err := http.ListenAndServe(":8081", handler); err != nil {
log.Fatal(err)
}
}
func contextWrap(h http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
req = req.WithContext(context.WithValue(req.Context(), ctxKey{}, "test"))
log.Println("in wrapper, context value is", req.Context().Value(ctxKey{}))
h.ServeHTTP(w, req)
})
}
func startService() {
lis, err := net.Listen("tcp", ":10000")
if err != nil {
log.Fatal(err)
}
s := grpc.NewServer()
pb.RegisterTestSvcServer(s, &testSvc{})
if err := s.Serve(lis); err != nil {
log.Fatalf("While serving gRPC request: %v", err)
}
}
type testSvc struct{}
func (svc *testSvc) GetTest(ctx context.Context, req *pb.TestRequest) (*pb.TestResponse, error) {
log.Println("in service, context value is", ctx.Value(ctxKey{}))
return &pb.TestResponse{
Data: req.Data,
}, nil
}
The proto file was compiled using protoc --go_out=plugins=grpc:pb --grpc-gateway_out=logtostderr=true,request_context=true:pb -I$GOPATH/src/github.com/grpc-ecosystem/grpc-gateway/third_party/googleapis -Ipb pb/test.proto
When I run this, and curl localhost:8081/test I would expect the server logs to print out
in wrapper, context value is test
in service, context value is test
But instead I get
in wrapper, context value is test
in service, context value is <nil>
Could you try recompiling the protoc with current head? This is now the default behavior so it should work. I'm going to close this preemptively but feel free to reopen if you're having issues still.
@achew22 Is it included in v1.3.1 release? Cannot make it working. I'm on the latest commit 6658b3a.
I am experiencing the same problem with my project along with this basic example by @paulbdavis
2018/03/12 11:27:39 Starting service
2018/03/12 11:27:45 in wrapper, context value is test
2018/03/12 11:27:45 in service, context value is <nil>
[pd@XPS pb]$ protoc --version
libprotoc 3.5.1
[pd@XPS pb]$ go version
go version go1.10 linux/amd64
From looking at the generated code, it seems as though the context is lost because the generated HTTP handler doesn't directly call the service method — it calls it through the gRPC client, same as it would if it were making a network RPC.
Not sure how to pass the context across this boundary, other than to change the library to take the server objects directly when initializing a gateway (instead of a net.ClientConn) and then call the service methods directly, instead of through gRPC. That seems like a pretty drastic change though.
Looks like you're supposed to solve this problem using gwruntime.WithMetadata(…), which passes some string-string key-value pairs through the gRPC boundary.
Huh, that is not what I would expect. If you have this flag set I would have expected it to reuse the context from the inbound http context in the grpc outbound context. Could you file a new issue documenting the issues you're having?
Most helpful comment
Looks like you're supposed to solve this problem using
gwruntime.WithMetadata(…), which passes some string-string key-value pairs through the gRPC boundary.