CreaRack-SL

ADR: Plan Servicios Fase C ligera — Migración de 6 crons del Bibliotecario a STAGE Hetzner

ADRactivecreado Sat May 16

ADR: Plan Servicios Fase C ligera — Migración de 6 crons del Bibliotecario a STAGE Hetzner

Contexto

Tras el cierre operativo del Plan Servicios al 95% (ver [[decision—20260516—auditoria-simplificacion-servicios-auxiliares]]), Edu replanteó si valía la pena ejecutar la Fase C — Migración selectiva a Hetzner aún siendo OPCIONAL.

El análisis de consumo Actions real reveló:

  • 22% del cap incluido Plan Pro (660/3000 min/mes estimados)
  • $0 overage actual ($4/mes Plan Pro fijo, ningún gasto Actions adicional)
  • Spending limit Actions a $20 era techo de seguridad, no gasto real

→ El driver económico para Fase C no existe hoy.

Sin embargo, Edu identificó valor cualitativo en migrar:

  • Resiliencia: crons siguen si GitHub Actions cae (raro pero pasa)
  • Margen futuro: si el proyecto crece a 5x consumo, ya está preparado
  • Frescor del Bibliotecario: con cap Actions levantado, subir frecuencia de los crons “gratis al escalar” (Catalog/Utility/Reindex-TS) ya no tiene techo

Decisión

Ejecutar Fase C en variante ligera: migrar los 6 cron-workflows del Bibliotecario que son llamadas curl-MCP triviales. NO migrar self-hosted runner para CI (riesgo de saturación CPU/RAM STAGE durante runs). NO migrar workflows que requieren clone repo + Python/Node + git push (catalog, translate, weekly-report, bib-reindex-ts schedule) — se quedan en GH Actions hasta una iteración futura si es necesario.

Workflows migrados (6 · cron systemd STAGE)

WorkflowFrecuenciaLlama LLM?Coste estimado/mes
wiki-curator.sh (Sonnet review drafts)L+J 05:00 UTCSí~$4
wiki-lint.sh (bulk + contradictions incremental)Diario 04:30 UTCNo$0
wiki-lint-consolidation.sh (mode full)Dom 03:00 UTCNo$0
wiki-utility.sh (recompute scores)L+M+V 06:00 UTCNo$0
wiki-drift-check.sh (Haiku dry_run cap 5)Diario 06:00 UTCSí (Haiku)~$0.5 (dry_run)
drift-cron-escriba.sh (REST endpoint)Diario 04:15 UTC(verificar)~$0

Workflows NO migrados (4 · siguen en GH Actions)

  • wiki-catalog.yml — Python + git push (necesita clone workspace + PAT)
  • wiki-translate.yml — Node + git push (Node no instalado en STAGE)
  • wiki-weekly-report.yml — Python + git push
  • bib-reindex-ts.yml (schedule diario) — Node + MCP (Node no instalado · su push trigger se mantiene siempre)

Frecuencias mantenidas iguales

Decisión consciente: no subir frecuencias en la misma sesión que se migra. Principio de cambios pequeños iterativos. Tras validar que los crons systemd corren limpios 1-2 semanas, se puede decidir aumento de frecuencia de los workflows “gratis al escalar” (utility a diario, por ejemplo) en una iteración separada.

Implementación

Estado STAGE pre-migración

  • 2 vCPUs · 3.7 GB RAM · 22 GB disco libre
  • Load avg 0.12 (idle)
  • Patrón cron ya establecido para Bibliotecario: /etc/cron.d/bib-reindex corriendo desde s50 sin incidentes
  • Tooling disponible: curl 8.5, jq 1.7, git 2.43, Python 3.12.3, systemd 255
  • Node NO instalado (motivo de NO migrar workflows Tipo A)

Footprint añadido tras migración

  • RAM idle: 0 MB (scripts ephemeral, mueren al acabar)
  • RAM pico: 200-400 MB durante run (~1-2 min/run)
  • CPU pico: 5-15s 1 core por run
  • Disco: ~50 MB (logs + tmp)
  • Veredicto: insignificante sobre el footprint actual

Estructura desplegada

/opt/biblioteca-crons/
├── _common.sh                  (lib compartida: token loading + mcp_call + mcp_verify)
├── wiki-curator.sh
├── wiki-lint.sh
├── wiki-lint-consolidation.sh
├── wiki-utility.sh
├── wiki-drift-check.sh
├── drift-cron-escriba.sh
└── logs/
    └── <name>.log

/etc/cron.d/biblioteca-crons    (6 líneas cron, frecuencias = workflows GH Actions originales)

Tokens reutilizados de /opt/bib-reindex/ (single source of truth):

  • .token (MCP_TOKEN)
  • .cf-access-id + .cf-access-secret (CF Access service token)

Smoke test (16-05-2026 noche)

5 de los 6 scripts ejecutados manualmente:

  • wiki-utility.sh → OK (1s, MCP responde)
  • wiki-drift-check.sh → OK (25s · 5 pages procesadas · 2 drift detectados · $0.0148)
  • drift-cron-escriba.sh → OK (1s · REST endpoint OK)
  • wiki-lint.sh → OK (33s · 2 calls secuenciales bulk + contradictions)
  • wiki-lint-consolidation.sh → OK (3s · mode full)

