How do deadlines propagate across service boundaries (e.g., gRPC), and how do you manage a time budget across multiple downstream calls?
Question 285MediumGo 1.22 to 1.25
A context does not travel over the network by itself; frameworks serialize parts of it. gRPC sends the remaining time in the grpc-timeout header. The server rebuilds a context with that deadline, so a 2s budget at the edge shrinks as it flows through services A to B to C. Cancellation also propagates: if the client cancels, the stream is reset and the server's context is canceled. Tracing systems (OpenTelemetry) carry span context in headers the same way.
For budgeting inside a service:
- Give each downstream call a sub-timeout derived from the incoming context, so none of them can exceed the overall deadline.
- Fail fast: if not enough time remains for a useful call, skip it or degrade instead of starting doomed work.
func (s *Svc) Quote(ctx context.Context, id string) (*Quote, error) {
if dl, ok := ctx.Deadline(); ok && time.Until(dl) < 50*time.Millisecond {
return nil, status.Error(codes.DeadlineExceeded, "insufficient budget")
}
pctx, cancel := context.WithTimeout(ctx, 300*time.Millisecond)
defer cancel()
price, err := s.pricing.Get(pctx, id) // bounded by min(300ms, remaining)
if err != nil {
return nil, err
}
return &Quote{ID: id, Price: price, Promo: s.promoOrDefault(ctx, id)}, nil
}
Gotcha: HTTP does not carry deadlines by default. A hand-built service mesh must pass the budget along in a header, or downstream services keep working after the caller has given up.
More on Context
- Q283How would you merge two contexts so the result is canceled when either one is?
- Q284Can you implement your own Context type? How does the stdlib propagate cancellation from a custom parent?
- Q286How do you implement graceful shutdown with signal.NotifyContext, and what context mistake defeats it?
- Q287How do you test context-aware code, including timeouts and cancellation?
- Q288Is a context safe for concurrent use? What happens if you read ctx.Done() from many goroutines, or call cancel concurrently?
- Q289How should a library expose context in its API, and how do you add context support to an existing API without breaking callers?