add configurable cloud api url and subpath routing support for reverse proxies

This commit is contained in:
2026-09-19 12:00:48 +05:30
parent ce16210525
commit cc45a2f270
10 changed files with 106 additions and 50 deletions
+25 -19
View File
@@ -19,10 +19,14 @@ def get_http_client() -> httpx.AsyncClient:
)
return _http_client
def get_cloud_base_url() -> str:
url = getattr(settings, "cloud_api_url", None) or os.getenv("CLOUD_API_URL") or "https://services-api.a2zhealth.in/v1/contec-monitor"
return url.rstrip("/")
async def forward_vitals_to_api(vitals: NormalizedVitals) -> bool:
"""
Attempts to POST the normalized vitals to the configured target API
and to the Render cloud database concurrently.
and to the Cloud server concurrently.
Returns True if at least one forward succeeds.
"""
headers = {"Content-Type": "application/json"}
@@ -59,16 +63,17 @@ async def forward_vitals_to_api(vitals: NormalizedVitals) -> bool:
logger.warning(f"Error forwarding to primary API: {type(e).__name__} ({err_msg})")
return False
# 2. Forward to Render Cloud Server
async def _forward_render() -> bool:
render_url = "https://contectfiveparamonitor.onrender.com/api/push-vitals"
is_on_render = os.getenv("RENDER") is not None or os.getenv("PORT") == "10000" or "render.local" in os.getenv("HOSTNAME", "")
if is_on_render:
# 2. Forward to Cloud Server
async def _forward_cloud() -> bool:
cloud_base = get_cloud_base_url()
cloud_url = f"{cloud_base}/api/push-vitals"
is_on_cloud = os.getenv("RENDER") is not None or os.getenv("PORT") == "10000" or "render.local" in os.getenv("HOSTNAME", "")
if is_on_cloud and ("onrender.com" in cloud_base):
return True
try:
url_with_key = render_url
url_with_key = cloud_url
if settings.api_token:
url_with_key = f"{render_url}?api_key={settings.api_token}"
url_with_key = f"{cloud_url}?api_key={settings.api_token}"
response = await client.post(
url_with_key,
@@ -76,28 +81,29 @@ async def forward_vitals_to_api(vitals: NormalizedVitals) -> bool:
headers=headers
)
response.raise_for_status()
logger.info(f"Successfully forwarded vitals to Render Cloud for device {vitals.device_id}")
logger.info(f"Successfully forwarded vitals to Cloud API for device {vitals.device_id}")
return True
except Exception as e:
err_msg = str(e).strip() or "timeout / connection reset"
logger.warning(f"Error forwarding to Render Cloud: {type(e).__name__} ({err_msg})")
logger.warning(f"Error forwarding to Cloud API: {type(e).__name__} ({err_msg})")
return False
results = await asyncio.gather(_forward_primary(), _forward_render(), return_exceptions=True)
results = await asyncio.gather(_forward_primary(), _forward_cloud(), return_exceptions=True)
return any(r is True for r in results if not isinstance(r, Exception))
async def sync_patient_assignment_to_cloud(patient_data: dict, device_id: str) -> bool:
"""
Synchronizes patient demographics assignment to Render Cloud Server.
Synchronizes patient demographics assignment to Cloud Server.
Ensures local and remote dashboards always show the exact same patient.
"""
is_on_render = os.getenv("RENDER") is not None or os.getenv("PORT") == "10000" or "render.local" in os.getenv("HOSTNAME", "")
if is_on_render:
cloud_base = get_cloud_base_url()
is_on_cloud = os.getenv("RENDER") is not None or os.getenv("PORT") == "10000" or "render.local" in os.getenv("HOSTNAME", "")
if is_on_cloud and ("onrender.com" in cloud_base):
return True
client = get_http_client()
render_assign_url = "https://contectfiveparamonitor.onrender.com/api/patient/assign"
cloud_assign_url = f"{cloud_base}/api/patient/assign"
payload = {
"device_id": device_id,
"mrn": patient_data.get("mrn") or patient_data.get("patient_id") or "",
@@ -108,13 +114,13 @@ async def sync_patient_assignment_to_cloud(patient_data: dict, device_id: str) -
"patient_type": patient_data.get("patient_type")
}
try:
url_with_key = render_assign_url
url_with_key = cloud_assign_url
if settings.api_token:
url_with_key = f"{render_assign_url}?api_key={settings.api_token}"
url_with_key = f"{cloud_assign_url}?api_key={settings.api_token}"
resp = await client.post(url_with_key, json=payload, headers={"Content-Type": "application/json"})
resp.raise_for_status()
logger.info(f"Successfully synced patient {payload['mrn']} ({payload['name']}) to Render Cloud for {device_id}")
logger.info(f"Successfully synced patient {payload['mrn']} ({payload['name']}) to Cloud for {device_id}")
return True
except Exception as e:
logger.warning(f"Could not sync patient assignment to Render Cloud: {type(e).__name__} ({e})")
logger.warning(f"Could not sync patient assignment to Cloud: {type(e).__name__} ({e})")
return False