Restore near-real-time public server status
This commit is contained in:
@@ -144,6 +144,53 @@ Comando de validacion de produccion tras redeploy:
|
||||
python .\scripts\audit_public_requests.py --base-url https://comunidadhll.devzamode.es --timeout 30 --filter current-match --output tmp\task227_current_match_audit_after.json
|
||||
```
|
||||
|
||||
## Estado post-fix TASK-228
|
||||
|
||||
Fecha: 2026-06-10
|
||||
Alcance aplicado: restauracion de `/api/servers` como endpoint near-real-time controlado para la home.
|
||||
|
||||
Causa confirmada:
|
||||
|
||||
- `TASK-226` hizo que `/api/servers` dejara de llamar `_try_collect_real_time_snapshot()`.
|
||||
- La ruta quedo en modo `cache-only`, con `refresh_attempted: false` y `refresh_status: cache-only`.
|
||||
- Cuando no existian snapshots persistidos, respondia rapido pero con `source: no-snapshot-available` e `items: []`, aunque la fuente live pudiera estar disponible en produccion.
|
||||
|
||||
Cambios de codigo aplicados:
|
||||
|
||||
- `/api/servers` vuelve a usar la politica live/casi-live:
|
||||
- sirve snapshot fresco si existe.
|
||||
- intenta refresh live si no hay snapshot o el snapshot esta stale.
|
||||
- devuelve live RCON/A2S si hay items.
|
||||
- cae a snapshot stale si live falla y existe ultimo estado conocido.
|
||||
- devuelve JSON controlado con error/fallback si live falla y no hay snapshot.
|
||||
- El refresh publico usa timeout corto interno (`2.5s`) propagado a RCON/A2S sin cambiar variables de entorno, hosts, puertos ni configuracion de servidores.
|
||||
- No se persiste desde el GET publico para evitar inicializaciones/DDL pesadas en lectura.
|
||||
|
||||
Estado esperado tras redeploy:
|
||||
|
||||
| Endpoint | Estado TASK-228 en codigo | Severidad esperada tras deploy |
|
||||
| --- | --- | --- |
|
||||
| `/api/servers` | Near-real-time controlado; live si cache falta/stale, stale fallback si live falla | OK o WARNING si live no disponible |
|
||||
| `/api/servers/latest` | Sigue leyendo almacenamiento local | OK o WARNING si no hay snapshots persistidos |
|
||||
| `/api/servers/history` | Sigue leyendo almacenamiento local | OK o WARNING si no hay snapshots persistidos |
|
||||
|
||||
Comando de validacion de produccion tras redeploy:
|
||||
|
||||
```powershell
|
||||
$base = "https://comunidadhll.devzamode.es"
|
||||
|
||||
Invoke-WebRequest "$base/api/servers" |
|
||||
Select-Object -ExpandProperty Content
|
||||
|
||||
Invoke-WebRequest "$base/api/servers/latest" |
|
||||
Select-Object -ExpandProperty Content
|
||||
|
||||
Invoke-WebRequest "$base/api/servers/history" |
|
||||
Select-Object -ExpandProperty Content
|
||||
|
||||
python .\scripts\audit_public_requests.py --base-url https://comunidadhll.devzamode.es --timeout 30 --filter servers --output tmp\task228_servers_audit_after.json
|
||||
```
|
||||
|
||||
## Evidencia ejecutada
|
||||
|
||||
Comandos ejecutados:
|
||||
|
||||
@@ -10,6 +10,8 @@ Actualizacion TASK-226, 2026-06-10: `/api/current-match/kills` y `/api/current-m
|
||||
|
||||
Actualizacion TASK-227, 2026-06-10: la auditoria real post-`TASK-226` mostro que kills/players seguian bloqueando en produccion porque la rama PostgreSQL de AdminLog no propagaba `ensure_storage=False` a `connect_postgres_compat()`. El fix propaga `initialize=ensure_storage`, de modo que `/api/current-match/kills` y `/api/current-match/players` ya no ejecutan `initialize_postgres_rcon_storage()` en el GET publico cuando se sirven como lecturas read-only.
|
||||
|
||||
Actualizacion TASK-228, 2026-06-10: `/api/servers` deja de ser cache-only estricto y vuelve a ser near-real-time controlado para la home. Sirve snapshot fresco si existe; si no hay cache o esta stale, intenta RCON/A2S con timeout publico corto y degrada a snapshot stale o JSON controlado si live falla. `/api/servers/latest` e `/api/servers/history` siguen siendo lecturas de almacenamiento local, no sustitutos del estado live.
|
||||
|
||||
Conclusiones principales:
|
||||
|
||||
- El backend de `ranking` ya no muestra el cuello de botella grave del ranking anual. La evidencia mas fuerte es el test `backend/tests/test_annual_ranking_payload.py`, que confirma que la lectura anual en PostgreSQL ya no inicializa storage en request publico.
|
||||
@@ -18,7 +20,7 @@ Conclusiones principales:
|
||||
- `partida-actual.js` no bloquea por `/health`, pero hace polling agresivo y paralelo a tres endpoints (`/api/current-match`, `/api/current-match/kills`, `/api/current-match/players`) sin `AbortController`, con intervalos de 1.5 s y 3 s que pueden amplificar carga y re-render innecesario. Tras TASK-227, kills/players usan AdminLog PostgreSQL en modo read-only real y degradan desde backend en JSON controlado.
|
||||
- En backend siguen existiendo fallbacks runtime publicos sobre tablas materializadas grandes para `ranking`, `stats search` y `stats player profile`. Son mejores que consultar RCON directo, pero siguen rompiendo la meta de servir lecturas publicas desde read models dedicados.
|
||||
- Las queries runtime de leaderboard y player stats usan patrones como `COALESCE(CAST(matches.ended_at AS TEXT), CAST(matches.started_at AS TEXT))` y agregaciones sobre `rcon_match_player_stats`, lo que aumenta riesgo de scans y de uso parcial de indices.
|
||||
- `current-match` sigue consultando RCON directo en request publico cuando hay target confiable. Eso contradice la regla objetivo de esta auditoria y debe tratarse como deuda arquitectonica explicita aunque hoy sea un requisito funcional de la pagina live.
|
||||
- `current-match` sigue consultando RCON directo en request publico cuando hay target confiable. `/api/servers` tambien consulta live de forma controlada cuando falta cache o esta stale porque la home requiere estado actual/casi actual.
|
||||
|
||||
## Mapa de Arquitectura de Lectura Publica
|
||||
|
||||
@@ -33,7 +35,7 @@ Flujo observado:
|
||||
|
||||
- `ranking` y `stats` mezclan frontend secuencial con backend que aun puede caer a runtime sobre tablas materializadas si falta snapshot o read model.
|
||||
- `historico` ya prioriza snapshots y fallback controlado.
|
||||
- `current-match` expone una excepcion relevante: `/api/current-match` consulta RCON directo en la ruta publica cuando encuentra target valido. Kills/players leen AdminLog sin inicializar storage en request publico, incluyendo la rama PostgreSQL corregida en `TASK-227`.
|
||||
- `current-match` expone una excepcion relevante: `/api/current-match` consulta RCON directo en la ruta publica cuando encuentra target valido. Kills/players leen AdminLog sin inicializar storage en request publico, incluyendo la rama PostgreSQL corregida en `TASK-227`. `/api/servers` usa refresh live acotado cuando el cache no sirve para mantener la home casi en tiempo real.
|
||||
|
||||
## Inventario de Endpoints Publicos
|
||||
|
||||
@@ -49,7 +51,7 @@ Flujo observado:
|
||||
| `/api/current-match` | `frontend/assets/js/partida-actual.js` | `build_current_match_payload()` | Read model live propio | Primero intenta `_query_current_match_rcon_sample()` directo; luego fallback a `/api/servers` snapshot | Si, y toca RCON directo | P0 |
|
||||
| `/api/current-match/kills` | `frontend/assets/js/partida-actual.js` | `build_current_match_kill_feed_payload()` | Read model live propio de kill feed | AdminLog materializado en modo read-only publico; PostgreSQL usa `connect_postgres_compat(initialize=False)` | Degradacion JSON controlada si falla read model | P2 |
|
||||
| `/api/current-match/players` | `frontend/assets/js/partida-actual.js` | `build_current_match_player_stats_payload()` | Read model live propio de player stats | AdminLog materializado en modo read-only publico; PostgreSQL usa `connect_postgres_compat(initialize=False)` | Degradacion JSON controlada si falla read model | P2 |
|
||||
| `/api/servers` | `frontend/assets/js/main.js`, fallback de current-match | `build_servers_payload()` | Snapshot live de servidores | Snapshot/cache persistido | Sin refresh live en GET publico | P2 |
|
||||
| `/api/servers` | `frontend/assets/js/main.js`, fallback de current-match | `build_servers_payload()` | Snapshot live de servidores | Snapshot fresco o refresh live RCON/A2S acotado si falta/stale | Stale snapshot o JSON controlado si live falla | P1 |
|
||||
| `/health` | `frontend/assets/js/main.js`, `ranking.js`, `stats.js` | `build_health_payload()` | N/A | Check tecnico | No aplica | P1 por bloqueo UI, no por backend |
|
||||
|
||||
Notas:
|
||||
|
||||
Reference in New Issue
Block a user