Fix wellness sync crash: serialize intraday_hr as JSON string for psycopg2
psycopg2 treats Python lists as PostgreSQL arrays (bigint[]) rather than JSON, causing a DatatypeMismatch error on the json/jsonb column. Serializing with json.dumps() before the raw SQL INSERT fixes the type error. Also wrap per-day INSERT in try/except+rollback so one bad day doesn't abort the entire session, and add db.rollback() in tasks.py after sync_wellness failure so the final status-update commit can always succeed. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -253,6 +253,12 @@ def sync_wellness(garmin, user_id: int, since: Optional[datetime], db,
|
|||||||
if not row:
|
if not row:
|
||||||
continue
|
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())
|
cols = list(row.keys())
|
||||||
col_sql = ", ".join(cols)
|
col_sql = ", ".join(cols)
|
||||||
val_sql = ", ".join(f":{c}" for c in 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 = {"user_id": user_id, "day": day.isoformat()}
|
||||||
params.update(row)
|
params.update(row)
|
||||||
|
|
||||||
db.execute(text(f"""
|
try:
|
||||||
INSERT INTO health_metrics (user_id, date, {col_sql})
|
db.execute(text(f"""
|
||||||
VALUES (:user_id, :day, {val_sql})
|
INSERT INTO health_metrics (user_id, date, {col_sql})
|
||||||
ON CONFLICT (user_id, date) DO UPDATE SET {upd_sql}
|
VALUES (:user_id, :day, {val_sql})
|
||||||
"""), params)
|
ON CONFLICT (user_id, date) DO UPDATE SET {upd_sql}
|
||||||
db.commit()
|
"""), params)
|
||||||
processed += 1
|
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
|
return processed
|
||||||
|
|
||||||
|
|||||||
@@ -530,6 +530,7 @@ def sync_garmin_connect_user(user_id: int):
|
|||||||
)
|
)
|
||||||
except Exception as exc:
|
except Exception as exc:
|
||||||
errors.append(f"wellness: {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_at = datetime.now(timezone.utc)
|
||||||
cfg.last_sync_status = (
|
cfg.last_sync_status = (
|
||||||
|
|||||||
Reference in New Issue
Block a user