import logging from datetime import datetime from threading import Event, Thread import pytz class CleanupTimer: """Provides a timed cleanup of the spot list.""" def __init__(self, spots, alerts, web_server, cleanup_interval): """Constructor""" self._spots = spots self._alerts = alerts self._web_server = web_server self._cleanup_interval = cleanup_interval self.last_cleanup_time = datetime.min.replace(tzinfo=pytz.UTC) self.status = "Starting" self._thread = None self._stop_event = Event() def start(self): """Start the cleanup timer""" self._thread = Thread(target=self._run, daemon=True) self._thread.start() def stop(self): """Stop any threads and prepare for application shutdown""" self._stop_event.set() def _run(self): while not self._stop_event.wait(timeout=self._cleanup_interval): self._cleanup() def _cleanup(self): """Perform cleanup and reschedule next timer""" try: # Perform cleanup via letting the data expire self._spots.expire() self._alerts.expire() # Explicitly clean up any spots and alerts that have expired for i in list(self._spots.iterkeys()): try: spot = self._spots[i] if spot.expired(): self._spots.delete(i) except KeyError: # Must have already been deleted, OK with that pass for i in list(self._alerts.iterkeys()): try: alert = self._alerts[i] if alert.expired(): self._alerts.delete(i) except KeyError: # Must have already been deleted, OK with that pass # Clean up web server SSE spot/alert queues self._web_server.clean_up_sse_queues() self.status = "OK" self.last_cleanup_time = datetime.now(pytz.UTC) except Exception: self.status = "Error" logging.exception("Exception in Cleanup thread") self._stop_event.wait(timeout=1)