Access multiple gRPC services each one running on separated port - go

I am running a grpc server listening on localhost:9000, with 2 separate grpc services:
AuthenticationServiceServer port:9001
JobsServiceServer port 9002
This works correctly when I am only running the Auth server, but when adding Jobs server I get:
"error": "rpc error: code = Unimplemented desc = unknown service pb.AuthService"
The server looks like this when working fine
var (
port int
authAddr string
)
func init() {
flag.IntVar(&port, "port", 9000, "api service port")
flag.StringVar(&authAddr, "auth_addr", "localhost:9001", "authenticaton service address")
flag.Parse()
}
func main() {
log.Print("starting main service")
conn, err := grpc.Dial(authAddr, grpc.WithInsecure())
if err != nil {
log.Panicln(err)
}
defer conn.Close()
authSvcClient := pb.NewAuthServiceClient(conn)
authHandlers := resthandlers.NewAuthHandlers(authSvcClient)
authRoutes := routes.NewAuthRoutes(authHandlers)
router := mux.NewRouter().StrictSlash(true)
routes.Install(router, authRoutes)
log.Printf("API service running on [::]:%d\n", port)
log.Fatal(http.ListenAndServe(fmt.Sprintf(":%d", port), routes.WithCORS(router)))
}
On some other attempts I got this error.
"error": "rpc error: code = Unavailable desc = connection error: desc = "transport: Error while dialing dial tcp: missing address""\
here's the code which returned an error
var (
port int
authAddr string
jobAddr string
)
func init() {
flag.IntVar(&port, "port", 9000, "api service port")
flag.StringVar(&authAddr, "auth_addr", "localhost:9001", "authenticaton service address")
flag.StringVar(&jobAddr, "job_addr", "localhost:9002", "job service address")
flag.Parse()
}
func main() {
log.Print("starting main service")
conn, err := grpc.Dial(authAddr, grpc.WithInsecure())
if err != nil {
log.Panicln(err)
}
defer conn.Close()
jobConn, err := grpc.Dial(jobAddr, grpc.WithInsecure())
if err != nil {
log.Panicln(err)
}
defer jobConn.Close()
jobSvcClient := pb.NewJobPostingServiceClient(jobConn)
jobHandlers := resthandlers.NewJobPostingHandlers(jobSvcClient)
jobRoutes := routes.NewJobPostingRoutes(jobHandlers)
authSvcClient := pb.NewAuthServiceClient(conn)
authHandlers := resthandlers.NewAuthHandlers(authSvcClient)
authRoutes := routes.NewAuthRoutes(authHandlers)
router := mux.NewRouter().StrictSlash(true)
routes.Install(router, authRoutes)
routes.Install(router, jobRoutes)
log.Printf("API service running on [::]:%d\n", port)
log.Fatal(http.ListenAndServe(fmt.Sprintf(":%d", port), routes.WithCORS(router)))
}

Related

Why am i getting connection connection closed before server preface received in go?

