Skip to content

Dispose the connection when stopping the client times out - #1937

Open
Trivikram Kamat (trivikr) wants to merge 3 commits into
microsoft:mainfrom
trivikr:client-shutdown-connection-disposal
Open

Trivikram Kamat (trivikr) wants to merge 3 commits into
microsoft:mainfrom
trivikr:client-shutdown-connection-disposal

Conversation

@trivikr

Copy link
Copy Markdown
Contributor

BaseLanguageClient.shutdown() only ended and disposed the connection when the shutdown request and exit notification finished before the timeout. If shutdown timed out or the shutdown request failed, the client dropped the connection without disposing it:

  • Pending responses were never rejected, and the reader and writer were never released.
  • The connection's close and error handlers stayed attached to the client. A late close, for example when the Node client kills the server process after stop, could run handleConnectionClosed() against a restarted client and dispose its new connection.

End and dispose the connection in the finally block, so it happens on every path. Errors from disposing are ignored so they don't hide the original failure. Also, clear the timeout timer when shutdown finishes first.

Copilot AI balanced review requested due to automatic review settings October 31, 2026 05:11

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

A throwing transport end() can still skip disposal and leave pending responses and stale close handlers active, while regression coverage for timeout and rejected-shutdown cleanup is missing.

2 open issues
What changed in this PR

This PR strengthens language-client shutdown cleanup so timed-out or failed shutdowns do not leave stale connections attached to the client.

Changes:

  • Moves connection ending and disposal into finally.
  • Catches cleanup errors to preserve the original shutdown failure.
  • Disposes the timeout timer when shutdown completes.
File Description
client/​src/​common/​client.ts Updates shutdown cleanup to handle success, failure, and timeout paths.

Review effort: Balanced

Comment thread client/src/common/client.ts Resolved
Comment thread client/src/common/client.ts Resolved
Copilot AI balanced review requested due to automatic review settings October 31, 2026 23:35

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has insufficient remaining quota. Try requesting a review at a lower effort level.

shutdown() only disposed the connection if the shutdown finished before
the timeout. On timeout or a failed shutdown request, the connection
leaked and its close handler could later act on a restarted client.

Dispose the connection in the finally block so it happens on every path,
and clear the timeout timer.
shutdown() called connection.end() and connection.dispose() in the same
try block, so if the transport's end() threw, dispose() was skipped and
the error was swallowed. The connection then kept its pending responses
and close handler, which is the leak the previous commit fixes. Call
dispose() in an inner finally so it runs even when end() fails.
Add integration tests for a shutdown request that times out and one
that the server rejects without closing the transport. Each test leaves
a request pending, stops the client, and restarts it before the old
server process is terminated. It then asserts that the pending request
is rejected and that the old transport's late close doesn't stop the
restarted client. Both tests fail without the previous fix.
@trivikr
Trivikram Kamat (trivikr) force-pushed the client-shutdown-connection-disposal branch from 72be05d to 3f8880f Compare October 31, 2026 23:35
Copilot AI balanced review requested due to automatic review settings October 31, 2026 23:35

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has insufficient remaining quota. Try requesting a review at a lower effort level.

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.

2 participants