CreaRack-SL

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

CampoValor
Fecha detección06-05-2026
SeveridadAlta — stale data masiva en el grafo de conocimiento
Servicio afectadoscripts/bib_openapi.py → handler MCP bib_index_openapi
Duración del falloDesde al menos 13-04-2026 hasta 06-05-2026 (~23 días)
Síntoma observableCron 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:

  1. Schemas primero — chunks de 50 schemas con paths: {} para que el handler no itere endpoints.
  2. 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

  1. 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.).
  2. Subrequests CF Workers son un límite silencioso: el worker aborta sin propagar el error al caller de forma obvia. Monitorizar endpoints_indexed en el cron output como canario.
  3. Counters a cero en un reindexado no son normales: si endpoints=0 y el grafo tiene nodos, hay un fallo. Antes de este fix la doc decía lo contrario — ya corregida en context/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_CHUNK en scripts/bib_openapi.py (sin tocar el handler ni el wrapper).
  • Valor seguro estimado: PATHS_PER_CHUNK=30 da ~150 subrequests por chunk.

Archivos afectados

ArchivoCambio
scripts/bib_openapi.pyRefactorización completa de push_to_mcp() → chunking + _post_chunk() + detección dual
context/BIBLIOTECA_REINDEX.mdCorrección nota “comportamiento normal” + entrada en histórico s50-fix-3
functions/api/mcp/index.tsWrapper 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]]