We can't find the internet
Attempting to reconnect
Something went wrong!
Attempting to reconnect
← Concurrency with Threads and asyncio step 46 of 56
Build a Request ID That Follows Tasks and Threads
Build the helpers a web service uses to tag its logs with a request ID. Code anywhere in the request can ask for the current ID, without anyone passing it as an argument.
with request_context("req-42"):
current_request_id() # "req-42"
with request_context("req-43"):
current_request_id() # "req-43"
current_request_id() # "req-42"
current_request_id() # None
What to write
@contextmanager
def request_context(request_id: str) -> Iterator[None]: ...
def current_request_id() -> str | None: ...
async def with_request[T](request_id: str, coro: Coroutine[Any, Any, T]) -> T: ...
Store the ID in one module-level ContextVar[str | None] with
default=None. Then follow these rules:
request_context(request_id)sets the variable for thewithblock. On exit, it puts back exactly the value from before. Keep the token thatsetreturns, and pass it toresetin afinallyblock. Then the old value comes back after an exception or a cancellation too.- Leaving a nested block puts back the outer ID. A plain
set(None)on exit would lose it. current_request_id()returns the current ID, orNonewhen none is set.with_request(request_id, coro)entersrequest_context(request_id), awaitscorodirectly inside it, in the current task, and returns the result. Exceptions and cancellation pass through to the caller.- IDs are strings, and the empty string
""is a real ID, distinct fromNone.
What the driver checks
Keep solve as it is. It runs one scenario:
| Scenario | What it checks |
|---|---|
nested_task |
Two child tasks started inside scope A both see A |
isolation |
Requests A and B run at the same time, and each sees only its own ID |
no_leak |
A child task sets CHILD inside A, then sees A again, and the parent still sees A |
exception |
A block that raises still puts back the previous value |
cancel |
A cancelled with_request puts back the previous value before its caller sees the CancelledError |
thread |
A function run with asyncio.to_thread inside A sees A in the worker thread |
nested_ctx |
Nested scopes read A, B, A, then None |
The report has these keys:
beforeandafter: the ID at the start and end of the scenario. Both areNone.observed: the IDs the scenario read, in order.thread_value: what the worker thread read in thethreadscenario, andNoneotherwise.outcome:"ok","ValueError"or"CancelledError".
Your code, saved here
Sign in to access your accepted solutions and saved draft history. You can keep reading the lesson without an account.
Sign in to your accountStuck?
Python reference solution
Sign in to track your attempts toward unlocking the reference solution.