Skip to content

Commit 6a83c7e

Browse files
committed
fix(watch): shutdown raw socket in stop() to prevent SSL read deadlocks
1 parent 9b28fde commit 6a83c7e

1 file changed

Lines changed: 21 additions & 0 deletions

File tree

kubernetes/base/watch/watch.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,25 @@ def __init__(self, return_type=None):
9393

9494
def stop(self):
9595
self._stop = True
96+
if hasattr(self, '_resp') and self._resp:
97+
import socket
98+
try:
99+
# Python SSL/socket GIL Workaround: Force-shutdown the raw socket under HTTP/1.1
100+
# to immediately unblock the background thread blocked in CPython's ssl.read() recv_into
101+
# call. This avoids deadlock where close() hangs waiting for SSL socket locks held by
102+
# the blocked read call.
103+
conn = getattr(self._resp, 'connection', None)
104+
sock = getattr(conn, 'sock', None) if conn else None
105+
if sock:
106+
sock.shutdown(socket.SHUT_RDWR)
107+
except Exception:
108+
pass
109+
try:
110+
self._resp.close()
111+
self._resp.release_conn()
112+
except Exception:
113+
pass
114+
96115

97116
def get_return_type(self, func):
98117
if self._raw_return_type:
@@ -189,6 +208,7 @@ def stream(self, func, *args, **kwargs):
189208
deserialize = kwargs.pop('deserialize', True)
190209
while True:
191210
resp = func(*args, **kwargs)
211+
self._resp = resp
192212
try:
193213
for line in iter_resp_lines(resp):
194214
# unmarshal when we are receiving events from watch,
@@ -226,6 +246,7 @@ def stream(self, func, *args, **kwargs):
226246
finally:
227247
resp.close()
228248
resp.release_conn()
249+
self._resp = None
229250
if self.resource_version is not None:
230251
kwargs['resource_version'] = self.resource_version
231252
else:

0 commit comments

Comments
 (0)