From a6ffcf95772be76e354a792a19b04ad5c3f93f98 Mon Sep 17 00:00:00 2001 From: npeter83 Date: Sat, 11 Jul 2026 19:44:53 +0200 Subject: [PATCH] chore(scheduler): dedup token-user query + drop pointless rss lambda MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Extract runner.token_users(db): the "all users with a stored refresh token" query was spelled 3× (get_service_user, run_subscription_resync, sync_all_playlists). get_service_user now reuses it ([0]); sync_all_playlists imports it from runner (no cycle — runner doesn't import playlists); the now- unused OAuthToken import is dropped there. - scheduler.py: _job("rss_poll", lambda db: run_rss_poll(db)) → _job("rss_poll", run_rss_poll) — the lambda was dead indirection; all sibling jobs pass the callable directly and _job calls fn(db). Behavior-neutral. ruff clean, localdev boots, re-review clean. --- backend/app/scheduler.py | 2 +- backend/app/sync/playlists.py | 11 +++-------- backend/app/sync/runner.py | 24 ++++++++++-------------- 3 files changed, 14 insertions(+), 23 deletions(-) diff --git a/backend/app/scheduler.py b/backend/app/scheduler.py index 5e001b6..e5e97b2 100644 --- a/backend/app/scheduler.py +++ b/backend/app/scheduler.py @@ -209,7 +209,7 @@ def scheduler_snapshot() -> dict: def _rss_job() -> None: - _job("rss_poll", lambda db: run_rss_poll(db)) + _job("rss_poll", run_rss_poll) def _enrich_job() -> None: diff --git a/backend/app/sync/playlists.py b/backend/app/sync/playlists.py index ca82b27..9634a99 100644 --- a/backend/app/sync/playlists.py +++ b/backend/app/sync/playlists.py @@ -14,7 +14,8 @@ from sqlalchemy.orm import Session from app import progress, quota from app.auth import has_read_scope -from app.models import Channel, OAuthToken, Playlist, PlaylistItem, User, Video +from app.models import Channel, Playlist, PlaylistItem, User, Video +from app.sync.runner import token_users from app.sync.videos import apply_video_details, parse_dt from app.youtube.client import YouTubeClient, YouTubeError @@ -370,13 +371,7 @@ def repull_playlist(db: Session, user: User, pl: Playlist) -> dict: def sync_all_playlists(db: Session) -> dict: """Scheduler entry point: mirror playlists for every user with a read scope + token.""" - users = ( - db.execute( - select(User).join(OAuthToken).where(OAuthToken.refresh_token_enc.is_not(None)) - ) - .scalars() - .all() - ) + users = token_users(db) total = 0 for i, user in enumerate(users, 1): if not has_read_scope(user): diff --git a/backend/app/sync/runner.py b/backend/app/sync/runner.py index 7239a5d..e325a50 100644 --- a/backend/app/sync/runner.py +++ b/backend/app/sync/runner.py @@ -31,19 +31,23 @@ from app.youtube.rss import fetch_channel_feed RSS_POLL_WORKERS = 16 -def get_service_user(db: Session) -> User | None: - return ( +def token_users(db: Session) -> list[User]: + """Every user with a stored YouTube refresh token (the read-scope service accounts), by id.""" + return list( db.execute( select(User) .join(OAuthToken) .where(OAuthToken.refresh_token_enc.is_not(None)) .order_by(User.id) - ) - .scalars() - .first() + ).scalars() ) +def get_service_user(db: Session) -> User | None: + users = token_users(db) + return users[0] if users else None + + def run_rss_poll(db: Session, channels: list[Channel] | None = None) -> int: if channels is None: channels = db.execute(select(Channel)).scalars().all() @@ -102,15 +106,7 @@ def run_shorts(db: Session) -> dict: def run_subscription_resync(db: Session) -> dict: """Re-import every user's subscriptions so unsubscribes and new subscriptions on YouTube are reflected automatically.""" - users = ( - db.execute( - select(User) - .join(OAuthToken) - .where(OAuthToken.refresh_token_enc.is_not(None)) - ) - .scalars() - .all() - ) + users = token_users(db) for i, user in enumerate(users, 1): try: import_subscriptions(db, user)