generated from nathanwoodburn/python-webserver-template
58 lines
1.9 KiB
Python
58 lines
1.9 KiB
Python
import fcntl
|
|
import logging
|
|
import os
|
|
import threading
|
|
|
|
from collectors import InventoryCollectorOrchestrator
|
|
from config import AppConfig
|
|
|
|
LOGGER = logging.getLogger(__name__)
|
|
|
|
|
|
class CollectionScheduler:
|
|
def __init__(self, config: AppConfig, orchestrator: InventoryCollectorOrchestrator):
|
|
self.config = config
|
|
self.orchestrator = orchestrator
|
|
self._stop_event = threading.Event()
|
|
self._thread: threading.Thread | None = None
|
|
self._leader_file = None
|
|
|
|
def start(self) -> bool:
|
|
if not self.config.scheduler_enabled:
|
|
LOGGER.info("Scheduler disabled via config")
|
|
return False
|
|
|
|
leader_file = open("/tmp/inventory-scheduler.lock", "w", encoding="utf-8")
|
|
try:
|
|
fcntl.flock(leader_file.fileno(), fcntl.LOCK_EX | fcntl.LOCK_NB)
|
|
except OSError:
|
|
leader_file.close()
|
|
LOGGER.info("Another worker owns scheduler lock")
|
|
return False
|
|
|
|
self._leader_file = leader_file
|
|
|
|
self._thread = threading.Thread(target=self._run_loop, name="inventory-scheduler", daemon=True)
|
|
self._thread.start()
|
|
LOGGER.info("Scheduler started with %s second interval", self.config.poll_interval_seconds)
|
|
return True
|
|
|
|
def _run_loop(self) -> None:
|
|
while not self._stop_event.is_set():
|
|
self.orchestrator.collect_once()
|
|
self._stop_event.wait(self.config.poll_interval_seconds)
|
|
|
|
def shutdown(self) -> None:
|
|
self._stop_event.set()
|
|
if self._thread and self._thread.is_alive():
|
|
self._thread.join(timeout=1.0)
|
|
if self._leader_file:
|
|
fcntl.flock(self._leader_file.fileno(), fcntl.LOCK_UN)
|
|
self._leader_file.close()
|
|
self._leader_file = None
|
|
|
|
|
|
def should_autostart_scheduler() -> bool:
|
|
# Do not auto-start on Flask's reloader child process.
|
|
return os.getenv("WERKZEUG_RUN_MAIN", "true") != "false"
|