Files
homelable/backend/app/core/scheduler.py
T
Pouzor 974e782057 fix: resolve all 64 mypy errors across backend
- Add dict[str, Any] / list[Any] type params throughout (fingerprint, models, schemas, scanner, status_checker)
- Add return type annotations to all route functions (nodes, edges, canvas, scan, auth, status, main)
- Fix no-any-return in security.py: cast pwd/jwt results to bool/str explicitly
- Fix canvas.py: use model_validate() for NodeResponse/EdgeResponse, rename db_node/db_edge upsert vars
- Fix scheduler.py: rename 'result' → 'check_result' to avoid type collision
- Fix get_db() return type: AsyncGenerator[AsyncSession, None]
- Add types-PyYAML for yaml import stubs
- Fix scanner.py: remove unnecessary type: ignore comment (nmap has stubs)
- Fix scan.py: wrap scalars().all() with list() for Sequence→list compatibility
2026-03-07 15:48:41 +01:00

67 lines
2.2 KiB
Python

"""APScheduler setup for background scan and status check jobs."""
import logging
from datetime import UTC, datetime
import yaml
from apscheduler.schedulers.asyncio import AsyncIOScheduler
from sqlalchemy import select
from app.core.config import settings
from app.db.database import AsyncSessionLocal
from app.db.models import Node
from app.services.status_checker import check_node
logger = logging.getLogger(__name__)
scheduler = AsyncIOScheduler()
async def _run_status_checks() -> None:
"""Check all nodes and broadcast results via WebSocket."""
from app.api.routes.status import broadcast_status # avoid circular import
async with AsyncSessionLocal() as db:
result = await db.execute(select(Node))
nodes = result.scalars().all()
for node in nodes:
if not node.check_method:
continue
try:
check_result = await check_node(node.check_method, node.check_target, node.ip)
async with AsyncSessionLocal() as db:
n = await db.get(Node, node.id)
if n:
n.status = check_result["status"]
n.response_time_ms = check_result["response_time_ms"]
n.last_seen = datetime.now(UTC) if check_result["status"] == "online" else n.last_seen
await db.commit()
await broadcast_status(
node_id=node.id,
status=check_result["status"],
checked_at=datetime.now(UTC).isoformat(),
response_time_ms=check_result["response_time_ms"],
)
except Exception as exc:
logger.error("Status check failed for node %s: %s", node.id, exc)
def _load_interval() -> int:
try:
with open(settings.config_path) as f:
cfg = yaml.safe_load(f)
return int(cfg.get("status_checker", {}).get("interval_seconds", 60))
except Exception:
return 60
def start_scheduler() -> None:
interval = _load_interval()
scheduler.add_job(_run_status_checks, "interval", seconds=interval, id="status_checks")
scheduler.start()
logger.info("Scheduler started — status checks every %ds", interval)
def stop_scheduler() -> None:
scheduler.shutdown(wait=False)