Lesson 13 / 25
Deadlines and Cancellation
Always set a deadline.
Bounded waiting across services
gRPC has no default deadline in many implementations, so a call can wait indefinitely. Set a deadline (or timeout) on every call; it travels to the server in the grpc-timeout header, and when it expires the call fails with DEADLINE_EXCEEDED on the client and is cancelled on the server. Servers should propagate the remaining deadline to downstream calls and stop work when the context is cancelled, so a slow chain does not keep doing useless work.
Failing well
Deadlines bound waiting, status codes describe failures, and retries recover from transient ones.
Deadlines in Go
Propagating context through calls (a sketch).
func (s *checkoutServer) PlaceOrder(ctx context.Context, req *pb.PlaceOrderRequest) (*pb.Order, error) {
// ctx already carries the caller's deadline; downstream calls inherit it
stock, err := s.inventory.Reserve(ctx, &invpb.ReserveRequest{Items: req.Items})
if err != nil {
return nil, err
}
_ = stock
// ...
return order, nil
}
// client side: set a deadline for the whole operation
ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
defer cancel()
order, err := client.PlaceOrder(ctx, req)Budget deadlines through the call chain
If the edge allows 2 seconds, downstream services must finish well within that; propagating the context does this automatically.
Quick check: What status does a client get when its deadline expires?
- NOT_FOUND
- DEADLINE_EXCEEDED
- OK
- UNIMPLEMENTED
Answer
DEADLINE_EXCEEDED — The server-side call is cancelled too.