/root/Routes-api on 31.97.228.132 is not a git repository. Work had been done directly on the box and existed nowhere else -- a single rm -rf from being lost, and impossible to review or roll back. Deploying the previous HEAD over it would have silently reverted all of this. Most visibly the Valhalla road-backend probe in main.py, whose own comment explains why it exists: road sequencing degrades to aerial silently by design, so an unreachable backend stays invisible, "which is exactly how the expired Google key went unnoticed". Overwriting it would have reintroduced precisely the failure it was written to catch, and the service would have kept answering 200 throughout. The server had also moved from Google Maps to Valhalla for road distance (VALHALLA_URL, road_backend_status, +190 lines in route_optimizer), extended docker-compose from 44 to 95 lines, and changed rider fetching, health, dynamic config and the cache layer. Only 10 files differ in substance. The other 27 that appeared to differ were CRLF-vs-LF noise -- the server writes CRLF -- and are normalised to LF here rather than committed as spurious whole-file rewrites. Committed as-is, before any change of mine, so the diff that follows is reviewable against what is actually running. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
118 lines
4.3 KiB
Python
118 lines
4.3 KiB
Python
|
|
import httpx
|
|
import logging
|
|
from datetime import datetime
|
|
from typing import List, Dict, Any
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
def _roster_cache_ttl() -> int:
|
|
"""Roster cache TTL in seconds. 0 disables caching entirely."""
|
|
try:
|
|
from app.config.dynamic_config import get_config
|
|
return int(get_config().get("rider_roster_cache_ttl_seconds", 30))
|
|
except Exception:
|
|
return 30
|
|
|
|
|
|
async def fetch_active_riders() -> List[Dict[str, Any]]:
|
|
"""
|
|
Fetch active rider logs from the external API for the current date.
|
|
Returns a list of rider log dictionaries.
|
|
|
|
This upstream call measured ~6s on live traffic and was the single largest
|
|
component of riderassign latency, so successful responses are cached for
|
|
`rider_roster_cache_ttl_seconds`. The TTL is deliberately short: a rider
|
|
going on or off duty must become visible quickly, and the absent-rider
|
|
validation in the assignment path checks against this roster.
|
|
|
|
Only non-empty successes are cached. Caching an empty result or a failure
|
|
would turn a brief upstream blip into a full-TTL outage where every request
|
|
sees zero riders.
|
|
"""
|
|
today_str = datetime.now().strftime("%Y-%m-%d")
|
|
ttl = _roster_cache_ttl()
|
|
cache_key = f"riders:active:{today_str}"
|
|
|
|
if ttl > 0:
|
|
try:
|
|
from app.services import cache as _cache
|
|
cached = _cache.get_json(cache_key)
|
|
if isinstance(cached, list) and cached:
|
|
logger.debug(f"[Riders] roster cache hit ({len(cached)} riders)")
|
|
return cached
|
|
except Exception:
|
|
pass
|
|
|
|
try:
|
|
url = "https://jupiter.nearle.app/live/api/v2/partners/getriderlogs/"
|
|
params = {
|
|
"applocationid": 1,
|
|
"partnerid": 44,
|
|
"fromdate": today_str,
|
|
"todate": today_str,
|
|
"keyword": ""
|
|
}
|
|
|
|
async with httpx.AsyncClient(timeout=30.0) as client:
|
|
response = await client.get(url, params=params)
|
|
response.raise_for_status()
|
|
data = response.json()
|
|
|
|
if data and data.get("code") == 200 and data.get("details"):
|
|
# Filter riders who are in our preferences list and are 'active' or 'idle' (assuming we want online riders)
|
|
# The user's example showed "onduty": 1. We might want to filter by that.
|
|
# For now, returning all logs, filtering can happen in assignment logic or here.
|
|
# Let's return the raw list as requested, filtering logic will be applied during assignment.
|
|
riders = data.get("details", [])
|
|
if riders and ttl > 0:
|
|
try:
|
|
from app.services import cache as _cache
|
|
_cache.set_json(cache_key, riders, ttl_seconds=ttl)
|
|
except Exception:
|
|
pass
|
|
return riders
|
|
|
|
logger.warning(f"Fetch active riders returned no details: {data}")
|
|
return []
|
|
|
|
except Exception as e:
|
|
logger.error(f"Error fetching active riders: {e}", exc_info=True)
|
|
return []
|
|
|
|
async def fetch_created_orders() -> List[Dict[str, Any]]:
|
|
"""
|
|
Fetch all orders in 'created' state for the current date.
|
|
"""
|
|
try:
|
|
today_str = datetime.now().strftime("%Y-%m-%d")
|
|
url = "https://jupiter.nearle.app/live/api/v1/orders/tenant/getorders/"
|
|
# Removed pagesize as per user request to fetch all
|
|
params = {
|
|
"applocationid": 0,
|
|
"tenantid": 0,
|
|
"locationid": 0,
|
|
"status": "created",
|
|
"fromdate": today_str,
|
|
"todate": today_str,
|
|
"keyword": "",
|
|
"pageno": 1
|
|
# "pagesize" intentionally omitted to fetch all
|
|
}
|
|
|
|
async with httpx.AsyncClient(timeout=60.0) as client:
|
|
response = await client.get(url, params=params)
|
|
response.raise_for_status()
|
|
data = response.json()
|
|
|
|
if data and data.get("code") == 200 and data.get("details"):
|
|
return data.get("details", [])
|
|
|
|
logger.warning(f"Fetch created orders returned no details: {data}")
|
|
return []
|
|
|
|
except Exception as e:
|
|
logger.error(f"Error fetching created orders: {e}", exc_info=True)
|
|
return []
|
|
|