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 []