@@ -30,10 +30,22 @@ async def wrapper() -> AsyncGenerator[T, None]:
3030 # This is needed to propagate context across async generator boundaries
3131 for context_var in context_vars :
3232 try :
33- previous_values [context_var ] = context_var .get ()
33+ current_value = context_var .get ()
34+ previous_values [context_var ] = current_value
35+ # Only set if value actually changed to avoid creating unnecessary tokens
36+ target_value = initial_context_values [context_var .name ]
37+ if current_value != target_value :
38+ tokens [context_var ] = context_var .set (target_value )
39+ else :
40+ tokens [context_var ] = None
3441 except LookupError :
3542 previous_values [context_var ] = _MISSING
36- tokens [context_var ] = context_var .set (initial_context_values [context_var .name ])
43+ # Var was unset, set it to initial value
44+ target_value = initial_context_values [context_var .name ]
45+ if target_value is not None :
46+ tokens [context_var ] = context_var .set (target_value )
47+ else :
48+ tokens [context_var ] = None
3749
3850 def _restore_context_var (context_var : ContextVar , * , _tokens = tokens , _prev = previous_values ) -> None :
3951 token = _tokens .get (context_var )
@@ -45,10 +57,15 @@ def _restore_context_var(context_var: ContextVar, *, _tokens=tokens, _prev=previ
4557 except (RuntimeError , ValueError ):
4658 pass
4759
48- if previous_value is _MISSING :
49- context_var .set (None )
50- else :
51- context_var .set (previous_value )
60+ # Manual restoration when token reset fails
61+ # Avoid creating unnecessary tokens to prevent accumulation that can cause deadlocks
62+ if previous_value is not _MISSING :
63+ try :
64+ current_value = context_var .get ()
65+ if current_value != previous_value :
66+ context_var .set (previous_value )
67+ except LookupError :
68+ context_var .set (previous_value )
5269
5370 try :
5471 item = await gen .__anext__ ()
0 commit comments