diff --git a/examples/features/deadline/client/main.go b/examples/features/deadline/client/main.go new file mode 100644 index 000000000000..d19178cc2d29 --- /dev/null +++ b/examples/features/deadline/client/main.go @@ -0,0 +1,95 @@ +/* + * + * Copyright 2018 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +// Binary client is an example client. +package main + +import ( + "context" + "flag" + "fmt" + "log" + "time" + + "google.golang.org/grpc" + "google.golang.org/grpc/codes" + pb "google.golang.org/grpc/examples/features/proto/echo" + "google.golang.org/grpc/status" +) + +func unaryCall(c pb.EchoClient, requestID int, message string, want codes.Code) { + // Creates a context with a one second deadline for the RPC. + ctx, cancel := context.WithTimeout(context.Background(), time.Second) + defer cancel() + + req := &pb.EchoRequest{Message: message} + + _, err := c.UnaryEcho(ctx, req) + got := status.Code(err) + fmt.Printf("[%v] wanted = %v, got = %v\n", requestID, want, got) +} + +func streamingCall(c pb.EchoClient, requestID int, message string, want codes.Code) { + // Creates a context with a one second deadline for the RPC. + ctx, cancel := context.WithTimeout(context.Background(), time.Second) + defer cancel() + + stream, err := c.BidirectionalStreamingEcho(ctx) + if err != nil { + log.Printf("Stream err: %v", err) + return + } + + err = stream.Send(&pb.EchoRequest{Message: message}) + if err != nil { + log.Printf("Send error: %v", err) + return + } + + _, err = stream.Recv() + + got := status.Code(err) + fmt.Printf("[%v] wanted = %v, got = %v\n", requestID, want, got) +} + +func main() { + port := flag.Int("port", 50052, "port number") + flag.Parse() + + target := fmt.Sprintf("localhost:%v", *port) + conn, err := grpc.Dial(target, grpc.WithInsecure()) + if err != nil { + log.Fatalf("did not connect: %v", err) + } + defer conn.Close() + + c := pb.NewEchoClient(conn) + + // A successful request + unaryCall(c, 1, "world", codes.OK) + // Exceeds deadline + unaryCall(c, 2, "delay", codes.DeadlineExceeded) + // A successful request with propagated deadline + unaryCall(c, 3, "[propagate me]world", codes.OK) + // Exceeds propagated deadline + unaryCall(c, 4, "[propagate me][propagate me]world", codes.DeadlineExceeded) + // Receives a response from the stream successfully. + streamingCall(c, 5, "[propagate me]world", codes.OK) + // Exceeds propagated deadline before receiving a response + streamingCall(c, 6, "[propagate me][propagate me]world", codes.DeadlineExceeded) +} diff --git a/examples/features/deadline/server/main.go b/examples/features/deadline/server/main.go new file mode 100644 index 000000000000..63044b542b5f --- /dev/null +++ b/examples/features/deadline/server/main.go @@ -0,0 +1,128 @@ +/* + * + * Copyright 2018 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +// Binary server is an example server. +package main + +import ( + "context" + "flag" + "fmt" + "io" + "log" + "net" + "strings" + "time" + + "google.golang.org/grpc" + "google.golang.org/grpc/codes" + pb "google.golang.org/grpc/examples/features/proto/echo" + "google.golang.org/grpc/status" +) + +var port = flag.Int("port", 50052, "port number") + +// server is used to implement EchoServer. +type server struct { + client pb.EchoClient + cc *grpc.ClientConn +} + +func (s *server) UnaryEcho(ctx context.Context, req *pb.EchoRequest) (*pb.EchoResponse, error) { + message := req.Message + if strings.HasPrefix(message, "[propagate me]") { + time.Sleep(800 * time.Millisecond) + message = strings.TrimPrefix(message, "[propagate me]") + return s.client.UnaryEcho(ctx, &pb.EchoRequest{Message: message}) + } + + if message == "delay" { + time.Sleep(1500 * time.Millisecond) + } + + return &pb.EchoResponse{Message: req.Message}, nil +} + +func (s *server) ServerStreamingEcho(req *pb.EchoRequest, stream pb.Echo_ServerStreamingEchoServer) error { + return status.Error(codes.Unimplemented, "RPC unimplemented") +} + +func (s *server) ClientStreamingEcho(stream pb.Echo_ClientStreamingEchoServer) error { + return status.Error(codes.Unimplemented, "RPC unimplemented") +} + +func (s *server) BidirectionalStreamingEcho(stream pb.Echo_BidirectionalStreamingEchoServer) error { + for { + req, err := stream.Recv() + if err == io.EOF { + return status.Error(codes.InvalidArgument, "request message not received") + } + if err != nil { + return err + } + + message := req.Message + if strings.HasPrefix(message, "[propagate me]") { + time.Sleep(800 * time.Millisecond) + message = strings.TrimPrefix(message, "[propagate me]") + res, err := s.client.UnaryEcho(stream.Context(), &pb.EchoRequest{Message: message}) + if err != nil { + return err + } + stream.Send(res) + } + + if message == "delay" { + time.Sleep(1500 * time.Millisecond) + } + stream.Send(&pb.EchoResponse{Message: message}) + } +} + +func (s *server) Close() { + s.cc.Close() +} + +func newEchoServer() *server { + target := fmt.Sprintf("localhost:%v", *port) + cc, err := grpc.Dial(target, grpc.WithInsecure()) + if err != nil { + log.Fatalf("did not connect: %v", err) + } + return &server{client: pb.NewEchoClient(cc), cc: cc} +} + +func main() { + flag.Parse() + + address := fmt.Sprintf(":%v", *port) + lis, err := net.Listen("tcp", address) + if err != nil { + log.Fatalf("failed to listen: %v", err) + } + + echoServer := newEchoServer() + defer echoServer.Close() + + grpcServer := grpc.NewServer() + pb.RegisterEchoServer(grpcServer, echoServer) + + if err := grpcServer.Serve(lis); err != nil { + log.Fatalf("failed to serve: %v", err) + } +}