Revert "Recreate aiohttp session on connectivity check (#5332)" (#5851)

This reverts commit 1504278223a8d852d3b11de25f676fa8d6501a70.

It turns out that recreating the session can cause race conditions, e.g.
with API checks triggered by proxied requests running alongside. These
manifest in the following error:

AttributeError: 'NoneType' object has no attribute 'connect'
...
  File "supervisor/homeassistant/api.py", line 187, in check_api_state
    if state := await self.get_api_state():
  File "supervisor/homeassistant/api.py", line 171, in get_api_state
    data = await self.get_core_state()
  File "supervisor/homeassistant/api.py", line 145, in get_core_state
    return await self._get_json("api/core/state")
  File "supervisor/homeassistant/api.py", line 132, in _get_json
    async with self.make_request("get", path) as resp:
  File "contextlib.py", line 214, in __aenter__
    return await anext(self.gen)
  File "supervisor/homeassistant/api.py", line 106, in make_request
    async with getattr(self.sys_websession, method)(
  File "aiohttp/client.py", line 1425, in __aenter__
    self._resp: _RetType = await self._coro
  File "aiohttp/client.py", line 703, in _request
    conn = await self._connector.connect(

The only reason for the _connection in the aiohttp client to be None is
when close() gets called on the session. The only place this is being
done is the connectivity check.

So it seems that between fetching the session from the `sys_websession`
property) and actually using the connector, a connectivity check has been
run which then causes the above stack trace.

Let's not mess with the lifetime of the ClientSession object and simply
revert the change. Another solution for the original problem needs to be
found.
This commit is contained in:
Stefan Agner 2025-04-28 23:48:47 +02:00 committed by GitHub
parent 4b5bcece64
commit 53393afe8d
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 5 additions and 15 deletions

View File

@ -68,7 +68,7 @@ class CoreSys:
# External objects
self._loop: asyncio.BaseEventLoop = asyncio.get_running_loop()
self._websession = None
self._websession: aiohttp.ClientSession = aiohttp.ClientSession()
# Global objects
self._config: CoreConfig = CoreConfig()
@ -101,8 +101,10 @@ class CoreSys:
self._bus: Bus | None = None
self._mounts: MountManager | None = None
# Setup aiohttp session
self.create_websession()
# Set default header for aiohttp
self._websession._default_headers = MappingProxyType(
{aiohttp.hdrs.USER_AGENT: SERVER_SOFTWARE}
)
# Task factory attributes
self._set_task_context: list[Callable[[Context], Context]] = []
@ -582,16 +584,6 @@ class CoreSys:
return self.loop.run_in_executor(None, funct, *args)
def create_websession(self) -> None:
"""Create a new aiohttp session."""
if self._websession:
self.create_task(self._websession.close())
# Create session and set default header for aiohttp
self._websession: aiohttp.ClientSession = aiohttp.ClientSession(
headers=MappingProxyType({aiohttp.hdrs.USER_AGENT: SERVER_SOFTWARE})
)
def _create_context(self) -> Context:
"""Create a new context for a task."""
context = copy_context()

View File

@ -292,8 +292,6 @@ class Supervisor(CoreSysAttributes):
"https://checkonline.home-assistant.io/online.txt", timeout=timeout
)
except (ClientError, TimeoutError):
# Need to recreate the websession to avoid stale connection checks
self.coresys.create_websession()
self.connectivity = False
else:
self.connectivity = True