---
name: valhalla_isochrones_async
kind: function
lang: py
domain: geo
version: "1.0.0"
purity: impure
signature: "async def valhalla_isochrones_async(requests: list[dict], base_url: str = 'http://localhost:8002', costing: str = 'auto', concurrency: int = 6, timeout_s: float = 120.0, denoise: float = 0.6, generalize_m: int = 50) -> list[dict | None]"
description: "Calcula isócronas para múltiples puntos en paralelo usando httpx.AsyncClient y asyncio.Semaphore. Order-preserving: la lista retornada es paralela a la de entrada."
tags: [valhalla, isochrone, geo, http, async, asyncio, geojson, batch]
uses_functions: []
uses_types: []
returns: []
returns_optional: true
error_type: "error_go_core"
imports: [httpx, asyncio]
params:
  - name: requests
    desc: "Lista de dicts con 'lat' (float), 'lon' (float), 'minutes' (int) y opcionalmente 'id' (str). Un elemento por punto."
  - name: base_url
    desc: "URL base del servidor Valhalla. Por defecto http://localhost:8002."
  - name: costing
    desc: "Modelo de coste: 'auto', 'bicycle', 'pedestrian', etc."
  - name: concurrency
    desc: "Número máximo de requests HTTP simultáneas (Semaphore). Por defecto 6."
  - name: timeout_s
    desc: "Timeout en segundos por request individual."
  - name: denoise
    desc: "Factor de suavizado del contorno (0-1)."
  - name: generalize_m
    desc: "Tolerancia de generalización de la geometría en metros."
output: "Lista paralela a 'requests' con GeoJSON dict (campo 'features') o None por cada punto. Preserva el orden de entrada. Nunca lanza excepcion — fallos individuales se mapean a None."
tested: true
tests: ["3 puntos Madrid retornan lista de 3"]
test_file_path: "python/functions/geo/tests/test_valhalla_isochrones_async.py"
file_path: "python/functions/geo/valhalla_isochrones_async.py"
source_repo: "internal:footprint_aurgi"
source_license: "internal-aurgi"
source_file: "ponderacion_isochronas/src/generar_isochronas_aurgi.py"
---

## Ejemplo

```python
import asyncio

pts = [
    {"lat": 40.4168, "lon": -3.7038, "minutes": 10, "id": "madrid_centro"},
    {"lat": 40.4530, "lon": -3.6883, "minutes": 10, "id": "retiro"},
]
results = asyncio.run(valhalla_isochrones_async(pts))
for req, gj in zip(pts, results):
    status = "ok" if gj else "error"
    print(f"{req['id']}: {status}")
```

## Notas

Adaptada de `_run_isochrones` y `_fetch_isochrone` en `generar_isochronas_aurgi.py`. La versión original acoplaba pandas DataFrames y escritura a disco — esta versión es pandas-free y retorna datos en memoria. Usa asyncio.gather para preservar el orden de resultados.
