@@ -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