fix(cache): prevent Connection closed errors during SWR background revalidation#2854
Merged
fix(cache): prevent Connection closed errors during SWR background revalidation#2854
Conversation
Contributor
🧪 BenchmarkShould we run the Virtual MCP strategy benchmark for this PR? React with 👍 to run the benchmark.
Benchmark will run on the next push after you react. |
Contributor
Release OptionsSuggested: Patch ( React with an emoji to override the release type:
Current version:
|
Contributor
There was a problem hiding this comment.
1 issue found across 13 files
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately. <file name="apps/mesh/src/api/app.ts"> <violation number="1" location="apps/mesh/src/api/app.ts:989"> P1: Wrap `await next()` in `try/finally` so pending revalidation handling still runs when downstream handlers throw.</violation> </file> Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.
Add a `pendingRevalidations: Promise<void>[]` field to MeshContext to track SWR background revalidation promises. This allows middleware to keep the request context alive while revalidations complete. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…ed errors Add optional `onRevalidation` callback to `fetchWithCache` so callers can track background revalidation promises. Add `isConnectionClosed` predicate to silently handle MCP connection closed errors during background revalidation (defense-in-depth for SWR best-effort semantics). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Pass onRevalidation callback at all 4 production call sites to register background revalidation promises on ctx.pendingRevalidations. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…losed errors After the route handler returns, fire-and-forget await pending SWR revalidations (with 30s timeout) to keep ctx and its client pool alive via closure. No pool disposal — SSE/streaming connections depend on pool clients remaining open. Fixes background revalidation "Connection closed" errors for HTTP/SSE MCP connections by ensuring the per-request client pool stays alive while revalidations complete. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2c79fd2 to a7f088d Compare pedrofrxncx approved these changes Mar 25, 2026
Ensures pending SWR revalidations run even when downstream handlers throw. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The LIST tool was triggering background SWR revalidations for every connection's tools via fetchWithCache. This is unnecessary since the GET tool already handles per-connection revalidation. Removing it reduces unnecessary background work and potential connection closed errors.
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.
What is this contribution about?
Fixes
McpError: MCP error -32000: Connection closederrors that occur during background cache revalidation for HTTP/SSE MCP connections.Root cause:
fetchWithCacheimplements stale-while-revalidate (SWR) — on cache hit, it returns cached data immediately and fires a backgroundfetchLive()to refresh the cache. For HTTP/SSE connections,fetchLive()creates clients via the per-request pool (ctx.getOrCreateClient). The pool's connections get closed before the background revalidation completes, causing the error.Fix (two layers):
pendingRevalidationsarray toMeshContext. Background revalidation promises are registered via anonRevalidationcallback. A Hono middleware fire-and-forgets awaiting these promises after the handler returns, keepingctx(and its client pool) alive via closure while revalidations complete. 30s timeout prevents hung revalidations.isMethodNotFoundhandling), since SWR revalidation is best-effort.No pool disposal is added — SSE/streaming proxy connections depend on pool clients remaining open after the handler returns.
Screenshots/Demonstration
N/A — backend-only change.
How to Test
[fetchWithCache] ... background revalidation FAILED: McpError: MCP error -32000: Connection closederrors in logsbun test apps/mesh/src/mcp-clients/mcp-list-cache.test.ts— all 27 tests should passMigration Notes
N/A — no database or configuration changes.
Review Checklist
Summary by cubic
Fixes MCP error -32000 "Connection closed" during SWR background revalidation for HTTP/SSE MCP connections by keeping the per-request client pool alive and treating revalidation as best-effort. Also skips redundant revalidations in the connections list to reduce noise and background work.
pendingRevalidationstoMeshContextand anonRevalidationcallback infetchWithCache; all call sites register revalidation promises, andhonomiddleware fire-and-forgets a 30s await after the handler returns, now wrapped in try/finally to keep the client pool alive.fetchWithCachenow suppresses "Connection closed" errors during revalidation and continues handlingMethodNotFoundby caching empty lists.COLLECTION_CONNECTIONS_LIST; the GET tool already revalidates per-connection, preventing unnecessary fan-out and potential connection closures.Written for commit be97752. Summary will update on new commits.