Skip to content

Instantly share code, notes, and snippets.

@manhdaovan
Last active August 1, 2019 01:34
Show Gist options
  • Save manhdaovan/f9a177e4caa477a29e129e2df246fd1a to your computer and use it in GitHub Desktop.
Save manhdaovan/f9a177e4caa477a29e129e2df246fd1a to your computer and use it in GitHub Desktop.
Simple test grpc.ClientConn
// asynchronous requesting with same client
func main() {
err := logger.RegisterLoggerFactory(func() (logger.Logger, error) {
return onelog.NewOneLogger(os.Stdout), nil
})
if err != nil {
fmt.Printf("error on register logger factory: %v", err)
return
}
lgr, _ := logger.NewLogger()
target := "localhost:51111"
conn, err := grpc.Dial(target, grpc.WithInsecure())
if err != nil {
lgr.Errorf(context.Background(), "cannot dial %s, err: %v", target, err)
}
client := service.NewGenerateIDClient(conn)
var wg sync.WaitGroup
wg.Add(2)
go func() {
defer wg.Done()
ctx := context.Background()
in := &service.GenerateRequest{
Prefix: "serviceA-ServiceB",
}
out, err := client.Generate(ctx, in)
lgr.Infof(ctx, "out: %+v, err: %v", out, err)
}()
go func() {
defer wg.Done()
ctx2 := context.Background()
in := &service.GenerateRequest{
Prefix: "serviceA-ServiceB2222",
}
out2, err2 := client.Generate(ctx2, in)
lgr.Infof(ctx2, "out: %+v, err: %v", out2, err2)
}()
wg.Wait()
}
// Generate generate a unique id per request, then save it to db
func (s *GenerateIDService) Generate(ctx context.Context, in *GenerateRequest) (*GenerateResponse, error) {
s.ac.GetLogger().Infof(ctx, "request: %+v", in)
time.Sleep(30 * time.Second)
id, err := s.idDAO.NextID(ctx, in.Prefix)
if err != nil {
return nil, status.Errorf(codes.Internal, "cannot generate next id for %s, error: %v", in.Prefix, err)
}
res := &GenerateResponse{Id: id.UniqueString()}
s.ac.GetLogger().Infof(ctx, "response: %+v", res)
return res, nil
}
// synchronous requesting with same client
func main() {
err := logger.RegisterLoggerFactory(func() (logger.Logger, error) {
return onelog.NewOneLogger(os.Stdout), nil
})
if err != nil {
fmt.Printf("error on register logger factory: %v", err)
return
}
lgr, _ := logger.NewLogger()
target := "localhost:51111"
conn, err := grpc.Dial(target, grpc.WithInsecure())
if err != nil {
lgr.Errorf(context.Background(), "cannot dial %s, err: %v", target, err)
}
client := service.NewGenerateIDClient(conn)
for {
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
//ctx := context.Background()
in := &service.GenerateRequest{
Prefix: "serviceA-ServiceB",
}
out, err := client.Generate(ctx, in)
lgr.Infof(ctx, "out: %+v, err: %v", out, err)
ctx2, cancel2 := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel2()
out2, err2 := client.Generate(ctx2, in)
lgr.Infof(ctx, "out: %+v, err: %v", out2, err2)
}
}
@manhdaovan
Copy link
Author

manhdaovan commented Jul 31, 2019

Testing cases

  • Case1: Have no timeout in the client-side (used context.Background() instead of context. WithTimeout())
  • Case2: Setting timeout in the client-side as above client.go code with diffirent context.
  • Case3: The client uses the same context with timeout context. (used same ctx1 in above client.go)

Testing scenario

  • Run server
  • Run client (async and sync requesting)
  • Force quit server without graceful shutdown
  • Rerun server

Testing result

  • In case1:
    • If the server is running, the client waits until received response.
    • If the server is shutdowned, rpc error: code = Unavailable desc = all SubConns are in TransientFailure, latest connection error: connection error: desc = \"transport: Error while dialing dial tcp 127.0.0.1:51111: connect: connection refused\"" was raised in client-side.
    • If the server is backed, the client connects and requests to the server normally without restarting the client.
  • In case2:
    • Because the server sleeps 30s when received the request, so the client-side got rpc error: code = DeadlineExceeded desc = context deadline exceeded" when the server is running.
    • In other steps, the result is the same as above case1.
  • In case3:
    • If the context is canceled (timeout), the second request failed immediately without requesting to the server while the server is running.
    • In other steps, the result is the same as above case1.

Conclusion

  • You just keep the connection open, then the client can use the connection in the whole lifetime of the app.
  • The client can request parallelly in multiple goroutines (see async_client.go file)
  • You don't need to reconnect to server event the server is restarted after shutdowned.
  • The connection can be used by multiple clients parallelly.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment