@@ -155,6 +155,8 @@ def __init__(self, socket_read_timeout=_DEFAULT_SOCKET_READ_TIMEOUT):
155155 self ._socket_read_timeout = socket_read_timeout + socket_read_timeout * .3
156156 self ._response = None
157157 self ._done = asyncio .Event ()
158+ client_timeout = aiohttp .ClientTimeout (total = 0 , sock_read = self ._socket_read_timeout )
159+ self ._sess = aiohttp .ClientSession (timeout = client_timeout )
158160
159161 async def start (self , url , extra_headers = None ): # pylint:disable=protected-access
160162 """
@@ -168,46 +170,53 @@ async def start(self, url, extra_headers=None): # pylint:disable=protected-acce
168170 raise RuntimeError ('Client already started.' )
169171
170172 self ._done .clear ()
171- client_timeout = aiohttp .ClientTimeout (total = 0 , sock_read = self ._socket_read_timeout )
172- async with aiohttp .ClientSession (timeout = client_timeout ) as sess :
173- try :
174- async with sess .get (url , headers = get_headers (extra_headers )) as response :
175- self ._response = response
176- event_builder = EventBuilder ()
177- async for line in response .content :
178- if line .startswith (b':' ):
179- _LOGGER .debug ("skipping emtpy line / comment" )
180- continue
181- elif line in _EVENT_SEPARATORS :
182- _LOGGER .debug ("dispatching event: %s" , event_builder .build ())
183- yield event_builder .build ()
184- event_builder = EventBuilder ()
185- else :
186- event_builder .process_line (line )
187-
188- except Exception as exc : # pylint:disable=broad-except
189- if self ._is_conn_closed_error (exc ):
190- _LOGGER .debug ('sse connection ended.' )
191- return
192-
193- _LOGGER .error ('http client is throwing exceptions' )
194- _LOGGER .error ('stack trace: ' , exc_info = True )
195-
196- finally :
197- self ._response = None
198- self ._done .set ()
173+ try :
174+ async with self ._sess .get (url , headers = get_headers (extra_headers )) as response :
175+ self ._response = response
176+ event_builder = EventBuilder ()
177+ async for line in response .content :
178+ if line .startswith (b':' ):
179+ _LOGGER .debug ("skipping emtpy line / comment" )
180+ continue
181+ elif line in _EVENT_SEPARATORS :
182+ _LOGGER .debug ("dispatching event: %s" , event_builder .build ())
183+ yield event_builder .build ()
184+ event_builder = EventBuilder ()
185+ else :
186+ event_builder .process_line (line )
187+
188+ except Exception as exc : # pylint:disable=broad-except
189+ if self ._is_conn_closed_error (exc ):
190+ _LOGGER .debug ('sse connection ended.' )
191+ return
192+
193+ _LOGGER .error ('http client is throwing exceptions' )
194+ _LOGGER .error ('stack trace: ' , exc_info = True )
195+
196+ finally :
197+ self ._response = None
198+ self ._done .set ()
199199
200200 async def shutdown (self ):
201201 """Close connection"""
202202 if self ._response :
203203 self ._response .close ()
204- await self ._done .wait ()
204+ # catching exception to avoid task hanging
205+ try :
206+ await self ._done .wait ()
207+ except asyncio .CancelledError :
208+ _LOGGER .error ("Exception waiting for event source ended" )
209+ _LOGGER .debug ('stack trace: ' , exc_info = True )
210+ pass
205211
206212 @staticmethod
207213 def _is_conn_closed_error (exc ):
208214 """Check if the ReadError is caused by the connection being closed."""
209215 return isinstance (exc , aiohttp .ClientConnectionError ) and str (exc ) == "Connection closed"
210216
217+ async def close_session (self ):
218+ if not self ._sess .closed :
219+ await self ._sess .close ()
211220
212221def get_headers (extra = None ):
213222 """
0 commit comments