I am trying to setup a rpc server and a proxy HTTP server over GRPC server on same port using grpc-gateway. Wierdly some times i am getting failed to receive server preface within timeout error randomly. Most of the times it happens on service restarts. It starts working and returns proper response after couple of retries. I am not sure what's happening. Can somebody help me out ? Here is the service startup snippet
func makeHttpServer(conn *grpc.ClientConn) *runtime.ServeMux {
router := runtime.NewServeMux()
if err := services.RegisterHealthServiceHandler(context.Background(), router, conn); err != nil {
log.Logger.Error("Failed to register gateway", zap.Error(err))
nricher
if err := services.RegisterConstraintsServiceHandler(context.Background(), router, conn); err != nil {
log.Logger.Error("Failed to register gateway", zap.Error(err))
}
return router
}
func makeGrpcServer(address string) (*grpc.ClientConn, *grpc.Server) {
grpcServer := grpc.NewServer()
services.RegisterHealthServiceServer(grpcServer, health.Svc{})
services.RegisterABCServer(grpcServer, ABC.Svc{})
conn, err := grpc.DialContext(
context.Background(),
address,
grpc.WithInsecure(),
)
if err != nil {
log.Logger.Error("Failed to dial server", zap.Error(err))
}
return conn, grpcServer
}
func httpGrpcRouter(grpcServer *grpc.Server, httpHandler *runtime.ServeMux, listener net.Listener) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if r.ProtoMajor == 2 {
grpcServer.Serve(listener)
} else {
httpHandler.ServeHTTP(w, r)
}
})
}
func Start() error {
conf := config.Get()
address := fmt.Sprintf("%s:%d", conf.ServerHost, conf.ServerPort)
listener, err := net.Listen("tcp", address)
if err != nil {
log.Logger.Fatal("failed to listen: %v", zap.Error(err))
}
conn, grpcServer := makeGrpcServer(address)
router := makeHttpServer(conn)
log.Logger.Info("Starting server on address : " + address)
err = http.Serve(listener, httpGrpcRouter(grpcServer, router, listener))
return err
}
Try wrapping your router with h2c.NewHandler so the the http.Serve() call looks as follows:
err = http.Serve(listener, h2c.NewHandler(
httpGrpcRouter(grpcServer, router, listener),
&http2.Server{})
)

Golang grpc: how to determine when the server has started listening?

So I have the following:
type Node struct {
Table map[string]string
thing.UnimplementedGreeterServer
address string
}
func (n *Node) Start() {
lis, err := net.Listen("tcp", port)
if err != nil {
log.Fatalf("failed to listen: %v", err)
}
s := grpc.NewServer()
thing.RegisterGreeterServer(s, n)
if err := s.Serve(lis); err != nil {
log.Fatalf("failed to serve: %v", err)
}
}
In my main function I'll spin up mulitple nodes like so:
func main() {
n :=Node{Table: map[string]string{}}
go n.Start()
conn, err := grpc.Dial("localhost:50051", grpc.WithInsecure(), grpc.WithBlock())
}
The problem is, because I'm spinning up the node concurrently, there's a chance the dial up connection might not work because the node might not have been setup yet.
Ideally, I'd like a done channel that tells me when the grpc server has actually started listening. How do I accomplish this?
This is essntially the same problem as How to add hook on golang grpc server start? which doesn't have an answer
s.Serve(listener) blocks, so you can't achieve your purpose by having a done chan, instead you have to implement the healthcheck and readiness for your service, and check those before performing any request by the client.
The server should implement the following proto:
syntax = "proto3";
package grpc.health.v1;
message HealthCheckRequest {
string service = 1;
}
message HealthCheckResponse {
enum ServingStatus {
UNKNOWN = 0;
SERVING = 1;
NOT_SERVING = 2;
SERVICE_UNKNOWN = 3; // Used only by the Watch method.
}
ServingStatus status = 1;
}
service Health {
rpc Check(HealthCheckRequest) returns (HealthCheckResponse);
rpc Watch(HealthCheckRequest) returns (stream HealthCheckResponse);
}
For example, the envoy proxy grpc_health_check works with the above proto.
Read GRPC Health Checking Protocol for more information.
The server can be Dialed as soon as net.Listen returns a nil error. Dial will block until the server calls Accept (which will happen somewhere in s.Serve in this case).
Either move creation of the listener into the caller and pass it as an argument:
func (n *Node) Start(lis net.Listener) {
s := grpc.NewServer()
thing.RegisterGreeterServer(s, n)
if err := s.Serve(lis); err != nil {
log.Fatalf("failed to serve: %v", err)
}
}
func main() {
lis, err := net.Listen("tcp", port)
if err != nil {
log.Fatalf("failed to listen: %v", err)
}
n := Node{Table: map[string]string{}}
go n.Start(lis)
conn, err := grpc.Dial("localhost:50051", grpc.WithInsecure(), grpc.WithBlock())
}
Or signal that the listener is up after Listen returns:
func (n *Node) Start(up chan struct{}) {
lis, err := net.Listen("tcp", port)
if err != nil {
log.Fatalf("failed to listen: %v", err)
}
if up != nil {
close(up)
}
s := grpc.NewServer()
thing.RegisterGreeterServer(s, n)
if err := s.Serve(lis); err != nil {
log.Fatalf("failed to serve: %v", err)
}
}
func main() {
n := Node{Table: map[string]string{}}
up := make(chan struct{})
go n.Start(up)
<-up
conn, err := grpc.Dial("localhost:50051", grpc.WithInsecure(), grpc.WithBlock())
}
For all those who are still looking for an answer to this, here is another simple way to do it. Start the server in a child routine. Here is a code snippet:
// Start the server in a child routine
go func() {
if err := s.Serve(listener); err != nil {
log.Fatalf("Failed to serve: %v", err)
}
}()
fmt.Println("Server succesfully started on port :50051")
In my case I am using MongoDB as well, so when you run it, you get:
grpc-go-mongodb-cobra>go run server/main.go
Starting server on port :50051...
Connecting to MongoDB...
Connected to MongoDB
Server succesfully started on port :50051
I have also written a Blog post on this, with working code in GitHub. Here is the link: https://softwaredevelopercentral.blogspot.com/2021/03/golang-grpc-microservice.html

