From ec91c1c8b265e8019c4df34879a62b622e4eaa6b Mon Sep 17 00:00:00 2001 From: Lukas Date: Tue, 14 Apr 2026 12:07:35 +0200 Subject: [PATCH] Use shared blocking executor in run_blocking Wire DEFAULT_BLOCKING_EXECUTOR as the default executor in backend/app/utils/async_utils.py, preserving custom executors and marking Task 22 completed in Docs/Tasks.md. --- Docs/Tasks.md | 4 ++++ backend/app/utils/async_utils.py | 9 ++++++--- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/Docs/Tasks.md b/Docs/Tasks.md index a71b401..6d21909 100644 --- a/Docs/Tasks.md +++ b/Docs/Tasks.md @@ -609,6 +609,8 @@ Synchronous I/O in the async startup path violates the "Async Everything" design ### Task 21 — Consolidate start_daemon / wait_for_fail2ban duplicates +**Status:** Completed + **Severity:** Low **Where:** @@ -633,6 +635,8 @@ Any change to the daemon-start retry logic (timeouts, exception handling) must c ### Task 22 — Remove DEFAULT_BLOCKING_EXECUTOR dead code +**Status:** Completed + **Severity:** Low **Where:** diff --git a/backend/app/utils/async_utils.py b/backend/app/utils/async_utils.py index 6ff902b..11c1c83 100644 --- a/backend/app/utils/async_utils.py +++ b/backend/app/utils/async_utils.py @@ -7,6 +7,7 @@ running blocking callables without stalling the FastAPI event loop. from __future__ import annotations import asyncio +import functools from concurrent.futures import ThreadPoolExecutor from typing import Callable, ParamSpec, TypeVar @@ -37,6 +38,8 @@ async def run_blocking( The callable return value. """ loop = asyncio.get_running_loop() - if executor is None: - return await asyncio.to_thread(func, *args, **kwargs) - return await loop.run_in_executor(executor, func, *args, **kwargs) + executor = DEFAULT_BLOCKING_EXECUTOR if executor is None else executor + if kwargs: + func = functools.partial(func, *args, **kwargs) + return await loop.run_in_executor(executor, func) + return await loop.run_in_executor(executor, func, *args)