Incidente s50-fix-3: bib_index_openapi revienta límite de subrequests CF Workers (endpoints=0 silencioso)
Incidente s50-fix-3: bib_index_openapi — límite subrequests CF Workers
Resumen
| Campo | Valor |
|---|---|
| Fecha detección | 06-05-2026 |
| Severidad | Alta — stale data masiva en el grafo de conocimiento |
| Servicio afectado | scripts/bib_openapi.py → handler MCP bib_index_openapi |
| Duración del fallo | Desde al menos 13-04-2026 hasta 06-05-2026 (~23 días) |
| Síntoma observable | Cron logueaba [OK] endpoints=0, schemas=0 pero los nodos de endpoints/schemas no se actualizaban. last_indexed_at permanecía en 13-04-2026. |
Causa raíz
CF Workers impone un límite de ~1000 subrequests por invocación. El handler bib_index_openapi realiza aproximadamente 4-5 queries D1 por endpoint (upsertNode + bib_endpoints SELECT/INSERT|UPDATE + edges). Con el spec completo de CreaRack Pro:
414 paths × ~5 queries D1 ≈ 2070 subrequests
199 schemas × ~2 queries D1 ≈ 398 subrequests
≈ 2468 subrequests totales → EXCEDE EL LÍMITE
CF Workers aborta la invocación y el wrapper MCP devuelve:
{"error": "Unhandled: Too many API requests by single Worker invocation"}
Nótese el campo error en singular (formato del wrapper MCP externo). El script bib_openapi.py anterior a s50-fix-3 solo miraba errors[] (plural, formato de los handlers internos), no detectaba este error y salía con rc=0. El cron registraba [OK] endpoints=0, schemas=0 — log completamente engañoso.
Línea de tiempo
13-04-2026 Último reindexado exitoso de endpoints/schemas (aprox.)
25-04-2026 Cron se para 10 días por bit ejecutable perdido (incidente previo s50-prev)
05-05-2026 s50: se implementa arquitectura completa bib_openapi.py + bib_docs.py
→ aún con bug de detección de error; cron corre pero sigue devolviendo
endpoints=0 schemas=0; aviso "2517 stale de 3958" persiste
06-05-2026 s50-fix-3: se diagnostica la causa real y se aplica la corrección
Corrección aplicada (commit 643c96f1)
1. Chunking del spec OpenAPI
scripts/bib_openapi.py divide el spec en lotes antes de enviarlo al handler:
PATHS_PER_CHUNK = 50 # ~250 subrequests por chunk → bien bajo el límite
SCHEMAS_PER_CHUNK = 50 # ~100 subrequests por chunk
Orden de procesamiento:
- Schemas primero — chunks de 50 schemas con
paths: {}para que el handler no itere endpoints. - Paths después — chunks de 50 paths con
components.schemas: {}(el handler resuelve refs por qname).
El output ahora reporta progreso detallado:
OK bib_index_openapi: paths=414 schemas=199 chunks=14 created=… updated=… edges=…
2. Detección dual error / errors
# Antes (solo miraba plural):
errors = inner.get("errors") or []
if errors:
sys.exit(2)
# Después (Regla 15 extendida):
err_singular = inner.get("error") # wrapper MCP externo
err_plural = inner.get("errors") or [] # handlers internos
if err_singular or err_plural:
sys.exit(2)
3. Wrapper MCP devuelve ambos formatos
functions/api/mcp/index.ts actualizado para emitir tanto error (singular) como errors (plural) en respuestas de fallo, garantizando compatibilidad con cualquier cliente futuro.
4. Timeout ampliado
Timeout HTTP de 120 s → 180 s para acomodar el tiempo de procesamiento de múltiples chunks secuenciales.
Lecciones aprendidas
- HTTP 200 ≠ éxito (Regla 15 del proyecto): siempre inspeccionar el payload inner del wrapper MCP, y hacerlo contra todas las claves de error conocidas (
error,errors,message, etc.). - Subrequests CF Workers son un límite silencioso: el worker aborta sin propagar el error al caller de forma obvia. Monitorizar
endpoints_indexeden el cron output como canario. - Counters a cero en un reindexado no son normales: si
endpoints=0y el grafo tiene nodos, hay un fallo. Antes de este fix la doc decía lo contrario — ya corregida encontext/BIBLIOTECA_REINDEX.md.
Mitigación futura
Si endpoints=0, schemas=0 vuelve a aparecer con cron sano:
- Verificar si el grafo ha crecido y un chunk de 50 paths sigue superando el límite.
- Reducir
PATHS_PER_CHUNKenscripts/bib_openapi.py(sin tocar el handler ni el wrapper). - Valor seguro estimado:
PATHS_PER_CHUNK=30da ~150 subrequests por chunk.
Archivos afectados
| Archivo | Cambio |
|---|---|
scripts/bib_openapi.py | Refactorización completa de push_to_mcp() → chunking + _post_chunk() + detección dual |
context/BIBLIOTECA_REINDEX.md | Corrección nota “comportamiento normal” + entrada en histórico s50-fix-3 |
functions/api/mcp/index.ts | Wrapper devuelve error y errors en respuestas de fallo |
Véase también
- [[entity—biblioteca—service—bib-openapi]]
- [[runbook—biblioteca—bib-reindex]]
- [[feature—biblioteca—bib-reindex-s50]]
- [[concept—biblioteca—subrequest-limit-cf-workers]]