Monday, 17 June 2019

How to communicate between gRPC micro-services in Go-Lang

Hi Everybody,
Today we will see how to build gRPC based micro-services from scratch and how to communicate with each other.
In this example we will be writing two gRPC micro-services and RPC2 will communicate to RPC1 and vicer-versa can be extended later. gRPC requires at-least the basic knowledge of Protobuf, In order to deep dive into this example I suggest you to go through the basics of protobuf and gRPC here (in case if you are new to gRPC): https://grpc.io/docs/guides/

Now all set let us create our first micro-service in Go Lang and call it grpc_comm_1.go

package main
import (
"fmt"
"net"
"os"
"os/signal"
"syscall"
"golang.org/x/net/context"
"google.golang.org/grpc"
log "github.com/sirupsen/logrus"
pb "rpc1/main/pb"
)
const servicePort = 17009
type server struct{}
func (s *server) GetRpc1Msg(ctx context.Context, in *pb.RequestParams) (*pb.Rpc1Reply, error) {
return &pb.Rpc1Reply{ Rpc1Msg: "Message From GRPC1-->COMMUNICATION SUCCESS!" }, nil
}
func main() {
customFormatter := new(log.TextFormatter)
customFormatter.TimestampFormat = "2006-01-02 15:04:05"
log.SetFormatter(customFormatter)
//De-register the service on exit
signals := make(chan os.Signal)
signal.Notify(signals, syscall.SIGTERM) //Notify when app is terminated
signal.Notify(signals, syscall.SIGINT) //Notify when app is interrupted
// Shutdown channel to notify the running go-routines to stop when main exists
shutdownChan := make(chan bool)
go ShutdownHook(signals, shutdownChan)
log.Info("GRPC1 started!")
laddr := fmt.Sprintf(":%d", servicePort)
lis, lisErr := net.Listen("tcp", laddr)
if lisErr!= nil {
os.Exit(1)
}
s := grpc.NewServer()
pb.RegisterRpcCommunicator1Server(s, &server{})
if err := s.Serve(lis); err != nil {
log.Fatalf("failed to serve: %v", err)
}
}
// ShutdownHook is called when service is stopped or aborted based on the OS signals
func ShutdownHook(signals <-chan os.Signal, shutdownChan chan bool) {
select {
case <-signals:
//Go the OS interrupt signal
log.Println("Deregistering the service")
//Stop all the routines listening to shutdown channel
close(shutdownChan)
os.Exit(3)
}
}
view raw grpc_comm_1.go hosted with ❤ by GitHub

Similarly let's create the second gRPC and call it grpc_comm_2.go

package main
import (
"fmt"
"net"
"os"
"os/signal"
"syscall"
"golang.org/x/net/context"
"google.golang.org/grpc"
"time"
log "github.com/sirupsen/logrus"
pb "rpc2/main/pb"
pbRpc1 "rpc2/main/pb/rpc1"
)
const (
servicePort = 17007
rpc1Address = "localhost:17009"
)
type server struct{}
func (s *server) GetRpc2Msg(ctx context.Context, in *pb.RequestParams) (*pb.Rpc2Reply, error) {
return &pb.Rpc2Reply{ Rpc2Msg: "Message From GRPC2-->COMMUNICATION SUCCESS!" }, nil
}
func main() {
customFormatter := new(log.TextFormatter)
customFormatter.TimestampFormat = "2006-01-02 15:04:05"
log.SetFormatter(customFormatter)
//De-register the service on exit
signals := make(chan os.Signal)
signal.Notify(signals, syscall.SIGTERM) //Notify when app is terminated
signal.Notify(signals, syscall.SIGINT) //Notify when app is interrupted
// Shutdown channel to notify the running go-routines to stop when main exists
shutdownChan := make(chan bool)
go ShutdownHook(signals, shutdownChan)
log.Info("RPC2 Started")
getMessageFromRpc1()
laddr := fmt.Sprintf(":%d", servicePort)
lis, lisErr := net.Listen("tcp", laddr)
if lisErr!= nil {
os.Exit(1)
}
s := grpc.NewServer()
pb.RegisterRpcCommunicator2Server(s, &server{})
if err := s.Serve(lis); err != nil {
log.Fatalf("failed to serve: %v", err)
}
}
func getMessageFromRpc1(){
// Set up a connection to the server.
conn, err := grpc.Dial(rpc1Address, grpc.WithInsecure())
if err != nil {
log.Fatalf("did not connect: %v", err)
}
defer conn.Close()
c := pbRpc1.NewRpcCommunicator1Client(conn)
ctx, cancel := context.WithTimeout(context.Background(), time.Second)
defer cancel()
r, err := c.GetRpc1Msg(ctx, &pbRpc1.RequestParams{})
if err != nil {
log.Fatalf("could not communicate: %v", err)
}
log.Info(r.Rpc1Msg)
}
// ShutdownHook is called when service is stopped or aborted based on the OS signals
func ShutdownHook(signals <-chan os.Signal, shutdownChan chan bool) {
select {
case <-signals:
//Go the OS interrupt signal
log.Println("Deregistering the service")
//Stop all the routines listening to shutdown channel
close(shutdownChan)
os.Exit(3)
}
}
view raw grpc_comm_2.go hosted with ❤ by GitHub

Now both services are ready first run the service grpc_comm_1.go and then following that run grpc_comm_2.go and in the terminal you can see the output displaying the services interacting with each other.

I have hosted the complete source code in git: https://github.com/harishp8889/haritechtalk/tree/master/go-lang/GRPC 
clone the GRPC folder which has all the code explained in the above example along with a gRPC client for testing purpose.

No comments:

Post a Comment