Home > Net >  gRPC Context cancellation propogation
gRPC Context cancellation propogation

Time:10-21

I am trying to understand how Go context cancellation works underneath in client service communication (say, any gRPC API call ).

Let's say a client canceled the context on its end. Does it result in a new HTTP request to the server communicating the context of the previous/ongoing gRPC request is canceled? How does server knows if client cancelled the context?

CodePudding user response:

Let's say a client canceled the context on its end. Does it result in a new HTTP request to the server communicating the context of the previous/ongoing GRPC request is canceled?

No. It closes the network connection.

How does server knows if client cancelled the context?

By virtue of the fact that the network connection was closed.

CodePudding user response:

By default, the HTTP2 is used as the underneath protocol for gPRC. And there could be multiple streams in on HTTP2 connection. Here is one image illustrate the connection and stream of HTTP2 from enter image description here

If you cancel the context in one gRPC call before the response comes back. The errCode could be CANCEL and mapping to RST_STREAM on client side, then this RST_STREAM would be sent to server. The RST_STREAM frame allows for immediate termination of a stream, which is the current RPC call stream would be terminated. However, the HTTP2 connection still there, when the next RPC call is invoked, another new stream will used to do the RPC call.


Here are some test codes snippet.

Client side: force to cancel context after 100 millseconds.

    conn, err := grpc.Dial(serverAddr,
        grpc.WithTransportCredentials(insecure.NewCredentials()))

    defer conn.Close()

    c := pb.NewGreeterClient(conn)

    for i := 0; i < 10; i   {
        ctx, cancel := context.WithCancel(context.TODO())
        go func() {
            // force call cancel after 100 milliseconds
            time.Sleep(100 * time.Millisecond)
            cancel()
        }()

        r, err := c.SayHello(ctx, &pb.HelloRequest{Name: "name"})
     }

Server side: delay sayHello response in 1 second.

func (s *server) SayHello(ctx context.Context, in *pb.HelloRequest) (*pb.HelloReply, error) {
    // Delay ack on server by 1 seconds
    randMS := 1000

    select {
    case <-time.After(time.Duration(randMS) * time.Millisecond):

    case <-ctx.Done():
        if ctx.Err() == context.Canceled || ctx.Err() == context.DeadlineExceeded {
            log.Printf("SayHello: context err % v \n", ctx.Err())
            return nil, ctx.Err()
            
        }
    }

Run the codes with GODEBUG=http2debug=2, more debug logs of gRPC could help us to know the message between client and server.


Client logs

2022/10/21 20:40:38 http2: Framer 0xc0005be000: wrote SETTINGS len=0
2022/10/21 20:40:38 http2: Framer 0xc0005be000: read SETTINGS len=6, settings: MAX_FRAME_SIZE=16384
2022/10/21 20:40:38 http2: Framer 0xc0005be000: wrote SETTINGS flags=ACK len=0
2022/10/21 20:40:38 http2: Framer 0xc0005be000: read SETTINGS flags=ACK len=0
2022/10/21 20:40:38 http2: Framer 0xc0005be000: wrote HEADERS flags=END_HEADERS stream=1 len=98
2022/10/21 20:40:38 http2: Framer 0xc0005be000: wrote DATA flags=END_STREAM stream=1 len=12 data="\x00\x00\x00\x00\a\n\x05world"
2022/10/21 20:40:38 http2: Framer 0xc0005be000: read WINDOW_UPDATE len=4 (conn) incr=12
2022/10/21 20:40:38 http2: Framer 0xc0005be000: read PING len=8 ping="\x02\x04\x10\x10\t\x0e\a\a"
2022/10/21 20:40:38 http2: Framer 0xc0005be000: wrote PING flags=ACK len=8 ping="\x02\x04\x10\x10\t\x0e\a\a"
force call cancel in client
2022/10/21 20:40:38 could not greet: rpc error: code = Canceled desc = context canceled
2022/10/21 20:40:38 http2: Framer 0xc0005be000: wrote RST_STREAM stream=1 len=4 ErrCode=CANCEL
2022/10/21 20:40:41 http2: Framer 0xc0005be000: wrote HEADERS flags=END_HEADERS stream=3 len=7
2022/10/21 20:40:41 http2: Framer 0xc0005be000: wrote DATA flags=END_STREAM stream=3 len=12 data="\x00\x00\x00\x00\a\n\x05world"
2022/10/21 20:40:41 http2: Framer 0xc0005be000: read WINDOW_UPDATE len=4 (conn) incr=12
2022/10/21 20:40:41 http2: Framer 0xc0005be000: read PING len=8 ping="\x02\x04\x10\x10\t\x0e\a\a"
2022/10/21 20:40:41 http2: Framer 0xc0005be000: wrote PING flags=ACK len=8 ping="\x02\x04\x10\x10\t\x0e\a\a"
force call cancel in client
2022/10/21 20:40:41 could not greet: rpc error: code = Canceled desc = context canceled
2022/10/21 20:40:41 http2: Framer 0xc0005be000: wrote RST_STREAM stream=3 len=4 ErrCode=CANCEL
2022/10/21 20:40:44 http2: Framer 0xc0005be000: wrote HEADERS flags=END_HEADERS stream=5 len=7
2022/10/21 20:40:44 http2: Framer 0xc0005be000: wrote DATA flags=END_STREAM stream=5 len=12 data="\x00\x00\x00\x00\a\n\x05world"
2022/10/21 20:40:44 http2: Framer 0xc0005be000: read WINDOW_UPDATE len=4 (conn) incr=12

  • Related