Replace asyncio.to_thread with ThreadPoolExecutor.run_in_executor

- Add ThreadPoolExecutor with 3 max workers to SeriesApp
- Replace all asyncio.to_thread calls with loop.run_in_executor
- Add shutdown() method to properly cleanup executor
- Integrate SeriesApp.shutdown() into FastAPI shutdown sequence
- Ensures proper resource cleanup on Ctrl+C (SIGINT/SIGTERM)
This commit is contained in:
2026-01-03 21:04:52 +01:00
parent b1726968e5
commit ab7d78261e
6 changed files with 102 additions and 329 deletions

View File

@@ -197,7 +197,17 @@ async def lifespan(_application: FastAPI):
except Exception as e: # pylint: disable=broad-exception-caught
logger.error("Error stopping download service: %s", e, exc_info=True)
# 3. Cleanup progress service
# 3. Shutdown SeriesApp and cleanup thread pool
try:
from src.server.utils.dependencies import _series_app
if _series_app is not None:
logger.info("Shutting down SeriesApp thread pool...")
_series_app.shutdown()
logger.info("SeriesApp shutdown complete")
except Exception as e: # pylint: disable=broad-exception-caught
logger.error("Error during SeriesApp shutdown: %s", e, exc_info=True)
# 4. Cleanup progress service
try:
progress_service = get_progress_service()
logger.info("Cleaning up progress service...")
@@ -205,9 +215,11 @@ async def lifespan(_application: FastAPI):
progress_service._active_progress.clear()
logger.info("Progress service cleanup complete")
except Exception as e: # pylint: disable=broad-exception-caught
logger.error("Error cleaning up progress service: %s", e, exc_info=True)
logger.error(
"Error cleaning up progress service: %s", e, exc_info=True
)
# 4. Close database connections with WAL checkpoint
# 5. Close database connections with WAL checkpoint
try:
from src.server.database.connection import close_db
logger.info("Closing database connections...")