Implementing Deadlines and Timeouts

1. Setting Client Deadline

APIDetail
WithDeadlineAbsolute time
WithTimeoutRelative duration
Sent asgrpc-timeout header

2. Setting Client Timeout

Example: Per-call timeout

ctx, cancel := context.WithTimeout(ctx, 500*time.Millisecond)
defer cancel()
_, err := client.GetUser(ctx, req)

3. Checking Remaining Time

Example: Compute leftover budget

if dl, ok := ctx.Deadline(); ok {
    remaining := time.Until(dl)
    if remaining < 50*time.Millisecond {
        return nil, status.Error(codes.DeadlineExceeded, "insufficient budget")
    }
}

4. Propagating Deadlines

BehaviorDetail
Auto-propagationgRPC forwards grpc-timeout across hops via ctx
Subtract marginAllow time for local processing
Don't extendNever increase parent deadline downstream

5. Setting Per-Call Timeout

MechanismDetail
ContextPreferred — explicit per call
Service configDefault for method via JSON

6. Using Default Timeout

Example: Service config default

{
  "methodConfig": [{
    "name": [{ "service": "user.v1.UserService" }],
    "timeout": "2s"
  }]
}

7. Handling Deadline Exceeded

SideDetail
Clientcodes.DeadlineExceeded
Serverctx.Err() = context.DeadlineExceeded — abort cleanly

8. Implementing Timeout Retry

RuleDetail
Only for idempotentPer idempotency_level
Bound attemptsUse retry policy or hedging
Reset deadlineAllocate fresh budget per attempt or use parent

9. Setting Server-Side Timeout

ApproachDetail
Interceptor with defaultApply timeout if client didn't set one
Honor client deadlineAlways check ctx

10. Using WaitForReady Option

Example: WaitForReady

res, err := client.GetUser(ctx, req, grpc.WaitForReady(true))
BehaviorDetail
trueQueue call until subchannel ready (or deadline hits)
false (default)Fail-fast with Unavailable if not ready