Skip to content

Plataforma técnica · Nostromo

Orchestrator ETL Controller

Nostromo ETL Orchestrator

EtlController es el puente HTTP entre Sevastopol y los loaders Python de Nostromo. Su única responsabilidad es disparar procesos Python desde Express con child_process.spawn, validar prerrequisitos antes del arranque y mantener el estado de las corridas en memoria.

No persiste resultados — el estado completo de una corrida vive en un Map<number, EtlExecutionStatus> indexado por PID, con LRU de 100 entradas. La trazabilidad persistente vive en los logs stdout/stderr que cada loader emite.

DecisiónMotivo
spawn en vez de import directoNostromo es un módulo Python independiente; importar Python en Node implicaría empaquetar el venv. La frontera CLI mantiene la separación de tecnologías.
Registry in-memory con LRU 100El estado de una corrida es efímero — el cliente la polea hasta completed/failed y la olvida. Persistir el registry no aporta valor (los logs ya están en stdout).
Watchdog ETL_TIMEOUT_MS=15minProcesos colgados (sesión SII, scraping) deben morir solos. El timeout es configurable por env.
Validación de UTM antes del spawnimpuesto_2cat_loader falla si no hay UTM del mes en parametros.indicadores. El controller hace getIndicador(YYYY-MM-01, "UTM") antes de gastar un fork. Devuelve 409 con accionRecomendada si falta.
errorTail con clasificación de patronesFUNCTIONAL_ERROR_PATTERNS (no encontró, no disponible, falló) prevalece sobre SECONDARY_LOGGING_PATTERNS (SSL, MongoDB). El tail prioriza el error funcional; el diagnóstico secundario va en “Secondary diagnostics”.
tailText(value, 1200)Solo los últimos ~1200 chars del log se devuelven al cliente. Suficiente para diagnóstico; evita pasar megabytes por red.
resolvePythonExecutable con venv detectionPrefiere .venv/Scripts/python.exe (dev) y cae a python del PATH (prod). El path absoluto a Nostromo es c:\dev\Nostromo — MVP documentado.
authenticateToken middlewareSolo usuarios autenticados disparan ETL. La UI valida adicionalmente que el rol sea SUPER_ADMIN.
Sin streaming de stdoutLa UI espera el endedAt para mostrar el errorTail. Streaming agregaría complejidad (SSE/WebSocket) sin caso de uso claro.
MétodoRutaBody / ParamsRespuesta
POST/api/etl/trigger{ script, period, ...flags }{ pid, script, message } o 400/409/500 con error.
GET/api/etl/status/:pid{ pid, status, startedAt, endedAt?, exitCode?, errorTail?, stdoutTail?, stderrTail?, timedOut? }.
script (body)Módulo PythonArgs pasados
sii_loaderaccounting_system.sii_loader--year, --month desde period (YYYY-MM).
previred_loaderaccounting_system.previred_loader--period.
correccion_monetariaaccounting_system.correccion_monetaria_loader--year (solo año).
impuesto_2cat_loaderaccounting_system.impuesto_2cat_loader--year, --month, --periodo, --utm?. Pre-valida UTM.
banco_central_loaderaccounting_system.bc_loader-fi, -fn, -dryrun 0, -m?. Acepta fechaInicio/fechaFin explícitas o las deriva del period.
CheckComportamiento
period matches ^\d{4}-\d{2}$400 si no.
utm provista en bodyPasa --utm y omite la siguiente check.
UTM en parametros.indicadores para YYYY-MM-01409 con accionRecomendada si falta.
periodoTipo ∈ {mensual, quincenal, semanal, diario, all}400 si otro. Default all.
CheckComportamiento
fechaInicio + fechaFin como YYYY-MM-DDAcepta override del period. 400 si formato inválido o inicio > fin.
Sin override → deriva del period (YYYY-MM)400 si period ausente o mal formado.
moneda ∈ {UF, USD, EUR, ALL}Default ALL. 400 si otro.
EstadoSignificado
runningspawn exitoso, proceso vivo.
completedExit code 0.
failedExit code ≠ 0 o timedOut: true.
unknownEl PID consultado no está en el registry (eviction o reinicio).
interface EtlExecutionStatus {
pid: number;
script: string;
status: "running" | "completed" | "failed";
startedAt: string; // ISO
endedAt?: string; // ISO al terminar
exitCode?: number;
errorTail?: string; // últimos ~1200 chars, filtrados
stdoutTail?: string;
stderrTail?: string;
timedOut?: boolean;
}
Env varDefaultUso
ETL_TIMEOUT_MS900000 (15 min)Timeout del watchdog.
  • orchestrator/src/controllers/EtlController.ts — la lógica.
  • orchestrator/src/routes/etlRoutes.ts — montaje con authenticateToken.
  • Mount en app.ts:222: app.use("/api/etl", etlRoutes).