56 lines
1.5 KiB
Python
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
|