fix: add retry logic for garmin 429 rate limiting

This commit is contained in:
2026-04-19 17:10:11 +02:00
parent 8bf3ed9831
commit ee948aefd3
+116 -109
View File
@@ -1,118 +1,125 @@
apiVersion: v1
kind: ConfigMap
metadata:
name: garmin-sync-script
namespace: garmin
data:
sync.py: |
import os
import json
from datetime import date, timedelta
import psycopg2
from garminconnect import Garmin
import os
import time
from datetime import date, timedelta
import psycopg2
from garminconnect import Garmin
email = os.environ["GARMIN_EMAIL"]
password = os.environ["GARMIN_PASSWORD"]
db_url = os.environ["DATABASE_URL"]
email = os.environ["GARMIN_EMAIL"]
password = os.environ["GARMIN_PASSWORD"]
db_url = os.environ["DATABASE_URL"]
client = Garmin(email, password)
client.login()
# Retry-Login bei 429
client = Garmin(email, password)
for attempt in range(5):
try:
client.login()
print(f"Login erfolgreich (Versuch {attempt + 1})")
break
except Exception as e:
if "429" in str(e):
wait = 60 * (attempt + 1)
print(f"Rate limited (429), warte {wait}s...")
time.sleep(wait)
else:
raise
else:
raise Exception("Login nach 5 Versuchen fehlgeschlagen")
today = date.today()
start = today - timedelta(days=365 * 3)
today = date.today()
start = today - timedelta(days=365 * 3)
activities = client.get_activities_by_date(
start.isoformat(), today.isoformat()
activities = client.get_activities_by_date(
start.isoformat(), today.isoformat()
)
conn = psycopg2.connect(db_url)
cur = conn.cursor()
cur.execute("""
CREATE TABLE IF NOT EXISTS activities (
id BIGINT PRIMARY KEY,
name TEXT,
type TEXT,
start_time TIMESTAMP,
duration_seconds FLOAT,
distance_meters FLOAT,
avg_hr INTEGER,
max_hr INTEGER,
avg_pace FLOAT,
vo2max FLOAT,
calories FLOAT,
elevation_gain FLOAT,
steps INTEGER,
cadence FLOAT,
hr_zone_1 FLOAT,
hr_zone_2 FLOAT,
hr_zone_3 FLOAT,
hr_zone_4 FLOAT,
hr_zone_5 FLOAT
)
""")
conn = psycopg2.connect(db_url)
cur = conn.cursor()
cur.execute("""
ALTER TABLE activities
ADD COLUMN IF NOT EXISTS max_hr INTEGER,
ADD COLUMN IF NOT EXISTS vo2max FLOAT,
ADD COLUMN IF NOT EXISTS calories FLOAT,
ADD COLUMN IF NOT EXISTS elevation_gain FLOAT,
ADD COLUMN IF NOT EXISTS steps INTEGER,
ADD COLUMN IF NOT EXISTS cadence FLOAT,
ADD COLUMN IF NOT EXISTS hr_zone_1 FLOAT,
ADD COLUMN IF NOT EXISTS hr_zone_2 FLOAT,
ADD COLUMN IF NOT EXISTS hr_zone_3 FLOAT,
ADD COLUMN IF NOT EXISTS hr_zone_4 FLOAT,
ADD COLUMN IF NOT EXISTS hr_zone_5 FLOAT
""")
for a in activities:
cur.execute("""
CREATE TABLE IF NOT EXISTS activities (
id BIGINT PRIMARY KEY,
name TEXT,
type TEXT,
start_time TIMESTAMP,
duration_seconds FLOAT,
distance_meters FLOAT,
avg_hr INTEGER,
max_hr INTEGER,
avg_pace FLOAT,
vo2max FLOAT,
calories FLOAT,
elevation_gain FLOAT,
steps INTEGER,
cadence FLOAT,
hr_zone_1 FLOAT,
hr_zone_2 FLOAT,
hr_zone_3 FLOAT,
hr_zone_4 FLOAT,
hr_zone_5 FLOAT
)
""")
INSERT INTO activities
(id, name, type, start_time, duration_seconds, distance_meters,
avg_hr, max_hr, avg_pace, vo2max, calories, elevation_gain,
steps, cadence, hr_zone_1, hr_zone_2, hr_zone_3, hr_zone_4, hr_zone_5)
VALUES (%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s)
ON CONFLICT (id) DO UPDATE SET
duration_seconds = EXCLUDED.duration_seconds,
distance_meters = EXCLUDED.distance_meters,
avg_hr = EXCLUDED.avg_hr,
max_hr = EXCLUDED.max_hr,
avg_pace = EXCLUDED.avg_pace,
vo2max = EXCLUDED.vo2max,
calories = EXCLUDED.calories,
elevation_gain = EXCLUDED.elevation_gain,
steps = EXCLUDED.steps,
cadence = EXCLUDED.cadence,
hr_zone_1 = EXCLUDED.hr_zone_1,
hr_zone_2 = EXCLUDED.hr_zone_2,
hr_zone_3 = EXCLUDED.hr_zone_3,
hr_zone_4 = EXCLUDED.hr_zone_4,
hr_zone_5 = EXCLUDED.hr_zone_5
""", (
a.get("activityId"),
a.get("activityName"),
a.get("activityType", {}).get("typeKey"),
a.get("startTimeLocal"),
a.get("duration"),
a.get("distance"),
a.get("averageHR"),
a.get("maxHR"),
a.get("averageSpeed"),
a.get("vO2MaxValue"),
a.get("calories"),
a.get("elevationGain"),
a.get("steps"),
a.get("averageRunningCadenceInStepsPerMinute"),
a.get("hrTimeInZone_1"),
a.get("hrTimeInZone_2"),
a.get("hrTimeInZone_3"),
a.get("hrTimeInZone_4"),
a.get("hrTimeInZone_5"),
))
cur.execute("""
ALTER TABLE activities
ADD COLUMN IF NOT EXISTS max_hr INTEGER,
ADD COLUMN IF NOT EXISTS vo2max FLOAT,
ADD COLUMN IF NOT EXISTS calories FLOAT,
ADD COLUMN IF NOT EXISTS elevation_gain FLOAT,
ADD COLUMN IF NOT EXISTS steps INTEGER,
ADD COLUMN IF NOT EXISTS cadence FLOAT,
ADD COLUMN IF NOT EXISTS hr_zone_1 FLOAT,
ADD COLUMN IF NOT EXISTS hr_zone_2 FLOAT,
ADD COLUMN IF NOT EXISTS hr_zone_3 FLOAT,
ADD COLUMN IF NOT EXISTS hr_zone_4 FLOAT,
ADD COLUMN IF NOT EXISTS hr_zone_5 FLOAT
""")
for a in activities:
cur.execute("""
INSERT INTO activities
(id, name, type, start_time, duration_seconds, distance_meters,
avg_hr, max_hr, avg_pace, vo2max, calories, elevation_gain,
steps, cadence, hr_zone_1, hr_zone_2, hr_zone_3, hr_zone_4, hr_zone_5)
VALUES (%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s)
ON CONFLICT (id) DO UPDATE SET
duration_seconds = EXCLUDED.duration_seconds,
distance_meters = EXCLUDED.distance_meters,
avg_hr = EXCLUDED.avg_hr,
max_hr = EXCLUDED.max_hr,
avg_pace = EXCLUDED.avg_pace,
vo2max = EXCLUDED.vo2max,
calories = EXCLUDED.calories,
elevation_gain = EXCLUDED.elevation_gain,
steps = EXCLUDED.steps,
cadence = EXCLUDED.cadence,
hr_zone_1 = EXCLUDED.hr_zone_1,
hr_zone_2 = EXCLUDED.hr_zone_2,
hr_zone_3 = EXCLUDED.hr_zone_3,
hr_zone_4 = EXCLUDED.hr_zone_4,
hr_zone_5 = EXCLUDED.hr_zone_5
""", (
a.get("activityId"),
a.get("activityName"),
a.get("activityType", {}).get("typeKey"),
a.get("startTimeLocal"),
a.get("duration"),
a.get("distance"),
a.get("averageHR"),
a.get("maxHR"),
a.get("averageSpeed"),
a.get("vO2MaxValue"),
a.get("calories"),
a.get("elevationGain"),
a.get("steps"),
a.get("averageRunningCadenceInStepsPerMinute"),
a.get("hrTimeInZone_1"),
a.get("hrTimeInZone_2"),
a.get("hrTimeInZone_3"),
a.get("hrTimeInZone_4"),
a.get("hrTimeInZone_5"),
))
conn.commit()
cur.close()
conn.close()
print(f"Synced {len(activities)} activities")
conn.commit()
cur.close()
conn.close()
print(f"Synced {len(activities)} activities")