import logging from datetime import datetime from threading import Timer, Event, Thread from time import sleep 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.cleanup_timer = None self.last_cleanup_time = datetime.min.replace(tzinfo=pytz.UTC) self.status = "Starting" 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 id in list(self.spots.iterkeys()): try: spot = self.spots[id] if spot.expired(): self.spots.delete(id) except KeyError: # Must have already been deleted, OK with that pass for id in list(self.alerts.iterkeys()): try: alert = self.alerts[id] if alert.expired(): self.alerts.delete(id) 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 as e: self.status = "Error" logging.exception("Exception in Cleanup thread") self._stop_event.wait(timeout=1)