gRPC には、当然ながらクライアントサイドでタイムアウトが設定できます。このとき、HTTP/2 上でどういうフレームが流れるのかを整理してみます。
タイムアウト設定
golang
Golang の場合は、 context.WithTimeout
を使ってタイムアウトを指定する。
ctx, cancel := context.WithTimeout(context.Background(), time.Second)
defer cancel()
req := &pb.EchoRequest{Message: message}
node
node.js の場合は、CallOptions で指定することになります。
const timeout = 2000 // milliseconds client.SayHello( { name: "kiririmode" }, { deadline: Date.now() + timeout }, (err, res) => { if (err) { console.log(err) return } console.log(res) } )
HTTP/2 での挙動
WireShark でパケットキャプチャをした結果が以下になります。
[1]
となっており、今回の Unary Call は stream 1 が使われていることがわかります。
まず、リクエストヘッダを覗いて見ましょう。
Header フレームの中に grpc-timeout
ヘッダが存在しており、その値が 2S
となっていることがわかります。このように、gRPC におけるタイムアウトは Timeout → "grpc-timeout" TimeoutValue TimeoutUnit
という形のヘッダとして表現されると定義されています。詳細は grpc/PROTOCOL-HTTP2.md at master · grpc/grpc · GitHub に記載があります。
今回はタイムアウトを 2 秒としているので、当該ヘッダの値は 2S
(2秒) となっています。
そしておおよそ 2 秒後に、クライアントから RST_STREAM
フレームが送信されています。
これにより、今回使用した stream 1 は closed
state に遷移し、完全に stream としてのライフサイクルを終えたことがわかります。
stream の状態遷移については、RFC 7540 を参照してください。
+--------+ send PP | | recv PP ,--------| idle |--------. / | | \ v +--------+ v +----------+ | +----------+ | | | send H / | | ,------| reserved | | recv H | reserved |------. | | (local) | | | (remote) | | | +----------+ v +----------+ | | | +--------+ | | | | recv ES | | send ES | | | send H | ,-------| open |-------. | recv H | | | / | | \ | | | v v +--------+ v v | | +----------+ | +----------+ | | | half | | | half | | | | closed | | send R / | closed | | | | (remote) | | recv R | (local) | | | +----------+ | +----------+ | | | | | | | | send ES / | recv ES / | | | | send R / v send R / | | | | recv R +--------+ recv R | | | send R / `----------->| |<-----------' send R / | | recv R | closed | recv R | `----------------------->| |<----------------------' +--------+ send: endpoint sends this frame recv: endpoint receives this frame H: HEADERS frame (with implied CONTINUATIONs) PP: PUSH_PROMISE frame (with implied CONTINUATIONs) ES: END_STREAM flag R: RST_STREAM frame Figure 2: Stream States
まとめ
client で gRPC timeout を指定した場合、
- client からは
grpc-timeout
ヘッダによってサーバにタイムアウト時間が通知される - 実際に client でタイムアウトすると、client から
END_STREAM
frame が送出され、stream は closed 状態に遷移し終了する