feat: add combined environment endpoint for concurrent weather + air quality fetch
- POST /volatile/fetch/environment/{city} fetches both in parallel
- Single geocode lookup shared between API calls
- Uses asyncio.gather() for concurrent external requests
- Fix scheduler executor name (rest_api → rest_api_executor)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -545,6 +545,64 @@ async def fetch_air_quality(
|
||||
}
|
||||
|
||||
|
||||
@router.post("/fetch/environment/{city}")
|
||||
async def fetch_environment(
|
||||
city: str,
|
||||
user: str = Query(default=DEFAULT_USER, description="User identifier"),
|
||||
weather_ttl: int = Query(default=3600, ge=60, le=86400, description="Weather TTL in seconds"),
|
||||
air_quality_ttl: int = Query(default=3600, ge=60, le=86400, description="Air quality TTL in seconds"),
|
||||
qdrant: QdrantDep = None,
|
||||
ollama: OllamaDep = None,
|
||||
api_key: str = Depends(verify_api_key)
|
||||
):
|
||||
"""
|
||||
Fetch weather and air quality concurrently for a city.
|
||||
|
||||
Performs a single geocode lookup and fetches both weather and air quality
|
||||
data in parallel, storing both in volatile cache. More efficient than
|
||||
calling /fetch/weather and /fetch/air_quality separately.
|
||||
|
||||
**Example:**
|
||||
```
|
||||
POST /volatile/fetch/environment/rotterdam?user=jpmschweitzer
|
||||
```
|
||||
|
||||
**Response includes:**
|
||||
- weather: Current conditions (temperature, humidity, wind, UV)
|
||||
- air_quality: AQI indices, pollutants, pollen data
|
||||
"""
|
||||
volatile_service = get_volatile_service(qdrant, ollama)
|
||||
weather_provider = get_weather_provider()
|
||||
|
||||
fetch_service = VolatileFetchService(
|
||||
volatile_service=volatile_service,
|
||||
weather_provider=weather_provider,
|
||||
)
|
||||
|
||||
result = await fetch_service.fetch_environment(
|
||||
user, city, weather_ttl=weather_ttl, air_quality_ttl=air_quality_ttl
|
||||
)
|
||||
|
||||
if not result.success:
|
||||
raise HTTPException(status_code=500, detail="; ".join(result.errors))
|
||||
|
||||
return {
|
||||
"success": True,
|
||||
"key": result.key,
|
||||
"weather": {
|
||||
"success": result.weather.success if result.weather else False,
|
||||
"record": result.weather.record if result.weather else None,
|
||||
"error": result.weather.error if result.weather else None,
|
||||
},
|
||||
"air_quality": {
|
||||
"success": result.air_quality.success if result.air_quality else False,
|
||||
"record": result.air_quality.record if result.air_quality else None,
|
||||
"error": result.air_quality.error if result.air_quality else None,
|
||||
},
|
||||
"errors": result.errors,
|
||||
}
|
||||
|
||||
|
||||
@router.get("/{namespace}/{key}", response_model=VolatileRecordResponse)
|
||||
async def get_record(
|
||||
namespace: str,
|
||||
|
||||
Reference in New Issue
Block a user