77from contextlib import contextmanager
88import dataclasses
99from datetime import datetime
10+ import errno
1011import fcntl
1112from io import TextIOWrapper
1213import json
@@ -207,11 +208,20 @@ def new_event_loop(self) -> asyncio.AbstractEventLoop:
207208
208209
209210@callback
210- def _async_loop_exception_handler (_ : Any , context : dict [str , Any ]) -> None :
211+ def _async_loop_exception_handler (
212+ loop : asyncio .AbstractEventLoop ,
213+ context : dict [str , Any ],
214+ ) -> None :
211215 """Handle all exception inside the core loop."""
216+ fatal_error : str | None = None
212217 kwargs = {}
213218 if exception := context .get ("exception" ):
214219 kwargs ["exc_info" ] = (type (exception ), exception , exception .__traceback__ )
220+ if isinstance (exception , OSError ) and exception .errno == errno .EMFILE :
221+ # Too many open files – something is leaking them, and it's likely
222+ # to be quite unrecoverable if the event loop can't pump messages
223+ # (e.g. unable to accept a socket).
224+ fatal_error = str (exception )
215225
216226 logger = logging .getLogger (__package__ )
217227 if source_traceback := context .get ("source_traceback" ):
@@ -232,6 +242,14 @@ def _async_loop_exception_handler(_: Any, context: dict[str, Any]) -> None:
232242 ** kwargs , # type: ignore[arg-type]
233243 )
234244
245+ if fatal_error :
246+ logger .error (
247+ "Fatal error '%s' raised in event loop, shutting it down" ,
248+ fatal_error ,
249+ )
250+ loop .stop ()
251+ loop .close ()
252+
235253
236254async def setup_and_run_hass (runtime_config : RuntimeConfig ) -> int :
237255 """Set up Home Assistant and run."""
0 commit comments