Add watchdog for missed launchd runs, fix backup path bug + retention

Watchdog (scripts/utils/watchdog.py, com.lotto.watchdog.plist, daily
21:30) checks whether the latest draw or the trained models are older
than the launchd schedule allows and sends a Telegram alert - this
would have caught the Aug 15 update run that silently never fired
(the Mac was presumably asleep; launchd does not retry missed
StartCalendarInterval jobs), instead of that only surfacing on the
next manual check.

Also fixes a real path bug in LottoAPIUpdater.create_backup(): since
self.data_file already points into data/, joining "data","backups"
wrote backups to data/data/backups/ instead of data/backups/ - 73
backups (6.3MB) had been piling up there undetected for months, with
data/data/ only ever gitignored rather than the root cause fixed.
Merges the misplaced backups into the correct location and adds
retention (keep last 30) so backups no longer grow unbounded; applied
the same retention to Eurojackpot's updater in a matching commit
there, which didn't have the path bug but had the same unbounded
growth (85 backups, 2.4MB).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
cbazzaandClaude Sonnet 5 committed 2026-09-12 10:02:04 +02:00
1 parent 427e704f3c
commit 612334dc1a
8 files changed
+178 -9899

No files matched your search

+30
View File
@@ -265,6 +265,36 @@ class LottoNotifier:
# TODO: Email-Versand implementieren wenn gewünscht
print("⚠️ Email-Benachrichtigung noch nicht implementiert")
def send_alert(self, message: str) -> bool:
"""Sendet eine formlose Warn-/Alarm-Nachricht (z.B. vom Watchdog)."""
if not self.config['telegram']['enabled']:
print("⚠️ Telegram nicht aktiviert in config/notifications.json")
return False
try:
bot_token = self.config['telegram']['bot_token']
chat_id = self.config['telegram']['chat_id']
url = f"https://api.telegram.org/bot{bot_token}/sendMessage"
data = {
"chat_id": chat_id,
"text": message,
"parse_mode": "Markdown"
}
response = requests.post(url, data=data, timeout=10)
if response.status_code == 200:
print("✅ Alarm-Benachrichtigung gesendet")
return True
else:
print(f"⚠️ Telegram-Fehler: {response.status_code}")
return False
except Exception as e:
print(f"⚠️ Alarm-Benachrichtigung fehlgeschlagen: {e}")
return False
def send_test_notification(self):
"""Sendet Test-Benachrichtigung."""
if self.config['telegram']['enabled']: