Context timeout configuration for HTTP handlers with downstream database calls in Go
0 reputation · 01 Mar 2021, 17:12 UTC
I am designing a Go service where each incoming HTTP request spawns a chain of calls: a database query, an outbound API request, and a cache write. I want a single deadline to govern the whole chain, but I also want individual stages to have their own stricter limits where needed.
My current assumption is that I would derive a base context with context.WithTimeout at the handler entry point, then derive child contexts with shorter deadlines for specific stages, passing each as the first argument rather than storing it in a struct. I know cancellation is hierarchical and cooperative, so each goroutine must select on ctx.Done(), and every derived cancel function must be called to avoid leaks.
What I am unsure about is the configuration boundary: when a child deadline fires, the error is context.DeadlineExceeded, but I need to distinguish "my stage timed out" from "the parent request was cancelled" when mapping to HTTP status codes. I also want the cache write to complete even if the request context is cancelled.
Which pattern is idiomatic for distinguishing child deadline expiry from parent cancellation? Is detaching the cache write via context.WithoutCancel (Go 1.21+) the right tool, and what are its trade-offs? Should stage timeouts be absolute durations or derived from remaining parent time?