From 94fcd5f685f19ec426b798aa30775dfb7b7e3f53 Mon Sep 17 00:00:00 2001 From: Stefan Koelle Date: Fri, 7 Aug 2026 20:56:12 +0200 Subject: [PATCH] sync healthcheck feature --- config/accounts.json.example | 6 ++++-- src/config.py | 6 ++++-- src/sync.py | 15 +++++++++++++++ 3 files changed, 23 insertions(+), 4 deletions(-) diff --git a/config/accounts.json.example b/config/accounts.json.example index 5293c90..1d663ff 100644 --- a/config/accounts.json.example +++ b/config/accounts.json.example @@ -10,14 +10,16 @@ {"label": "LinkedIn", "url": "https://www.linkedin.com/search/results/all/?keywords=[fullname]"}, {"label": "Google Maps Home", "url": "https://www.google.com/maps?q=[homecity]"}, {"label": "Google Maps Work", "url": "https://www.google.com/maps?q=[workcity]"} - ] + ], + "healthcheck_url": "https://healthchecks.example.de/ping/abc123" }, { "name": "partner", "apple_email": "partner@icloud.com", "apple_app_password": "yyyy-yyyy-yyyy-yyyy", "authelia_user": "partner.user", - "custom_links": [] + "custom_links": [], + "healthcheck_url": "" } ], "admins": [ diff --git a/src/config.py b/src/config.py index 57f32a3..53f238b 100644 --- a/src/config.py +++ b/src/config.py @@ -13,12 +13,13 @@ ICLOUD_BASE_URL = "https://contacts.icloud.com/" class Account: def __init__(self, name: str, apple_email: str, apple_app_password: str, authelia_user: str | None, - custom_links: list[dict] | None = None): + custom_links: list[dict] | None = None, healthcheck_url: str = ""): self.name = name self.apple_email = apple_email self.apple_app_password = apple_app_password self.authelia_user = authelia_user self.custom_links = custom_links or [] + self.healthcheck_url = healthcheck_url class Config: @@ -101,7 +102,8 @@ class Config: raise RuntimeError(f"Account-Name '{name}' ist nicht eindeutig") seen_names.add(name) custom_links = entry.get("custom_links", []) - accounts.append(Account(name, email, pwd, authelia_user, custom_links)) + healthcheck_url = entry.get("healthcheck_url", "") + accounts.append(Account(name, email, pwd, authelia_user, custom_links, healthcheck_url)) return accounts @classmethod diff --git a/src/sync.py b/src/sync.py index 016817a..c820b07 100644 --- a/src/sync.py +++ b/src/sync.py @@ -9,6 +9,8 @@ vollständiger Re-Sync.""" import logging import sys +import requests + import db from carddav_client import ICLOUD_BASE_URL, CardDAVClient, SyncTokenInvalid from config import Config @@ -18,6 +20,16 @@ logging.basicConfig(level=Config.LOG_LEVEL, format="%(asctime)s [%(levelname)s] logger = logging.getLogger("sync") +def _call_healthcheck(account): + if not account.healthcheck_url: + return + try: + resp = requests.get(account.healthcheck_url, timeout=10) + logger.info("[%s] Healthcheck OK (%d)", account.name, resp.status_code) + except Exception as exc: + logger.warning("[%s] Healthcheck fehlgeschlagen: %s", account.name, exc) + + def _classify_vcards(raw_vcards, raw_etags, account_name): contacts, groups = [], [] for v, etag in zip(raw_vcards, raw_etags): @@ -56,6 +68,7 @@ def sync_account(conn, account, href_to_uid_cache: dict): db.save_sync_token(conn, account.name, new_token) db.finish_sync_run(conn, run_id, "success", upserted=len(contacts), deleted=0) logger.info("[%s] Initialer Sync abgeschlossen: %d Kontakte, %d Gruppen", account.name, len(contacts), len(groups)) + _call_healthcheck(account) return try: @@ -72,6 +85,7 @@ def sync_account(conn, account, href_to_uid_cache: dict): db.save_sync_token(conn, account.name, new_token) db.finish_sync_run(conn, run_id, "success", upserted=len(contacts), deleted=0) logger.info("[%s] Re-Sync abgeschlossen: %d Kontakte, %d Gruppen", account.name, len(contacts), len(groups)) + _call_healthcheck(account) return contacts, groups = _classify_vcards(changed_vcards, etags, account.name) @@ -97,6 +111,7 @@ def sync_account(conn, account, href_to_uid_cache: dict): "[%s] Delta-Sync abgeschlossen: %d geändert/neu, %d gelöscht (%d Gruppen geändert)", account.name, len(contacts), len(deleted_uids), len(groups), ) + _call_healthcheck(account) except Exception as exc: logger.exception("[%s] Sync-Lauf %s fehlgeschlagen", account.name, run_id) print(f"SYNC-FEHLER [{account.name}]: {exc}", file=sys.stderr, flush=True)