mirror of https://github.com/home-assistant/core
Fix shutdown being delayed for cancelling tasks (#93287)
This commit is contained in:
parent
72c76d35cc
commit
780f9bcdc0
|
@ -82,7 +82,11 @@ from .exceptions import (
|
||||||
from .helpers.aiohttp_compat import restore_original_aiohttp_cancel_behavior
|
from .helpers.aiohttp_compat import restore_original_aiohttp_cancel_behavior
|
||||||
from .helpers.json import json_dumps
|
from .helpers.json import json_dumps
|
||||||
from .util import dt as dt_util, location, ulid as ulid_util
|
from .util import dt as dt_util, location, ulid as ulid_util
|
||||||
from .util.async_ import run_callback_threadsafe, shutdown_run_callback_threadsafe
|
from .util.async_ import (
|
||||||
|
cancelling,
|
||||||
|
run_callback_threadsafe,
|
||||||
|
shutdown_run_callback_threadsafe,
|
||||||
|
)
|
||||||
from .util.read_only_dict import ReadOnlyDict
|
from .util.read_only_dict import ReadOnlyDict
|
||||||
from .util.timeout import TimeoutManager
|
from .util.timeout import TimeoutManager
|
||||||
from .util.unit_system import (
|
from .util.unit_system import (
|
||||||
|
@ -678,7 +682,11 @@ class HomeAssistant:
|
||||||
start_time: float | None = None
|
start_time: float | None = None
|
||||||
current_task = asyncio.current_task()
|
current_task = asyncio.current_task()
|
||||||
|
|
||||||
while tasks := [task for task in self._tasks if task is not current_task]:
|
while tasks := [
|
||||||
|
task
|
||||||
|
for task in self._tasks
|
||||||
|
if task is not current_task and not cancelling(task)
|
||||||
|
]:
|
||||||
await self._await_and_log_pending(tasks)
|
await self._await_and_log_pending(tasks)
|
||||||
|
|
||||||
if start_time is None:
|
if start_time is None:
|
||||||
|
@ -791,7 +799,7 @@ class HomeAssistant:
|
||||||
# while we are awaiting canceled tasks to get their result
|
# while we are awaiting canceled tasks to get their result
|
||||||
# which will result in the set size changing during iteration
|
# which will result in the set size changing during iteration
|
||||||
for task in list(running_tasks):
|
for task in list(running_tasks):
|
||||||
if task.done():
|
if task.done() or cancelling(task):
|
||||||
# Since we made a copy we need to check
|
# Since we made a copy we need to check
|
||||||
# to see if the task finished while we
|
# to see if the task finished while we
|
||||||
# were awaiting another task
|
# were awaiting another task
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
"""Asyncio utilities."""
|
"""Asyncio utilities."""
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
from asyncio import Semaphore, gather, get_running_loop
|
from asyncio import Future, Semaphore, gather, get_running_loop
|
||||||
from asyncio.events import AbstractEventLoop
|
from asyncio.events import AbstractEventLoop
|
||||||
from collections.abc import Awaitable, Callable
|
from collections.abc import Awaitable, Callable
|
||||||
import concurrent.futures
|
import concurrent.futures
|
||||||
|
@ -20,6 +20,13 @@ _R = TypeVar("_R")
|
||||||
_P = ParamSpec("_P")
|
_P = ParamSpec("_P")
|
||||||
|
|
||||||
|
|
||||||
|
def cancelling(task: Future[Any]) -> bool:
|
||||||
|
"""Return True if task is done or cancelling."""
|
||||||
|
# https://docs.python.org/3/library/asyncio-task.html#asyncio.Task.cancelling
|
||||||
|
# is new in Python 3.11
|
||||||
|
return bool((cancelling_ := getattr(task, "cancelling", None)) and cancelling_())
|
||||||
|
|
||||||
|
|
||||||
def run_callback_threadsafe(
|
def run_callback_threadsafe(
|
||||||
loop: AbstractEventLoop, callback: Callable[..., _T], *args: Any
|
loop: AbstractEventLoop, callback: Callable[..., _T], *args: Any
|
||||||
) -> concurrent.futures.Future[_T]:
|
) -> concurrent.futures.Future[_T]:
|
||||||
|
|
Loading…
Reference in New Issue