diff --git a/backend/app/services/garmin_connect_sync.py b/backend/app/services/garmin_connect_sync.py index cd460b3..5bb9239 100644 --- a/backend/app/services/garmin_connect_sync.py +++ b/backend/app/services/garmin_connect_sync.py @@ -253,6 +253,12 @@ def sync_wellness(garmin, user_id: int, since: Optional[datetime], db, if not row: continue + # psycopg2 treats Python lists as PostgreSQL arrays; serialize JSON columns + # explicitly so they arrive as a JSON string that the json/jsonb column accepts. + import json as _json + if "intraday_hr" in row and isinstance(row["intraday_hr"], list): + row["intraday_hr"] = _json.dumps(row["intraday_hr"]) + cols = list(row.keys()) col_sql = ", ".join(cols) val_sql = ", ".join(f":{c}" for c in cols) @@ -267,13 +273,17 @@ def sync_wellness(garmin, user_id: int, since: Optional[datetime], db, params = {"user_id": user_id, "day": day.isoformat()} params.update(row) - db.execute(text(f""" - INSERT INTO health_metrics (user_id, date, {col_sql}) - VALUES (:user_id, :day, {val_sql}) - ON CONFLICT (user_id, date) DO UPDATE SET {upd_sql} - """), params) - db.commit() - processed += 1 + try: + db.execute(text(f""" + INSERT INTO health_metrics (user_id, date, {col_sql}) + VALUES (:user_id, :day, {val_sql}) + ON CONFLICT (user_id, date) DO UPDATE SET {upd_sql} + """), params) + db.commit() + processed += 1 + except Exception as exc: + logger.warning("Failed to upsert health_metrics for %s: %s", day_str, exc) + db.rollback() return processed diff --git a/backend/app/workers/tasks.py b/backend/app/workers/tasks.py index c23b471..50b79f1 100644 --- a/backend/app/workers/tasks.py +++ b/backend/app/workers/tasks.py @@ -530,6 +530,7 @@ def sync_garmin_connect_user(user_id: int): ) except Exception as exc: errors.append(f"wellness: {exc}") + db.rollback() # recover session so the final status commit can succeed cfg.last_sync_at = datetime.now(timezone.utc) cfg.last_sync_status = (