Add healthcheck
This commit is contained in:
@@ -9,3 +9,7 @@ MYSQL_ROOT_PASSWORD=root_password
|
||||
COLLECT_INTERVAL_SECONDS=900
|
||||
APP_TIMEZONE=Europe/London
|
||||
FLASK_SECRET_KEY=replace-with-a-random-string
|
||||
|
||||
# Optional: healthcheck.io-style heartbeat URL
|
||||
# On success: GET <url> | On failure: POST <url>/fail
|
||||
HEALTHCHECK_URL=https://health.pattinson.org/ping/2009942a-9877-411e-89b4-3d17382c8286
|
||||
|
||||
+26
-1
@@ -2,6 +2,8 @@ from __future__ import annotations
|
||||
|
||||
import logging
|
||||
import time
|
||||
import urllib.error
|
||||
import urllib.request
|
||||
from datetime import datetime, timezone
|
||||
from typing import Any
|
||||
|
||||
@@ -73,6 +75,27 @@ def save_reading(device: Device, status: dict[str, Any]) -> None:
|
||||
)
|
||||
|
||||
|
||||
def _ping_healthcheck(success: bool, detail: str | None = None) -> None:
|
||||
url = config.healthcheck_url
|
||||
if not url:
|
||||
logger.debug("Healthcheck ping skipped: HEALTHCHECK_URL not configured")
|
||||
return
|
||||
try:
|
||||
if success:
|
||||
logger.debug("Pinging healthcheck (success): %s", url)
|
||||
urllib.request.urlopen(url, timeout=10) # noqa: S310
|
||||
logger.info("Healthcheck ping sent successfully")
|
||||
else:
|
||||
fail_url = f"{url}/fail"
|
||||
logger.debug("Pinging healthcheck (fail): %s — %s", fail_url, detail)
|
||||
payload = (detail or "").encode()
|
||||
req = urllib.request.Request(fail_url, data=payload, method="POST")
|
||||
urllib.request.urlopen(req, timeout=10) # noqa: S310
|
||||
logger.info("Healthcheck fail ping sent: %s", detail)
|
||||
except Exception as exc: # noqa: BLE001
|
||||
logger.warning("Healthcheck ping failed: %s", exc)
|
||||
|
||||
|
||||
def collect_once(client: SwitchBotClient) -> None:
|
||||
logger.info("Starting collection cycle")
|
||||
devices = sync_devices(client)
|
||||
@@ -106,8 +129,10 @@ def main() -> int:
|
||||
started = time.monotonic()
|
||||
try:
|
||||
collect_once(client)
|
||||
except Exception:
|
||||
_ping_healthcheck(True)
|
||||
except Exception as exc:
|
||||
logger.exception("Collector cycle failed")
|
||||
_ping_healthcheck(False, str(exc))
|
||||
elapsed = time.monotonic() - started
|
||||
time.sleep(max(1, interval - elapsed))
|
||||
|
||||
|
||||
@@ -20,6 +20,7 @@ class Config:
|
||||
collect_interval_seconds: int = int(os.getenv("COLLECT_INTERVAL_SECONDS", "900"))
|
||||
app_timezone: str = os.getenv("APP_TIMEZONE", "Europe/London")
|
||||
flask_secret_key: str = os.getenv("FLASK_SECRET_KEY", "dev-only-secret")
|
||||
healthcheck_url: str | None = os.getenv("HEALTHCHECK_URL")
|
||||
|
||||
|
||||
config = Config()
|
||||
|
||||
@@ -6,8 +6,7 @@
|
||||
<section class="hero">
|
||||
<div>
|
||||
<p class="eyebrow">Today so far</p>
|
||||
<h1>Temperature dashboard</h1>
|
||||
<p class="muted">Local timezone: {{ timezone }}. Collector interval: {{ collect_interval_seconds // 60 }} min.</p>
|
||||
<h1>Vet Temperatures</h1>
|
||||
</div>
|
||||
<a class="button" href="/reports">Make report</a>
|
||||
</section>
|
||||
|
||||
@@ -40,6 +40,7 @@ services:
|
||||
SWITCHBOT_SECRET: ${SWITCHBOT_SECRET:-}
|
||||
COLLECT_INTERVAL_SECONDS: ${COLLECT_INTERVAL_SECONDS:-900}
|
||||
APP_TIMEZONE: ${APP_TIMEZONE:-Europe/London}
|
||||
HEALTHCHECK_URL: ${HEALTHCHECK_URL:-}
|
||||
depends_on:
|
||||
db:
|
||||
condition: service_healthy
|
||||
|
||||
Reference in New Issue
Block a user