Recently popular gRPC. Data can be serialized by the schema language Protocol Buffers. As it can communicate faster than json communication which was mainstream so far, Increasingly, it is being adopted in microservice development.
During this time, a bug as the title occurred when trying to communicate between the client and server built with gRPC. I've had a lot of trouble, so I'll leave the cause and solution as a memorandum.
Click here for the source. https://github.com/yzmw1213/PostService
Implement the following two services on the gRPC server written in go. --Posting service --Tag management service for posts (handled as master data)
Then, the client side code implemented by typescript sends a request to the above service and processes it.
client.ts
import { Tag, CreateTagRequest } from "~/grpc/tag_pb"
import { TagServiceClient } from "~/grpc/TagServiceClientPb"
post() {
const client = new TagServiceClient(
"http://localhost:8080", {}, {}
)
const request = new CreateTagRequest()
var tag = new Tag()
tag.setTagId(postTag.tagID)
tag.setTagName(postTag.tagName)
tag.setStatus(postTag.status)
request.setTag(tag)
//Send a request to the createTag method of TagService
client.createTag(request, {}, (err, res) => {
if (err != null) {
console.log(err)
}
console.log(res)
})
}
When requesting tag creation from the client side to the tag service as described above, the following error occurred.
{ code: 12, message: "unknown service post_grpc.TagService" }
Look at the official git wondering what code: 12 is ... saw.
Then
// HTTP Mapping: 501 Not Implemented UNIMPLEMENTED = 12;
in short, The content meant "the service has not been implemented."
So, check if the calling service is registered on the gRPC server.
Use grpcurl to check the operation of the grpc server.
There were many details in this article. https://qiita.com/yukina-ge/items/a84693f01f3f0edba482
For example, if you're building a gRPC server on port 50051, hit it like this:
#List of services registered on the port
$ grpcurl -plaintext localhost:50051 list
grpc.reflection.v1alpha.ServerReflection
post_grpc.PostService
Server Reflection and Post Service seem to be registered. Well then, I thought TagService was ... and when I read the code on the server side, I noticed an obvious mistake.
server.go
package grpc
import (
"fmt"
"log"
"net"
"os"
"os/signal"
"github.com/yzmw1213/PostService/grpc/post_grpc"
"github.com/yzmw1213/PostService/usecase/interactor"
"google.golang.org/grpc"
"google.golang.org/grpc/reflection"
)
type server struct {
PostUsecase interactor.PostInteractor
TagUsecase interactor.TagInteractor
}
//NewPostGrpcServer gRPC server start
func NewPostGrpcServer() {
lis, err := net.Listen("tcp", "0.0.0.0:50051")
if err != nil {
log.Fatalf("Failed to listen: %v", err)
}
server := &server{}
s := makeServer()
//Register PostService on server
post_grpc.RegisterPostServiceServer(s, server)
//TagService is missing!!!
// Register reflection service on gRPC server.
reflection.Register(s)
log.Println("main grpc server has started")
go func() {
if err := s.Serve(lis); err != nil {
log.Fatalf("failed to serve: %v", err)
}
}()
ch := make(chan os.Signal, 1)
signal.Notify(ch, os.Interrupt)
// Block until a sgnal is received
<-ch
fmt.Println("Stopping the server")
s.Stop()
fmt.Println("Closing the client")
lis.Close()
fmt.Println("End of Program")
}
func makeServer() *grpc.Server {
s := grpc.NewServer(
grpc.UnaryInterceptor(grpc.UnaryServerInterceptor(transmitStatusInterceptor)),
)
return s
}
I have registered PostService with post_grpc.RegisterPostServiceServer TagService must be registered with the gRPC server as well.
I added the following code and solved it.
server.go
//Register PostService on server
post_grpc.RegisterPostServiceServer(s, server)
//Add the following
//Tag service registration
post_grpc.RegisterTagServiceServer(s, server)
This time, I spent a lot of time identifying the cause. I put an envoy Proxy between the client and the server, and I was distracted by the proxy. .. It was a fairly rudimentary mistake for me, even if I was worried about it. grpcurl, let's use it from the beginning.
When building a gRPC server that assumes microservice operation, I have the impression that there are many articles written on the premise of 1 service / 1 server, but it is not always There is no need to divide the server into small parts for all services, as implemented above I think that there will be no problem in operation if each Register Service is used.
Relevant services (such as user registration and authentication services) I think it is possible to operate on the same server in this way.
I plan to write an authentication service in the future, so I'll give it a try.
I tried to check the operation of the gRPC server with grpcurl