added healthcheck api and updated docker-compose to use it

This commit is contained in:
2026-08-11 19:00:11 +02:00
parent deba979cf2
commit 4ac1edfa31
6 changed files with 39 additions and 6 deletions
+20 -2
View File
@@ -2,9 +2,10 @@ import logging
logging.basicConfig(level=logging.INFO)
from flask import Flask, jsonify, render_template
import os, sys, time
from datetime import datetime
import os, sys
from src.anayzer import (
from src.analyzer import (
calculate_totals,
get_last_n_days,
get_stats,
@@ -45,6 +46,23 @@ def api_dashboard():
def api_sessions():
return jsonify(sessions_cache.get())
@app.route("/api/health")
def api_health():
is_alive = daemon.is_alive()
last_fetch = calendar.get_last_fetch_date()
if last_fetch:
min_since_last_fetch = round((datetime.now(tz=config.TIME_ZONE) - last_fetch).total_seconds() / 60)
is_up_to_date = min_since_last_fetch < 4 * config.REFETCH_MINUTES # four fetches failed -> bad health
else:
is_up_to_date = False
healthy = is_alive and is_up_to_date
return jsonify({
"status": "ok" if healthy else "degraded",
"daemon_alive": is_alive,
"last_fetch_success": str(last_fetch) if last_fetch else None
}), 200 if healthy else 503
# data
initial_fetch(calendar, sessions_cache)
daemon.run(calendar, sessions_cache)
+6
View File
@@ -7,3 +7,9 @@ services:
ports:
- "5000:5000"
restart: unless-stopped
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:5000/api/health"]
interval: 2m
timeout: 5s
retries: 3
start_period: 10s
@@ -23,7 +23,7 @@ def calculate_totals(sessions) -> dict:
def get_last_n_days(n: int, sessions) -> list[dict]:
days = []
today = datetime.now().date()
today = datetime.now(tz=config.TIME_ZONE).date()
for i in range(n):
day = today - timedelta(days=i)
days.append(
@@ -52,7 +52,7 @@ def get_total_month(sessions) -> int:
for session in sessions:
year_month = str(session["date"])[:7]
if year_month == datetime.now(config.TIME_ZONE).strftime("%Y-%m"):
if year_month == datetime.now(tz=config.TIME_ZONE).strftime("%Y-%m"):
total_min += session["minutes"]
return total_min
+3 -2
View File
@@ -23,7 +23,8 @@ REFETCH_MINUTES = os.environ.get("REFETCH_INTERVAL_MINUTES", "5")
if not REFETCH_MINUTES.isdigit():
logger.error("Invalid refetch interval")
sys.exit(1)
REFETCH_SECONDS = int(REFETCH_MINUTES) * 60
REFETCH_MINUTES = int(REFETCH_MINUTES)
REFETCH_SECONDS = REFETCH_MINUTES * 60
# get the date of the start of the semester were currently in
# or return None if no semesters were specified
@@ -33,7 +34,7 @@ def get_current_semester_start() -> date:
return None
# first check if one the dates was previously this year
today = datetime.now().date()
today = datetime.now(tz=TIME_ZONE).date()
found_start = None
try:
dates = [datetime.strptime(str(today.year)+"-"+date_str, "%Y-%m-%d").date() for date_str in SEMESTER_STARTS]
+3
View File
@@ -33,3 +33,6 @@ class BGFetchJob:
logger.info("Starting fetch job daemon")
self.thread = threading.Thread(target=background_fetch_job, args=(calendar, sessions_cache), daemon=True)
self.thread.start()
def is_alive(self):
return self.thread.is_alive()
+5
View File
@@ -24,6 +24,10 @@ class Calendar:
password=config.CALDAV_PASS,
)
self._calendar = self._client.calendar(url=config.CALDAV_URL)
self._last_succ_fetch: datetime = None
def get_last_fetch_date(self):
return self._last_succ_fetch
def fetch_events(self):
return self._calendar.events()
@@ -45,6 +49,7 @@ class Calendar:
})
logger.info(f"Fetched {len(event_list)} sessions from calDAV server")
self._last_succ_fetch = datetime.now(tz=config.TIME_ZONE)
return event_list
# grab only the sessions that fall into the current semester