Skip to content

Commit ef2ecce

Browse files
aojeayliaog
authored andcommitted
fix(watch): shutdown raw socket in stop() to prevent SSL read deadlocks
1 parent 3735c2c commit ef2ecce

1 file changed

Lines changed: 17 additions & 0 deletions

File tree

kubernetes/base/watch/watch.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,21 @@ 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. The actual response/connection closing is handled in the finally
103+
# block when the stream loop exits.
104+
conn = getattr(self._resp, 'connection', None)
105+
sock = getattr(conn, 'sock', None) if conn else None
106+
if sock:
107+
sock.shutdown(socket.SHUT_RDWR)
108+
except Exception:
109+
pass
110+
96111

97112
def get_return_type(self, func):
98113
if self._raw_return_type:
@@ -189,6 +204,7 @@ def stream(self, func, *args, **kwargs):
189204
deserialize = kwargs.pop('deserialize', True)
190205
while True:
191206
resp = func(*args, **kwargs)
207+
self._resp = resp
192208
try:
193209
for line in iter_resp_lines(resp):
194210
# unmarshal when we are receiving events from watch,
@@ -226,6 +242,7 @@ def stream(self, func, *args, **kwargs):
226242
finally:
227243
resp.close()
228244
resp.release_conn()
245+
self._resp = None
229246
if self.resource_version is not None:
230247
kwargs['resource_version'] = self.resource_version
231248
else:

0 commit comments

Comments
 (0)