wiki-curator.sh NO ejecutado manualmente (Sonnet con coste notable · misma lógica MCP que el resto, validada).

Desactivación schedule en GH Actions

Los 6 workflows .yml del workspace tienen schedule: comentado con bloque explicativo:

on:
  # schedule deshabilitado 16-05-2026 (s66) — migrado a STAGE Hetzner (Plan Servicios Fase C ligera)
  # Cron systemd activo: /etc/cron.d/biblioteca-crons → /opt/biblioteca-crons/<name>.sh
  # ADR: decision--20260516--fase-c-crons-stage-ligera
  # Para reactivar en GH Actions: descomentar bloque schedule abajo + desactivar línea en /etc/cron.d/biblioteca-crons.
  # schedule:
  #   - cron: "..."
  workflow_dispatch:
    ...

workflow_dispatch: mantenido para invocación manual y rollback trivial (descomentar schedule + commit).

Alternativas descartadas

Full Fase C (incluir self-hosted runner CI)

Rechazada. Self-runner persistente consume 200-300 MB RAM idle + 1-2 GB durante runs CI. Riesgo concreto: CI compite con Django STAGE durante runs (timeout web/worker o tests STAGE lentos). El valor añadido (minutos Actions ilimitados) no compensa cuando actualmente estamos al 22% del cap.

Incluir wiki-catalog/translate/weekly-report (Tipo A)

Postponed. Requieren clone del repo workspace en STAGE + Python deps + Node + PAT con permisos push + adaptar scripts. Estimado +2-3h trabajo. Se hará si emerge dolor real (consumo Actions creciendo o necesidad de subir frecuencia de catalog).

No hacer Fase C

Rechazada por Edu. El valor cualitativo (resiliencia, margen futuro) supera el coste mínimo de implementación cuando ya existe el patrón cron-bib-reindex.sh validado en STAGE.

Consecuencias

Positivas

  • 6 workflows menos en consumo GH Actions (~36 min/mes ahorrados, marginal pero acumulativo)
  • Resiliencia: estos 6 crons sobreviven a outages GitHub Actions
  • Latencia: ~10-30s ahorro por run (no esperar runner managed)
  • Sin gasto API Anthropic adicional (mismas llamadas, mismo flujo, solo cambia el caller)

Negativas / Riesgos

  • Mantenimiento STAGE: ahora 8 cron jobs corren en STAGE (bib-reindex × 3 + biblioteca-crons × 6 + dr-backups + gh-actions-watchdog). Si STAGE cae, el Bibliotecario pierde ~50% de su procesamiento periódico.
  • Logs no centralizados en GH UI: ahora hay que ssh root@crearack-staging "tail -50 /opt/biblioteca-crons/logs/<name>.log" para troubleshoot. Mitigación: GitHub Issues open en error (futuro, no implementado todavía).
  • Pausa global perdida: el toggle vars.BIBLIOTECARIO_PAUSADO ya no afecta a los 6 migrados. Si se necesita pausar Bibliotecario completo, hay que tocar 2 sitios ahora: GH variable + comentar líneas en /etc/cron.d/biblioteca-crons.

Mitigaciones

  • Rollback trivial: descomentar schedule: en los .yml + comentar líneas en /etc/cron.d/biblioteca-crons → vuelven a GH Actions. 5 min máx.
  • Logs accesibles vía tailnet ssh root@crearack-staging.
  • Si el patrón funciona 1-2 semanas, considerar Tipo A (catalog, translate, weekly-report) en iteración futura.

Estado

  • 16-05-2026 (s66 noche): ADR firmado, implementación completada, smoke test 5/6 OK. Workflows GH Actions con schedule: comentado pushed. Cron systemd activo en STAGE. Primer trigger automático esperado: 17-05-2026 03:00 UTC (wiki-lint-consolidation domingo).

Verificación a corto plazo (1-2 semanas)

  • Confirmar primer run automático de cada cron systemd (logs en /opt/biblioteca-crons/logs/).
  • Confirmar que el resultado del cron en STAGE = el resultado que producía el workflow en GH Actions (mismo content en D1, mismas pages procesadas).
  • Si OK: cerrar verificación a 17-05-2026 +14d.
  • Si emerge un fallo persistente: rollback rápido + investigar causa.

Reapertura / siguiente iteración

Si tras 1-2 semanas el patrón funciona y emerge interés:

  • Sub-fase C.2: instalar Node en STAGE + clonar repo workspace + PAT push + migrar wiki-catalog/wiki-translate/wiki-weekly-report/bib-reindex-ts(schedule). Crear ADR independiente.
  • Aumento de frecuencias: Catalog L+M+V → diario, Utility L+M+V → diario, Reindex-TS 24h → 12h. Todo gratis al escalar (no llaman LLM).

Véase también

  • [[concept—workspace—supercontexto-05-crons]]
  • [[concept—infra—staging-server]]
  • [[decision—20260516—auditoria-simplificacion-servicios-auxiliares]]