Duración máxima: 2 horas 30 minutos.
Modalidad: grupal.
Estamos a cargo de el desarrollo y mantenimiento de un sistema que nos permite saber cuál es el próximo colectivo de cada línea que va a pasar por mi parada.
Contamos con varios servicios que se encargan de distintos concerns: lineas, paradas y cuando-viene. Este último es el único que va a estar de cara a los usuarios, exponiendo una API REST.
Existe un cuarto componente, monitoreo, que nos sirve para conocer el estado del resto de los servicios. Éste expone una página web para ser visualizada por el equipo de infraestructura.
La misma utiliza websockets para ser notificada ante cambios en los estados. Debería poder soportar varias pestañas abiertas.
Los servicios se encuentran en cuando-viene/python_src y usan Python, asyncio y
aiohttp para HTTP, llamadas concurrentes y WebSockets. Las solicitudes entre servicios
incluyen timeouts, reintentos y manejo de errores.
El objetivo es practicar el uso de corutias, esperas no bloqueantes, concurrencia de este tipo de contextos de ejecucion y cancelación de
tareas. La persistencia y actualización periódica de las líneas ya están resueltas
y no deben modificarse (lineas.py y utils/actualizacion_lineas.py).
Completen los TODOs presentes en el código:
- Espera no bloqueante (
paradas.py): completen el middleware para que uno de cada dos pedidos (excepto/health) demore 5 segundos sin bloquear el event loop. - Consultas concurrentes (
cuando_viene.py): implementenget_line_detailspara consultar todas las líneas a la vez. Los resultados deben conservar el orden de entrada. No hagan los pedidos secuencialmente. - Tolerancia a fallos (
cuando_viene.py): Ajustenget_line_detailspara que si la consulta a una línea particular falla, el endpoint principal no devuelva error, sino que omita esa línea y devuelva los resultados exitosos. - Ejecución de una corutina (
cuando_viene.py): corrijan la consulta de la parada enarrival_timespara trabajar con el resultado y no con el objeto corutina. - Monitoreo periódico (
monitoreo.py): implementenmonitorpara consultar los tres servicios concurrentemente, enviar sus estados por el WebSocket una vez por segundo y terminar limpiamente al cerrar la conexión. - Métricas en segundo plano (paradas.py): Existe una función
registrar_metricaque demora 2 segundos. Incorpórenla enget_stopde forma tal que se ejecute correctamente pero el usuario reciba la respuesta de la parada sin tener que esperar ese tiempo extra.
Bonus:
- Control de concurrencia (
cuando_viene.py): Enget_line_detailspara no saturar la red, implementen un algo que limite a un máximo de 4 consultas concurrentes simultáneas al servicio de líneas.
Pueden usar asyncio.gather o TaskGroup en los puntos de concurrencia;
no es necesario modificar el manejo de sesiones HTTP ya provisto.
- El código no contiene
time.sleepni crea una sesión HTTP por pedido. - Una petición lenta a
paradasno impide que/healthresponda inmediatamente. - Las consultas a varias líneas se inician concurrentemente y el endpoint
/cuando-viene/{parada}devuelve los estados ordenados por tiempo de llegada. - Cada pestaña de monitoreo recibe actualizaciones independientes y periódicas.
- Al cerrar una pestaña no quedan tareas de monitoreo ejecutándose.
- No se modifican
lineas.pyniutils/actualizacion_lineas.py.
- Una función declarada con
async defdevuelve una corutina al invocarla; para obtener su resultado hay que esperarla. asyncio.sleepcede el control al event loop; mientras quetime.sleeplo bloquea.asyncio.gatheracepta varias corutinas y devuelve sus resultados en el orden en que fueron pasadas.- El alta y la cancelación de la tarea de monitoreo ya están resueltas en
index_or_websocket; el trabajo pendiente está dentro demonitor. asyncio.Semaphorees una primitiva de sincronización que se utiliza para limitar el número de tareas concurrentes que pueden acceder a un recurso o bloque de código específico simultáneamente Semaphore.
Con los cuatro servicios levantados, prueben los endpoints indicados debajo. Abran
además dos pestañas en http://localhost:3003/, verifiquen que ambas se actualicen
y cierren una para confirmar que la otra continúe funcionando. Ejecuten dos veces
seguidas el endpoint de paradas y, mientras la segunda llamada espera, consulten
/health desde otra terminal.
Para ejecutar los cuatro servicios con Docker:
docker compose up --buildEndpoints:
http://localhost:3000/paradas/0http://localhost:3001/lineas/15http://localhost:3002/cuando-viene/0http://localhost:3003/(monitoreo por WebSocket)
python -m venv .venv
source .venv/bin/activate
pip install -r cuando-viene/requirements.txtDesde cuando-viene/python_src, inicie cada servicio en una terminal independiente:
python paradas.py
python lineas.py
PARADAS_HOST=localhost LINEAS_HOST=localhost python cuando_viene.py
PARADAS_HOST=localhost LINEAS_HOST=localhost CUANDO_VIENE_HOST=localhost python monitoreo.py