mirror of
https://github.com/PrefectHQ/fastmcp.git
synced 2026-08-21 04:54:17 +02:00
Fix race condition with mounted server task results
When a server is mounted on another, both were creating their own Docket and Worker instances. With memory:// URLs they share the same FakeServer queue but have separate result_storage instances. This caused a race condition where results could be stored in one Docket's storage but looked up in another's, returning None. The fix marks mounted servers with `_is_mounted=True` flag so they skip creating their own Docket/Worker. The parent's Docket handles all task execution for mounted servers. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
parent
54fcdad85f
commit
a335a9dd89
1 changed files with 15 additions and 0 deletions
|
|
@ -201,6 +201,9 @@ class FastMCP(Generic[LifespanResultT]):
|
|||
|
||||
self._additional_http_routes: list[BaseRoute] = []
|
||||
self._mounted_servers: list[MountedServer] = []
|
||||
self._is_mounted: bool = (
|
||||
False # Set to True when this server is mounted on another
|
||||
)
|
||||
self._tool_manager: ToolManager = ToolManager(
|
||||
duplicate_behavior=on_duplicate_tools,
|
||||
mask_error_details=mask_error_details,
|
||||
|
|
@ -395,6 +398,13 @@ class FastMCP(Generic[LifespanResultT]):
|
|||
server_token = _current_server.set(weakref.ref(self))
|
||||
|
||||
try:
|
||||
# For directly mounted servers, the parent's Docket/Worker handles all
|
||||
# task execution. Skip creating our own to avoid race conditions with
|
||||
# multiple workers competing for tasks from the same queue.
|
||||
if self._is_mounted:
|
||||
yield
|
||||
return
|
||||
|
||||
# Create Docket instance using configured name and URL
|
||||
async with Docket(
|
||||
name=settings.docket.name,
|
||||
|
|
@ -2696,6 +2706,11 @@ class FastMCP(Generic[LifespanResultT]):
|
|||
if as_proxy and not isinstance(server, FastMCPProxy):
|
||||
server = FastMCP.as_proxy(server)
|
||||
|
||||
# Mark the server as mounted so it skips creating its own Docket/Worker.
|
||||
# The parent's Docket handles task execution, avoiding race conditions
|
||||
# with multiple workers competing for tasks from the same queue.
|
||||
server._is_mounted = True
|
||||
|
||||
# Delegate mounting to all three managers
|
||||
mounted_server = MountedServer(
|
||||
prefix=prefix,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue