fix: use ContextVar for client config overrides and propagate context to thread pool#162
Open
halfbaked wants to merge 1 commit into
Open
Conversation
… to thread pool
Two bugs prevented CLIENT_CONFIG_OVERRIDES_KEY from working:
1. create_clickhouse_client() called ctx.get_state() without await.
get_state is async, so calling it from a sync function returns a
coroutine object instead of the actual value. The override was
silently ignored. Unit tests masked this because MagicMock.get_state
returns values synchronously.
2. QUERY_EXECUTOR.submit() did not propagate contextvars to worker
threads. Even if bug 1 were fixed, the override set by middleware
in the async context would be invisible to execute_query running
in the thread pool.
Fix:
- Replace ctx.get_state/set_state with a module-level ContextVar
(_client_config_overrides_var) that middleware can set synchronously.
- Wrap ThreadPoolExecutor in _ContextPropagatingExecutor that uses
contextvars.copy_context().run() to propagate the calling context
into worker threads.
- Update tests to use the ContextVar directly instead of mocked
ctx.get_state.
Middleware should now use:
from mcp_clickhouse.mcp_server import _client_config_overrides_var
token = _client_config_overrides_var.set({...})
try:
result = await call_next(context)
finally:
_client_config_overrides_var.reset(token)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
CLIENT_CONFIG_OVERRIDES_KEY(introduced for per-request client config overrides via middleware) does not work. Two bugs prevent the override from being applied:Bug 1: Async/sync mismatch in
create_clickhouse_clientcreate_clickhouse_client()is a sync function that callsctx.get_state(CLIENT_CONFIG_OVERRIDES_KEY)withoutawait:Context.get_stateisasync def, so calling it withoutawaitreturns a coroutine object, not the dict. The override is silently ignored. The unit tests pass becauseMagicMock.get_state.return_valuereturns synchronously, masking the bug.Bug 2:
QUERY_EXECUTOR.submitdoesn't propagatecontextvarsThreadPoolExecutor.submitdoes not copy the current context into worker threads. Even if Bug 1 were fixed,ContextVarvalues set by middleware in the async context are invisible toexecute_queryrunning in the thread pool.Fix
Replace
ctx.get_state/set_statewith a module-levelContextVar(_client_config_overrides_var). This is synchronous and works naturally withcontextvarspropagation.Wrap
ThreadPoolExecutorin_ContextPropagatingExecutorthat usescontextvars.copy_context().run()to propagate the calling context into worker threads.How middleware should use it
Testing
ContextVardirectly instead of mockedctx.get_stateRelated