fix: reliable cloud sync and connection pooling for Render live dashboard
This commit is contained in:
@@ -79,3 +79,86 @@ async def retry_failed_transmissions():
|
||||
logger.error(f"Error in retry background task: {e}")
|
||||
|
||||
await asyncio.sleep(settings.retry_interval_seconds)
|
||||
|
||||
|
||||
async def sync_cloud_state():
|
||||
"""
|
||||
Periodically syncs all assigned patients and their latest non-null vitals to Render Cloud.
|
||||
Ensures that whenever Render restarts or deploys with an empty DB, the cloud dashboard
|
||||
is immediately populated with the same data as localhost.
|
||||
"""
|
||||
import os
|
||||
if os.getenv("RENDER") is not None or os.getenv("PORT") == "10000" or "render.local" in os.getenv("HOSTNAME", ""):
|
||||
return # Do not run sync loop if we are running inside Render
|
||||
|
||||
from models import Patient
|
||||
from api_client import sync_patient_assignment_to_cloud, forward_vitals_to_api
|
||||
from datetime import datetime, timezone
|
||||
from sqlalchemy import or_
|
||||
|
||||
logger.info("Starting background task for periodic cloud state sync to Render...")
|
||||
await asyncio.sleep(5)
|
||||
|
||||
while True:
|
||||
try:
|
||||
db = SessionLocal()
|
||||
try:
|
||||
patients = db.query(Patient).filter(
|
||||
Patient.patient_id != "UNKNOWN",
|
||||
Patient.mrn != "UNKNOWN"
|
||||
).all()
|
||||
|
||||
for p in patients:
|
||||
if not p.device_id:
|
||||
continue
|
||||
|
||||
# 1. Sync patient demographics assignment to Render
|
||||
p_data = {
|
||||
"mrn": p.mrn or p.patient_id,
|
||||
"name": p.name,
|
||||
"gender": p.gender,
|
||||
"dob": p.dob,
|
||||
"bed_id": p.bed_id,
|
||||
"patient_type": getattr(p, "patient_type", None)
|
||||
}
|
||||
await sync_patient_assignment_to_cloud(p_data, p.device_id)
|
||||
|
||||
# 2. Backfill and forward latest complete non-null vitals to Render
|
||||
patient_filters = or_(
|
||||
VitalReading.patient_id == p.mrn,
|
||||
VitalReading.patient_id == p.patient_id,
|
||||
VitalReading.device_id == p.device_id
|
||||
)
|
||||
recent_r = db.query(VitalReading).filter(patient_filters).order_by(VitalReading.timestamp.desc()).first()
|
||||
if recent_r:
|
||||
spo2_r = db.query(VitalReading.spo2).filter(patient_filters, VitalReading.spo2 != None).order_by(VitalReading.timestamp.desc()).first()
|
||||
hr_r = db.query(VitalReading.heart_rate).filter(patient_filters, VitalReading.heart_rate != None).order_by(VitalReading.timestamp.desc()).first()
|
||||
bp_r = db.query(VitalReading.systolic_bp, VitalReading.diastolic_bp, VitalReading.map_bp).filter(patient_filters, VitalReading.systolic_bp != None).order_by(VitalReading.timestamp.desc()).first()
|
||||
temp_r = db.query(VitalReading.temperature).filter(patient_filters, VitalReading.temperature != None).order_by(VitalReading.timestamp.desc()).first()
|
||||
rr_r = db.query(VitalReading.respiratory_rate).filter(patient_filters, VitalReading.respiratory_rate != None).order_by(VitalReading.timestamp.desc()).first()
|
||||
|
||||
merged = NormalizedVitals(
|
||||
device_id=p.device_id,
|
||||
patient_id=p.mrn or p.patient_id,
|
||||
patient_name=p.name,
|
||||
patient_gender=p.gender,
|
||||
patient_dob=p.dob,
|
||||
bed_id=p.bed_id,
|
||||
patient_type=getattr(p, "patient_type", None),
|
||||
timestamp=recent_r.timestamp or datetime.now(timezone.utc),
|
||||
heart_rate=hr_r[0] if hr_r else None,
|
||||
spo2=spo2_r[0] if spo2_r else None,
|
||||
systolic_bp=bp_r[0] if bp_r else None,
|
||||
diastolic_bp=bp_r[1] if bp_r else None,
|
||||
map_bp=bp_r[2] if bp_r else None,
|
||||
temperature=temp_r[0] if temp_r else None,
|
||||
respiratory_rate=rr_r[0] if rr_r else None
|
||||
)
|
||||
await forward_vitals_to_api(merged)
|
||||
finally:
|
||||
db.close()
|
||||
except Exception as e:
|
||||
logger.error(f"Error in sync_cloud_state background task: {e}")
|
||||
|
||||
await asyncio.sleep(15)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user