"connect: connection refused" while attempting to connect to localhost

I'm currently attempting to create a TCP service that will just log/store whatever is sent to it. I can't seem to understand why I cannot connect to my localhost using DialTCP. I keep getting
dial tcp 127.0.0.1:8080: connect: connection refused
func main() {
errCh := make(chan error)
tcpAddr, _ := net.ResolveTCPAddr("tcp", "localhost:8080")
for {
conn, err := net.DialTCP("tcp", nil, tcpAddr)
if err != nil {
log.Println("Could not connect -> ", err.Error())
} else {
recordMessage(conn, errCh)
err = <-errCh
log.Println("Error", err)
conn.Close()
}
log.Println("trying again in 10 seconds..")
time.Sleep(30 * time.Second)
}
}
I looked over my Firewall settings and noting seems to be blocking it. I'm still not sure if its due to something related to my Firewall or if I'm just missing something super obvious.
Start by running this Go program in a terminal -- it listens to port 2000 but you could change it to 8080 or whatever you wish:
func main() {
// Listen on TCP port 2000 on all interfaces.
l, err := net.Listen("tcp", ":2000")
if err != nil {
log.Fatal(err)
}
defer l.Close()
for {
// Wait for a connection.
conn, err := l.Accept()
if err != nil {
log.Fatal(err)
}
// Handle the connection in a new goroutine.
// The loop then returns to accepting, so that
// multiple connections may be served concurrently.
go func(c net.Conn) {
log.Println(c)
// Echo all incoming data.
io.Copy(c, c)
// Shut down the connection.
c.Close()
}(conn)
}
}
Then in a separate terminal run this simple client:
func main() {
var addr string
if len(os.Args) > 1 {
addr = os.Args[1]
} else {
addr = "localhost:2000"
}
conn, err := net.Dial("tcp", addr)
if err != nil {
log.Fatal(err)
// handle error
}
fmt.Fprintf(conn, "foobar")
conn.Close()
}
Asking it to connect to the same port. The connection should succeed and you should see the server logging something.
Now try to connect with your client.
Without writing Go, you could to these things with the nc command-line tool (netcat). nc -lv PORT creates a simple listening server on PORT, for example.

how to use etcd in service discovery?

