Files
Dockhand_Backup/app/scheduler.py
2026-07-13 13:12:49 +02:00

56 lines
1.5 KiB
Python

"""APScheduler wrapper: runs the full backup on a cron schedule read from the
JSON config. The schedule is (re)applied whenever settings change.
"""
import logging
from apscheduler.schedulers.background import BackgroundScheduler
from apscheduler.triggers.cron import CronTrigger
from . import backup, store, timeutil
log = logging.getLogger("scheduler")
_scheduler = BackgroundScheduler()
_JOB_ID = "nightly-backup"
def _job():
log.info("scheduled backup starting")
backup.run_all()
log.info("scheduled backup finished")
def start():
if not _scheduler.running:
_scheduler.start()
reschedule()
def reschedule():
"""Apply the cron expression from config, or remove the job if disabled."""
config = store.load()
try:
_scheduler.remove_job(_JOB_ID)
except Exception: # noqa: BLE001 - job may not exist yet
pass
if not config.get("schedule_enabled", True):
log.info("schedule disabled")
return
cron = config.get("schedule", "0 3 * * *")
tz = timeutil.get_tz()
try:
trigger = CronTrigger.from_crontab(cron, timezone=tz)
except ValueError as exc:
log.error("invalid cron '%s': %s — schedule not applied", cron, exc)
return
_scheduler.add_job(_job, trigger, id=_JOB_ID, max_instances=1,
coalesce=True, replace_existing=True)
log.info("scheduled backup with cron '%s' (tz=%s)", cron, timeutil.tz_name())
def next_run_time():
job = _scheduler.get_job(_JOB_ID)
return job.next_run_time if job else None