Skip to content

Commit 1e763aa

Browse files
fix: use socket.shutdown() in Python force_stop() for reliable disconnect
socket.close() and file wrapper close don't reliably interrupt a blocking readline() on another thread in Python. socket.shutdown(SHUT_RDWR) sends TCP FIN to the server immediately (triggering server-side disconnect detection) and interrupts any pending blocking reads across threads — matching Node.js socket.destroy() and Go conn.Close() behavior.
1 parent 49569b4 commit 1e763aa

1 file changed

Lines changed: 14 additions & 5 deletions

File tree

python/copilot/client.py

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2259,17 +2259,26 @@ def __init__(self, sock_file, sock_obj):
22592259
self._socket = sock_obj
22602260

22612261
def terminate(self):
2262-
# Close the file wrapper first — makefile() holds its own
2263-
# reference to the socket, so socket.close() alone won't
2264-
# release the OS-level resource until the wrapper is closed too.
2262+
import socket as _socket_mod
2263+
2264+
# shutdown() sends TCP FIN to the server (triggering
2265+
# server-side disconnect detection) and interrupts any
2266+
# pending blocking reads on other threads immediately.
22652267
try:
2266-
self.stdin.close()
2268+
self._socket.shutdown(_socket_mod.SHUT_RDWR)
22672269
except OSError:
22682270
pass # Safe to ignore — socket may already be closed
2271+
# Close the file wrapper — makefile() holds its own
2272+
# reference to the fd, so socket.close() alone won't
2273+
# release the OS resource until the wrapper is closed too.
2274+
try:
2275+
self.stdin.close()
2276+
except OSError:
2277+
pass # Safe to ignore — already closed
22692278
try:
22702279
self._socket.close()
22712280
except OSError:
2272-
pass # Safe to ignore — socket may already be closed
2281+
pass # Safe to ignore — already closed
22732282

22742283
def kill(self):
22752284
self.terminate()

0 commit comments

Comments
 (0)