Skip to content

Commit 3ce05ac

Browse files
opt: improvements on background app refresh and tmdb data fetch (#7)
2 parents f2d5e0c + b710ee5 commit 3ce05ac

File tree

5 files changed

+58
-24
lines changed

5 files changed

+58
-24
lines changed

app/core/app.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ async def lifespan(app: FastAPI):
3737
global catalog_updater
3838

3939
# Startup
40-
if settings.AUTO_UPDATE_CATALOGS and settings.CATALOG_REFRESH_INTERVAL_SECONDS > 0:
40+
if settings.AUTO_UPDATE_CATALOGS and settings.CATALOG_REFRESH_INTERVAL_SECONDS > 3600: # minimum 1 hour
4141
catalog_updater = BackgroundCatalogUpdater(interval_seconds=settings.CATALOG_REFRESH_INTERVAL_SECONDS)
4242
catalog_updater.start()
4343
logger.info(

app/services/catalog_updater.py

Lines changed: 19 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
import asyncio
22
from typing import Any
33

4+
from apscheduler.schedulers.asyncio import AsyncIOScheduler
5+
from apscheduler.triggers.interval import IntervalTrigger
46
from loguru import logger
57

68
from app.services.catalog import DynamicCatalogService
@@ -38,21 +40,28 @@ class BackgroundCatalogUpdater:
3840

3941
def __init__(self, interval_seconds: int) -> None:
4042
self.interval_seconds = max(60, interval_seconds)
41-
self._task: asyncio.Task | None = None
42-
self._stop_event = asyncio.Event()
43+
self.scheduler = AsyncIOScheduler()
4344

4445
def start(self) -> None:
45-
if self._task is not None:
46+
if self.scheduler.running:
4647
return
47-
self._stop_event.clear()
48-
self._task = asyncio.create_task(self._run())
48+
49+
logger.info(f"Starting background catalog updater. Interval: {self.interval_seconds}s")
50+
self.scheduler.add_job(
51+
self.refresh_all_tokens,
52+
trigger=IntervalTrigger(seconds=self.interval_seconds),
53+
id="catalog_refresh",
54+
replace_existing=True,
55+
max_instances=1, # Prevent new job from starting if previous one is still running
56+
coalesce=True, # If multiple runs are missed, only run once
57+
)
58+
self.scheduler.start()
4959

5060
async def stop(self) -> None:
51-
if self._task is None:
52-
return
53-
self._stop_event.set()
54-
await self._task
55-
self._task = None
61+
if self.scheduler.running:
62+
logger.info("Stopping background catalog updater...")
63+
self.scheduler.shutdown(wait=True) # Wait for running jobs to complete
64+
logger.info("Background catalog updater stopped.")
5665

5766
async def refresh_all_tokens(self) -> None:
5867
"""Refresh catalogs for all tokens concurrently with a semaphore."""
@@ -89,18 +98,6 @@ async def _update_safe(key: str, payload: dict[str, Any]) -> None:
8998
except Exception as exc:
9099
logger.error(f"Catalog refresh scan failed: {exc}", exc_info=True)
91100

92-
async def _run(self) -> None:
93-
logger.info(f"Background catalog updater started. Interval: {self.interval_seconds}s")
94-
try:
95-
while not self._stop_event.is_set():
96-
await self.refresh_all_tokens()
97-
try:
98-
await asyncio.wait_for(self._stop_event.wait(), timeout=self.interval_seconds)
99-
except TimeoutError:
100-
continue
101-
finally:
102-
logger.info("Background catalog updater stopped.")
103-
104101
@staticmethod
105102
def _has_credentials(payload: dict[str, Any]) -> bool:
106103
return bool(payload.get("authKey") or (payload.get("username") and payload.get("password")))

pyproject.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ description = "Add your description here"
55
readme = "README.md"
66
requires-python = ">=3.10"
77
dependencies = [
8+
"apscheduler>=3.11.1",
89
"async-lru>=2.0.5",
910
"cachetools>=6.2.2",
1011
"cryptography>=46.0.3",

requirements.txt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,4 +7,5 @@ loguru>=0.7.2
77
cachetools>=6.2.2
88
redis>=5.0.1
99
cryptography>=41.0.0
10-
async-lru>=2.0.4
10+
async-lru>=2.0.5
11+
apscheduler>=3.11.1

uv.lock

Lines changed: 35 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)