Bring back cleanup thread

This commit is contained in:
Ian Renton
2026-08-13 07:07:15 +01:00
parent 6a4b0bed95
commit bab14bd7ac
13 changed files with 113 additions and 16 deletions
+71
View File
@@ -0,0 +1,71 @@
import logging
from datetime import datetime
from threading import Event, Thread
import pytz
from core.data_store import DATA_STORE
class CleanupTimer:
"""Provides a timed cleanup of the spot list."""
def __init__(self):
"""Constructor"""
self._cleanup_interval = None
self.last_cleanup_time = datetime.min.replace(tzinfo=pytz.UTC)
self.status = "Starting"
self._thread = None
self._stop_event = Event()
def setup(self, cleanup_interval):
self._cleanup_interval = cleanup_interval
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:
for i in list(DATA_STORE.spots.iterkeys()):
try:
spot = DATA_STORE.spots[i]
if spot.expired():
DATA_STORE.spots.delete(i)
except KeyError:
# Must have already been deleted, OK with that
pass
for i in list(DATA_STORE.alerts.iterkeys()):
try:
alert = DATA_STORE.alerts[i]
if alert.expired():
DATA_STORE.alerts.delete(i)
except KeyError:
# Must have already been deleted, OK with that
pass
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)
# Global object
CLEANUP_TIMER = CleanupTimer()
+4
View File
@@ -5,6 +5,7 @@ from threading import Thread, Event
import psutil
import pytz
from core.cleanup import CLEANUP_TIMER
from core.config import SERVER_OWNER_CALLSIGN
from core.constants import SOFTWARE_VERSION
from core.data_providers import DATA_PROVIDERS
@@ -88,6 +89,9 @@ class StatusReporter:
tzinfo=pytz.UTC).timestamp() if p.last_update_time.year > 2000 else 0,
"lookup_count": p.lookup_count},
DATA_PROVIDERS.callsign_data_providers))
DATA_STORE.status_data["cleanup"] = {"status": CLEANUP_TIMER.status,
"last_ran": CLEANUP_TIMER.last_cleanup_time.replace(
tzinfo=pytz.UTC).timestamp() if CLEANUP_TIMER.last_cleanup_time else 0}
DATA_STORE.status_data["webserver"] = {"status": WEB_SERVER.web_server_metrics["status"],
"last_api_access": WEB_SERVER.web_server_metrics[
"last_api_access_time"].replace(
+4
View File
@@ -4,6 +4,7 @@ import os
import signal
import sys
from core.cleanup import CLEANUP_TIMER
from core.config import SERVER_OWNER_CALLSIGN, LOG_LEVEL
from core.constants import SOFTWARE_VERSION
from core.data_providers import DATA_PROVIDERS
@@ -22,6 +23,7 @@ def shutdown(_signum=None, _frame=None):
logging.info("Stopping program...")
WEB_SERVER.stop()
DATA_PROVIDERS.stop()
CLEANUP_TIMER.stop()
DATA_STORE.close()
os._exit(0)
@@ -47,6 +49,8 @@ if __name__ == '__main__':
# Set up data store
DATA_STORE.setup()
CLEANUP_TIMER.setup(cleanup_interval=60)
CLEANUP_TIMER.start()
# Set up and start data providers
DATA_PROVIDERS.setup()
+11 -1
View File
@@ -18,7 +18,6 @@ info:
### 2.0
* **Breaking change:** The "add spot" API has changed to enable future support for upstream submission to the spotting services associated with various SIGs. Instead of just posting the spot object itself as the JSON content of the POST, this has moved into a `spot` object within the structure. A new `handling` object alongside it contains the `submit_upstream`, `upstream_provider`, `upstream_credentials`, and `captcha_token` fields which control the server handling of the spot.
* **Breaking change:** Removed `cleanup` from `/status` response
* **Breaking change:** In the `/options` response, renamed `spot_sources` and `alert_sources` to `spot_providers` and `alert_providers`
* **Breaking change:** A user's QRZ.com and HamQTH credentials are now supplied as request headers (`X-QRZ-Username`, `X-QRZ-Password`, `X-QRZ-Session-Key`, `X-HamQTH-Username`, `X-HamQTH-Password`, `X-HamQTH-Session-ID`) rather than query parameters, to keep credentials out of server logs.
* **Breaking change:** "WAB/WAI GRID" as a location source has been renamed to just "GRID", and also applies to Tiles on the Air spots and grid references from cluster spot comments.
@@ -1951,6 +1950,17 @@ components:
type: integer
description: Number of alerts currently in the system.
example: 123
"cleanup":
type: object
properties:
status:
type: string
description: The status of the cleanup thread
example: OK
last_ran:
type: number
description: The last time the cleanup operation ran, UTC seconds since UNIX epoch.
example: 1759579508
"webserver":
type: object
properties:
+3
View File
@@ -12,6 +12,9 @@ function loadStatus() {
$("#web-server-last-api").text(moment.unix(jsonData["webserver"]["last_api_access"]).utc().fromNow());
$("#web-server-last-page").text(moment.unix(jsonData["webserver"]["last_page_access"]).utc().fromNow());
$("#cleanup-status").text(jsonData["cleanup"]["status"]);
$("#cleanup-last-ran").text((jsonData["cleanup"]["last_ran"] > 0) ? moment.unix(jsonData["cleanup"]["last_ran"]).utc().fromNow() : "N/A");
jsonData["spot_providers"].forEach(p => {
$("#spot_providers-status-container").append(`
<div class="row row-cols-1 row-cols-md-4 g-4 mb-4 mb-md-2">
+1 -1
View File
@@ -76,7 +76,7 @@
</div>
<script src="/static/js/add-spot.js?v=1786599927"></script>
<script src="/static/js/add-spot.js?v=1786601235"></script>
<script>$(document).ready(function () {
$("#nav-link-add-spot").addClass("active");
}); <!-- highlight active page in nav --></script>
+1 -1
View File
@@ -82,7 +82,7 @@
</div>
<script src="/static/js/alerts.js?v=1786599927"></script>
<script src="/static/js/alerts.js?v=1786601235"></script>
<script>$(document).ready(function () {
$("#nav-link-alerts").addClass("active");
}); <!-- highlight active page in nav --></script>
+2 -2
View File
@@ -79,8 +79,8 @@
</div>
<script src="/static/js/spotsbandsandmap.js?v=1786599927"></script>
<script src="/static/js/bands.js?v=1786599927"></script>
<script src="/static/js/spotsbandsandmap.js?v=1786601235"></script>
<script src="/static/js/bands.js?v=1786601235"></script>
<script>$(document).ready(function () {
$("#nav-link-bands").addClass("active");
}); <!-- highlight active page in nav --></script>
+5 -5
View File
@@ -1,6 +1,6 @@
{% extends "skeleton.html" %}
{% block head_extra %}
<link rel="stylesheet" href="/static/css/style.css?v=1786599927" type="text/css">
<link rel="stylesheet" href="/static/css/style.css?v=1786601235" type="text/css">
<link href="/static/vendor/css/bootstrap-5.3.8.min.css" rel="stylesheet">
<link href="/static/vendor/css/fontawesome-6.7.2.min.css" rel="stylesheet">
<link href="/static/vendor/css/solid-6.7.2.min.css" rel="stylesheet">
@@ -10,10 +10,10 @@
<script src="/static/vendor/js/bootstrap-5.3.8.bundle.min.js"></script>
<script src="/static/vendor/js/tinycolor2-1.6.0.min.js"></script>
<script src="/static/js/utils.js?v=1786599927"></script>
<script src="/static/js/ui-ham.js?v=1786599927"></script>
<script src="/static/js/geo.js?v=1786599927"></script>
<script src="/static/js/common.js?v=1786599927"></script>
<script src="/static/js/utils.js?v=1786601235"></script>
<script src="/static/js/ui-ham.js?v=1786601235"></script>
<script src="/static/js/geo.js?v=1786601235"></script>
<script src="/static/js/common.js?v=1786601235"></script>
{% end %}
{% block body %}
<div class="container">
+1 -1
View File
@@ -284,7 +284,7 @@
</div>
<script src="/static/vendor/js/chart-4.4.9.umd.min.js"></script>
<script src="/static/js/conditions.js?v=1786599927"></script>
<script src="/static/js/conditions.js?v=1786601235"></script>
<script>$(document).ready(function () {
$("#nav-link-conditions").addClass("active");
}); <!-- highlight active page in nav --></script>
+2 -2
View File
@@ -112,8 +112,8 @@
<script src="/static/vendor/js/leaflet-cqzones.js"></script>
<script src="/static/vendor/js/leaflet-workedallbritainireland.js" type="module"></script>
<script src="/static/js/spotsbandsandmap.js?v=1786599927"></script>
<script src="/static/js/map.js?v=1786599927"></script>
<script src="/static/js/spotsbandsandmap.js?v=1786601235"></script>
<script src="/static/js/map.js?v=1786601235"></script>
<script>$(document).ready(function () {
$("#nav-link-map").addClass("active");
}); <!-- highlight active page in nav --></script>
+2 -2
View File
@@ -118,8 +118,8 @@
</div>
<script src="/static/js/spotsbandsandmap.js?v=1786599927"></script>
<script src="/static/js/spots.js?v=1786599927"></script>
<script src="/static/js/spotsbandsandmap.js?v=1786601235"></script>
<script src="/static/js/spots.js?v=1786601235"></script>
<script>$(document).ready(function () {
$("#nav-link-spots").addClass("active");
}); <!-- highlight active page in nav --></script>
+6 -1
View File
@@ -24,6 +24,11 @@
<div class="col">Last API call: <span id="web-server-last-api"></span></div>
<div class="col">Last page req: <span id="web-server-last-page"></span></div>
</div>
<div class="row row-cols-1 row-cols-md-4 g-4 mb-2">
<div class="col"><strong>Cleanup Service</strong></div>
<div class="col">Status: <span id="cleanup-status"></span></div>
<div class="col">Last ran: <span id="cleanup-last-ran"></span></div>
</div>
</div>
</div>
@@ -81,7 +86,7 @@
</div>
</div>
<script src="/static/js/status.js?v=1786599927"></script>
<script src="/static/js/status.js?v=1786601235"></script>
<script>
$(document).ready(function () {
$("#nav-link-status").addClass("active");