Skip to content

Make hanging-request fake-server teardown deterministic and bounded - #17

Merged
HelloThisWorld merged 1 commit into
mainfrom
fix/fake-ollama-teardown
Aug 19, 2026
Merged

Make hanging-request fake-server teardown deterministic and bounded#17
HelloThisWorld merged 1 commit into
mainfrom
fix/fake-ollama-teardown

Conversation

@HelloThisWorld

Copy link
Copy Markdown
Owner

Summary

A post-merge main run on macOS/node 20 spent the full 30-second Vitest budget inside ollama.test.ts > a timeout aborts the request deterministically — a test whose own contract is ~1.5 seconds — while 1,649 of 1,650 tests passed (failing job). The test drives the fake server''s timeout behavior (accept the request, never respond) and closes the server in a finally, so the anonymous outer timeout could not even distinguish a hung client abort from a hung fixture teardown.

Inspection found the concrete design gap on the teardown side: close() relied on closeAllConnections?.() plus the server close callback, with no bound on the wait and no tracking of the socket a client abort leaves mid-unwind — a code path that could wait forever on an OS/runtime scheduling hiccup. Both fake HTTP servers (Ollama and OpenAI-compatible, which shared the identical pattern) now use one hardened lifecycle, trackedServerLifecycle: every accepted TCP socket is tracked from the connection event; close() stops the listener, explicitly destroys every live socket (idle keep-alive and intentionally hanging requests), and bounds the whole wait — on expiry it force-destroys stragglers and rejects with <server> teardown timed out after N ms with K tracked socket(s) still open, so any future hang fails fast at the actual location with actionable diagnostics instead of hiding behind the outer test budget.

Deliberately unchanged: the timeout fixture still leaves a real hanging HTTP request that only the client''s AbortSignal.timeout ends (the abort path stays genuinely tested); production timeout/cancellation semantics in safeHttpRequest and the Ollama runner are untouched; and no Vitest timeout budget was raised anywhere — the point is to remove the hang, not to hide it. Loopback-only traffic, no platform-specific behavior.

New regression tests (fake server lifecycle describe block): teardown after a client-aborted hanging request completes well inside a 2s bound with the timeout still classified timed-out/timed_out; teardown while a request is still in flight destroys it and settles; ten abort→teardown cycles stay bounded. The adjacent cancellation test (same hanging fixture) is covered by the same hardened helper.

Validation

  • tests/runners/ollama.test.ts: 27/27 (24 existing + 3 new)
  • Stress: 20 consecutive runs of the whole file (~20 timeout + ~200 external-cancellation abort→teardown cycles): 0 failures
  • Every consumer of the changed helpers (openai-compatible, mcp-runner-tools, openai-execution, multi-runner, conformance, cli-v06-runner): 90/90
  • pnpm lint / pnpm typecheck / pnpm build: pass
  • pnpm test: 116 files, 1,651 tests, exit 0
  • macOS node 20 targeted validation: NOT RUN (no macOS environment here; validated on Windows — the hardening is platform-neutral by design)

Checklist

  • pnpm lint, pnpm typecheck, and pnpm test pass locally
  • pnpm check:public-contracts passes — no contract touched (test helpers only)
  • Documentation updated for any user-visible behavior change — none
  • CHANGELOG entry added for any user-visible change — none
  • Everything is in English (code, comments, docs, commit messages)
  • No employer or client proprietary content — examples and fixtures are synthetic
  • No credentials, tokens, or secret values anywhere in the diff, fixtures, or recorded test output

…nded

A post-merge macOS/node 20 run spent the full 30-second Vitest budget
inside "a timeout aborts the request deterministically" -- a test whose
own contract is ~1.5 seconds -- while 1,649 of 1,650 tests passed. The
test drives the fake Ollama server''s `timeout` behavior (accept the
request, never respond) and then closes the server in a finally block, so
the anonymous outer timeout could not even say whether the client abort
or the fixture teardown was the side that hung.

The fixture teardown was the suspect with an actual design gap: it relied
on `closeAllConnections?.()` plus the server close callback, with nothing
bounding the wait and nothing tracking the socket the aborted request
leaves mid-unwind. Both fake servers now share one hardened lifecycle
(`trackedServerLifecycle`): every accepted TCP socket is tracked from the
`connection` event, `close()` stops the listener, destroys every live
socket explicitly (idle keep-alive AND intentionally hanging requests),
and bounds the whole wait -- on expiry it force-destroys stragglers and
rejects with "<server> teardown timed out after N ms with K tracked
socket(s) still open", so any future hang fails fast at the actual
location instead of hiding behind the outer test budget.

Nothing about the CLIENT path changed: the timeout fixture still leaves a
real hanging HTTP request that only AbortSignal.timeout ends, production
timeout/cancellation semantics are untouched, and no Vitest budget was
raised anywhere.

New regression tests (fake server lifecycle): teardown after a
client-aborted hanging request completes well inside a 2 s bound with the
timeout still classified; teardown WHILE a request is still in flight
destroys it and settles; and ten abort-to-teardown cycles stay bounded.
Stress: 20 consecutive runs of the whole Ollama file (about 20 timeout
plus 200 cancellation abort/teardown cycles) with zero failures. Full
suite: 1,651 tests passing.
@HelloThisWorld
HelloThisWorld merged commit acb4312 into main Aug 19, 2026
7 checks passed
@HelloThisWorld
HelloThisWorld deleted the fix/fake-ollama-teardown branch August 19, 2026 12:56
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant