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