Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Working from the helloworld example but getting an error on HTTP requests: grpc: the client connection is closing. Would like to improve the docs. #1924

Closed
seantcanavan opened this issue Jan 26, 2021 · 9 comments

Comments

@seantcanavan
Copy link

seantcanavan commented Jan 26, 2021

I'm a huge fan of the library and I've been hard at work for over a week trying to massage the docs into something that compiles, runs, and works. I feel I'm extremely close because my GRPC requests successfully return but my HTTP GET requests return 408 apparently?

http curl output:

Mon Jan 25 08:37 PM golang: curl -vvv http://localhost:8080/v1/saygoodbye/Sean
*   Trying 127.0.0.1:8080...
* TCP_NODELAY set
* Connected to localhost (127.0.0.1) port 8080 (#0)
> GET /v1/saygoodbye/Sean HTTP/1.1
> Host: localhost:8080
> User-Agent: curl/7.68.0
> Accept: */*
> 
* Mark bundle as not supporting multiuse
< HTTP/1.1 408 Request Timeout
< Content-Type: application/json
< Date: Tue, 26 Jan 2021 02:51:17 GMT
< Content-Length: 74
< 
* Connection #0 to host localhost left intact
{"code":1,"message":"grpc: the client connection is closing","details":[]}

the guts of server/main.go:

func runGRPCServer() {
	lis, err := net.Listen("tcp", gw.GrpcPort)
	if err != nil {
		log.Fatalf("failed to listen: %v", err)
	}
	s := grpc.NewServer()
	gw.RegisterGreeterServer(s, &gw.GreeterServerImplementation{})

	go func() {
		fmt.Printf("Serving GRPC on 0.0.0.0%s\n", gw.GrpcPort)
		if err := s.Serve(lis); err != nil {
			log.Fatalf("failed to serve: %v", err)
		}
	}()
}

func runHTTPServer() {
	ctx := context.Background()
	ctx, cancel := context.WithCancel(ctx)
	defer cancel()

	// Register gRPC server endpoint
	// Note: Make sure the gRPC server is running properly and accessible
	mux := runtime.NewServeMux()
	opts := []grpc.DialOption{grpc.WithInsecure()}
	grpcServerEndpoint := flag.String("grpc-server-endpoint",  "localhost" + gw.GrpcPort, "gRPC server endpoint")
	err := gw.RegisterGreeterHandlerFromEndpoint(ctx, mux,  *grpcServerEndpoint, opts)
	if err != nil {
		log.Fatalf("failed to register ")
	}

	go func() {
		fmt.Println("go func http.ListenAndServe")
		if err := http.ListenAndServe(gw.HttpPort, mux); err != nil {
			glog.Fatal(err)
		}
	}()
}

func main() {
	flag.Parse()
	defer glog.Flush()

	osSignals := make(chan os.Signal, 1)
	signal.Notify(osSignals, syscall.SIGINT, syscall.SIGTERM)

	runGRPCServer()
	runHTTPServer()

	osSignal := <-osSignals
	fmt.Println(osSignal)
	fmt.Println("Exiting")
}

helloworld/greeter_server.go:

const (
	HttpPort = ":8080"
	GrpcPort = ":8081"
)

type GreeterServerImplementation struct { }

func (i GreeterServerImplementation) mustEmbedUnimplementedGreeterServer() {
	panic("implement me") 	// NO IDEA WHAT TO DO HERE
}

func (GreeterServerImplementation) SayHello(_ context.Context, request *HelloRequest) (*HelloReply, error) {
	return &HelloReply{
		Message:       fmt.Sprintf("Hello, %s.", request.Name),
	}, nil
}
func (GreeterServerImplementation) SayGoodbye(_ context.Context, request *GoodbyeRequest) (*GoodbyeReply, error) {
	return &GoodbyeReply{
		Message:       fmt.Sprintf("Goodbye, %s.", request.Name),
	}, nil
}

client/main.go:

func main() {
	// Perform GRPC requests first
	MakeGrpcRequests()

	// Perform HTTP requests after
	MakeHelloHTTPRequest()
	MakeGoodbyeHTTPRequest()
}

func MakeGrpcRequests() {
	// Set up a connection to the server.
	conn, err := grpc.Dial(baseGrpcAddress, grpc.WithInsecure(), grpc.WithBlock())
	if err != nil {
		log.Fatalf("did not connect: %v", err)
	}
	defer conn.Close()
	c := gw.NewGreeterClient(conn)

	// Contact the server and print out its response.
	name := defaultName
	if len(os.Args) > 1 {
		name = os.Args[1]
	}
	ctx, cancel := context.WithTimeout(context.Background(), time.Second)
	defer cancel()
	r1, err := c.SayHello(ctx, &gw.HelloRequest{Name: name})
	if err != nil {
		log.Fatalf("could not greet: %v", err)
	}
	log.Printf("Greeting: %s", r1.GetMessage()) // SUCCESS

	r2, err := c.SayGoodbye(ctx, &gw.GoodbyeRequest{Name: name})
	if err != nil {
		log.Fatalf("could not say goodbye: %v", err)
	}
	log.Printf("Goodbye: %s", r2.GetMessage()) // SUCCESS
}

func MakeHelloHTTPRequest() {
	resp, err := http.Get(baseHttpAddress + gw.HttpPort + "/v1/sayhello/Sean")
	if err != nil {
		log.Fatalln(err)
	}

	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		log.Fatalln(err)
	}

	log.Println(string(body)) // ERROR {"code":1,"message":"grpc: the client connection is closing","details":[]}
}

func MakeGoodbyeHTTPRequest() {
	resp, err := http.Get(baseHttpAddress + gw.HttpPort + "/v1/saygoodbye/Sean")
	if err != nil {
		log.Fatalln(err)
	}

	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		log.Fatalln(err)
	}

	log.Println(string(body)) // ERROR {"code":1,"message":"grpc: the client connection is closing","details":[]}
}

Any ideas would be great and once I get everything working I can update the code in examples/helloworld.

@johanbrandhorst
Copy link
Collaborator

Hi @seantcanavan, thanks for your interest in the project! We've recently released a new tutorial series that should set you up with a basic grpc-gateway from scratch: https://grpc-ecosystem.github.io/grpc-gateway/docs/tutorials/introduction/. Could you try walking through this and see if that sets you up successfully?

Your error is indicative of the grpc-gateway client not being able to connect to the grpc server. I would recommend scrapping what you have in main and basing it off the tutorial or the boilerplate repo (https://github.com/johanbrandhorst/grpc-gateway-boilerplate). A quick skim through the code doesn't reveal anything obvious, but the way you're running things inside goroutines in main is a bit unusual anyway.

Let me know if you think the tutorial or docs could be improved still!

@seantcanavan
Copy link
Author

Thanks Johan I'll dig into that. Pretty rough running into an error in the first line of the doc but I've opened a PR to try to update the documentation #1929

@seantcanavan
Copy link
Author

Hey @johanbrandhorst, I started from scratch and the updated instructions have produced a working example on my local. The new buf tool is pretty sweet compared to parsing a bunch of args for protoc. Thanks again for all your help.

@johanbrandhorst
Copy link
Collaborator

Hey @johanbrandhorst, I started from scratch and the updated instructions have produced a working example on my local. The new buf tool is pretty sweet compared to parsing a bunch of args for protoc. Thanks again for all your help.

Glad to hear it, I work at Buf 😁.

@e7
Copy link

e7 commented Aug 9, 2021

I got the same error, but sometimes it works and I dont know why. Even in a same execution, it could be ok or error when request multiple times

@e7
Copy link

e7 commented Aug 9, 2021

I got the same error, but sometimes it works and I dont know why. Even in a same execution, it could be ok or error when request multiple times

I think it has something to do with the context handling

# sometimes ok, sometimes not
ctx, cancel := context.WithCancel(context.Background())
# always not ok
ctx, cancel := context.WithTimeout(context.Background(), 1 * time.Second)
# always ok
ctx, cancel := context.WithTimeout(context.Background(), 3000 * time.Second)

@seantcanavan
Copy link
Author

@e7 if it helps I took all the knowledge I gained working through the sample code here to come up with my own sample? starter? I'll let you decide. It's a barebones out-of-the-box fully documented working grpc gateway example: https://github.com/seantcanavan/minimal-go-grpc-gateway-example

@gp-arconomy
Copy link

I just ran into the same issue. It's because the the defer cancel, as the http service is started in a go routine. The defer cancel gets called and stops the http service. Simply removing the defer cancel call will resolve the issue.

ctx, cancel := context.WithTimeout(context.Background(), time.Second)
defer cancel()

@johanbrandhorst
Copy link
Collaborator

If this is still present in the example, please submit a PR to fix it, thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants