Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 26 additions & 1 deletion backend/app/services/scheduler.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
"""APScheduler integration — weekly Sunday digest dispatch."""

from __future__ import annotations

import logging
from datetime import UTC, datetime

Expand All @@ -9,11 +10,13 @@
from ..config import settings
from ..database import SessionLocal
from ..models import DigestSubscription
from ..routers.collaboration import manager as collaboration_manager
from .email_service import compute_subscriber_stats, send_digest

log = logging.getLogger(__name__)
scheduler = BackgroundScheduler(daemon=True)
JOB_ID = "weekly_digest"
PURGE_ROOMS_JOB_ID = "purge_empty_collab_rooms"


def _send_weekly_digests() -> None:
Expand Down Expand Up @@ -54,6 +57,18 @@ def _send_weekly_digests() -> None:
db.close()


def _purge_empty_collab_rooms() -> None:
"""Remove collaboration rooms left with no active sockets."""
empty = [
sid for sid, room in list(collaboration_manager.rooms.items())
if not room.sockets
]
for sid in empty:
collaboration_manager.rooms.pop(sid, None)
if empty:
log.info("Purged %d empty collaboration room(s)", len(empty))


def start_scheduler() -> None:
"""Start the background scheduler with the weekly digest job."""
if scheduler.get_job(JOB_ID):
Expand All @@ -69,11 +84,21 @@ def start_scheduler() -> None:
id=JOB_ID,
replace_existing=True,
)

log.info("Starting empty collaboration room purge job (every 30 min)")
scheduler.add_job(
_purge_empty_collab_rooms,
trigger="interval",
minutes=30,
id=PURGE_ROOMS_JOB_ID,
replace_existing=True,
)

scheduler.start()


def stop_scheduler() -> None:
"""Shut down the background scheduler."""
if scheduler.running:
log.info("Stopping weekly digest scheduler")
scheduler.shutdown(wait=False)
scheduler.shutdown(wait=False)
Loading