package main import ( "context" "grpc-tutorial/greeter" "io" "log" "os" "os/signal" "sync" "syscall" "time" "github.com/golang/protobuf/ptypes/empty" "google.golang.org/grpc" "google.golang.org/grpc/codes" "google.golang.org/grpc/status" ) func main() { ctx, cancel := context.WithCancel(context.Background()) defer cancel() conn, err := grpc.DialContext(ctx, "localhost:8080", grpc.WithBlock(), grpc.WithTimeout(3*time.Second), grpc.WithInsecure()) if err != nil { log.Fatalf("could not connect to server: %v", err) } defer conn.Close() cli := greeter.NewGreeterClient(conn) stream, err := cli.SayHelloStream(ctx, &greeter.HelloRequest{}) if err != nil { log.Fatalf("could not create streaming client: %v", err) } sigCh := make(chan os.Signal, 1) signal.Notify(sigCh, os.Interrupt, syscall.SIGTERM) wg := sync.WaitGroup{} wg.Add(1) go func() { defer wg.Done() select { case <-ctx.Done(): return case s := <-sigCh: log.Printf("got signal %v, attempting graceful shutdown", s) cancel() } }() wg.Add(1) go func() { defer wg.Done() time.Sleep(5 * time.Second) resp, err := cli.SayHello(ctx, &empty.Empty{}) if err != nil { if status.Code(err) == codes.Canceled { log.Println("context cancelled") return } log.Fatalf("could not perform regular rpc request: %v", err) } log.Printf("received SayHello response: %+v", resp) }() wg.Add(1) go func() { defer wg.Done() for { r, err := stream.Recv() if err != nil { if err == io.EOF || status.Code(err) == codes.Canceled { log.Println("stream closed (context cancelled)") cancel() return } log.Fatalf("error while receiving stream response: %v", err) } log.Printf("received value: %+v", r) } }() wg.Wait() }