I am beginner for etcd
my purpose is the follow
1.service register itself after service start
2.client find service and invoke service
the follow code show test how to find service and invoke it
func ClientTestService() {
cli, err := clientv3.New(clientv3.Config{
Endpoints: []string{endpoint},
DialTimeout: time.Second * 5,
})
if err != nil {
log.Println("connect etcd err:", err.Error())
return
}
defer cli.Close()
r := &naming.GRPCResolver{Client: cli}
b := grpc.RoundRobin(r)
conn, err := grpc.Dial(service_name, grpc.WithBalancer(b), grpc.WithInsecure())
if err != nil {
log.Println("dial err:", err.Error())
return
}
defer conn.Close()
c := calc.NewCalcClient(conn)
req := calc.CalcRequest{IResult: 1, SResult: "req"}
resp, err := c.CalcResult(context.Background(), &req)
if err != nil {
log.Println("calc err:", err)
return
}
log.Println(resp.IResult, resp.SResult)
}
console output "calc err: rpc error: code = Unavailable desc = there is no address available" after execute resp, err := c.CalcResult(context.Background(), &req)
it means that resolver can't find the address of service from the service name
i guess there have two possible
1. call service need start etcd "proxy service" or "gateway" first
2. need to get service address from service name by manual
the follow code show register service
func RegisterService(w *sync.WaitGroup) {
w.Add(1)
defer func() {
w.Done()
}()
cli, err := clientv3.New(clientv3.Config{
Endpoints: []string{endpoint},
DialTimeout: time.Second * 5,
})
if err != nil {
log.Println("etcd err:", err)
return
}
cli.Delete(cli.Ctx(), service_name)
r := &naming.GRPCResolver{Client: cli}
for _, addr := range GetLocalAddrs() {
service_node := addr + ":" + strconv.Itoa(port)
err = r.Update(cli.Ctx(), service_name, gn.Update{Op: gn.Add, Addr: service_node})
log.Println("register node :", service_name, service_node, err)
}
}
My understanding is that function "ClientTestService" connect etcd server and resolve the service name to service address and invoke service by balance
but when i debug this code and then find it just invoke etcd by balance,
is there function in etcd for my need ?
Try add grpc.WithBlock() for Dial, like this:
grpc.Dial(service_name, grpc.WithBalancer(b), grpc.WithInsecure(), grpc.WithBlock() )

Docker API call returns "server gave HTTP response to HTTPS client"

I have the following Code and a Call to the API returns an error as follows, I hve also pasted Docker Daemon command below. I have tried a few combinations from HTTP/ HTTPS / TCP with / without TLS.
Where could I be wrong here?
"panic: An error occurred trying to connect: Get https://172.28.8.212:2375/v1.24/containers/json?limit=0: http: server gave HTTP response to HTTPS client
"
func main() {
var headers map[string]string
tr := &http.Transport{
TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
}
cl := &http.Client{Timeout: time.Minute}
cli, err := client.NewClient("tcp://172.28.8.212:2375", "1.24", cl, headers)
if err != nil {
panic(err)
}
containers, err := cli.ContainerList(context.Background(), types.ContainerListOptions{})
if err != nil {
panic(err)
}
for _, container := range containers {
fmt.Printf("%s %s\n", container.ID[:10], container.Image)
}
}
My Docker Daemon is started as follows
[Unit]
Description = Docker Service Daemon
[Service]
ExecStart=/usr/bin/docker daemon -H tcp://0.0.0.0:2375 -H unix:///var/run/docker.sock --cluster-store=consul://172.28.8.211:8500
func main() {
var headers map[string]string
tr := &http.Transport{} <---- Note the difference here.
tr.Dial = func(proto, addr string) (net.Conn, error) {
fmt.Println("Dial called")
conn, err := net.DialTimeout(proto, addr, time.Minute)
if err != nil {
fmt.Println("There was an err", err)
}
return conn, err
}
cl := &http.Client{Transport: tr}
cli, err := client.NewClient("http://x.y.z.w:2376", "1.24", cl, headers)
if err != nil {
panic(err)
}
containers, err := cli.ContainerList(context.Background(), types.ContainerListOptions{})
if err != nil {
panic(err)
}
for _, container := range containers {
fmt.Printf("%s %s\n", container.ID[:10], container.Image)
}
}

Resources