feat(engine-room): unifica Casa de Máquinas com Registry do Kernel

- Adiciona fetchRegistryServices() para consultar /api/registry/services
- Adiciona mapRegistryToEngine() para converter formato do Registry
- Modifica /api/engine-room/status para usar Registry como fonte primária
- Evita duplicação: se Registry tem serviços, não adiciona presets duplicados
- MetaSet só é adicionado se não houver bi-engine (evita 2 Motores BI)
- Fallback para kernel-adapter se Registry não disponível

Isso unifica a visão da Casa de Máquinas com o Discovery automático.

Refs: kernel, registry, casa-de-maquinas, unificacao
This commit is contained in:
Jonas Pacheco 2026-04-08 10:51:19 -03:00
parent 015273ffdd
commit aa83dbdbce
1 changed files with 105 additions and 29 deletions

View File

@ -10,6 +10,55 @@ import {
isKernelAvailable isKernelAvailable
} from "./kernel-adapter"; } from "./kernel-adapter";
// NOVO: Consulta Registry do Kernel para serviços descobertos
async function fetchRegistryServices(): Promise<any[] | null> {
try {
const controller = new AbortController();
const timeout = setTimeout(() => controller.abort(), 3000);
const response = await fetch('http://localhost:5001/api/registry/services', {
signal: controller.signal,
});
clearTimeout(timeout);
if (!response.ok) return null;
const data = await response.json();
return data.success && Array.isArray(data.data?.services) ? data.data.services : null;
} catch {
return null;
}
}
// NOVO: Converte serviço do Registry para formato EngineStatus
function mapRegistryToEngine(service: any): any {
const id = service.id || service.name;
// Mapear health status
let status: 'online' | 'offline' | 'error' = 'offline';
if (service.healthStatus === 'healthy') status = 'online';
else if (service.healthStatus === 'unhealthy') status = 'error';
return {
name: id,
displayName: service.displayName || service.name,
type: service.type || 'unknown',
port: service.port || 0,
category: service.category || 'data',
description: service.description || `Serviço ${service.name}`,
status,
responseTime: undefined,
details: {
endpoint: service.endpoint,
health: service.healthStatus,
version: service.version,
capabilities: service.capabilities?.map((c: any) => c.name) || [],
source: 'registry',
},
};
}
// Fallback para sistema antigo (import comentado - remover após validação) // Fallback para sistema antigo (import comentado - remover após validação)
// import { restartManagedService, stopManagedService, getManagedServiceInfo, getManagedServiceLogs } from "../index"; // import { restartManagedService, stopManagedService, getManagedServiceInfo, getManagedServiceLogs } from "../index";
@ -157,35 +206,62 @@ export function registerEngineRoomRoutes(app: Express): void {
}); });
} }
// Obter engines do Kernel // NOVO: Tentar obter serviços do Registry primeiro
const kernelEngines = await getKernelEngines(); const registryServices = await fetchRegistryServices();
const engines: any[] = [];
const engineNames = new Set<string>();
// Adicionar Plus (gerenciado externamente - PHP/Laravel) if (registryServices && registryServices.length > 0) {
const plusEngine = ENGINES.find(e => e.name === "plus"); // Usar serviços do Registry (descobertos via Docker/Coolify)
if (plusEngine) { for (const service of registryServices) {
const plusHealth = await checkEngineHealth(plusEngine); const mapped = mapRegistryToEngine(service);
kernelEngines.push({ engines.push(mapped);
...plusHealth, engineNames.add(mapped.name);
name: plusEngine.name, }
displayName: plusEngine.displayName, console.log(`[Engine Room] ${engines.length} serviços do Registry`);
type: plusEngine.type, } else {
category: plusEngine.category, // Fallback: usar engines do Kernel (modo antigo)
description: plusEngine.description, const kernelEngines = await getKernelEngines();
} as any); engines.push(...kernelEngines);
kernelEngines.forEach(e => engineNames.add(e.name));
console.log(`[Engine Room] ${engines.length} serviços do Kernel (fallback)`);
} }
// Adicionar MetaSet (gerenciado externamente - Python/Superset) // Adicionar serviços externos que não estão no Registry
const metasetEngine = ENGINES.find(e => e.name === "metaset"); // Plus (gerenciado externamente - PHP/Laravel)
if (metasetEngine) { if (!engineNames.has("plus")) {
const metasetHealth = await checkEngineHealth(metasetEngine); const plusEngine = ENGINES.find(e => e.name === "plus");
kernelEngines.push({ if (plusEngine) {
...metasetHealth, const plusHealth = await checkEngineHealth(plusEngine);
name: metasetEngine.name, engines.push({
displayName: metasetEngine.displayName, ...plusHealth,
type: metasetEngine.type, name: plusEngine.name,
category: metasetEngine.category, displayName: plusEngine.displayName,
description: metasetEngine.description, type: plusEngine.type,
} as any); category: plusEngine.category,
description: plusEngine.description,
} as any);
engineNames.add("plus");
}
}
// MetaSet (gerenciado externamente - Python/Superset)
// Só adiciona se não estiver no Registry e se bi-engine não existir
// (evita duplicação de Motor BI)
if (!engineNames.has("metaset") && !engineNames.has("bi-engine")) {
const metasetEngine = ENGINES.find(e => e.name === "metaset");
if (metasetEngine) {
const metasetHealth = await checkEngineHealth(metasetEngine);
engines.push({
...metasetHealth,
name: metasetEngine.name,
displayName: metasetEngine.displayName,
type: metasetEngine.type,
category: metasetEngine.category,
description: metasetEngine.description,
} as any);
engineNames.add("metaset");
}
} }
let agentsStatus: any[] = []; let agentsStatus: any[] = [];
@ -196,11 +272,11 @@ export function registerEngineRoomRoutes(app: Express): void {
agentsStatus = []; agentsStatus = [];
} }
const online = kernelEngines.filter((r) => r.status === "online").length; const online = engines.filter((r) => r.status === "online").length;
const total = kernelEngines.length; const total = engines.length;
res.json({ res.json({
engines: kernelEngines, engines,
agents: agentsStatus, agents: agentsStatus,
summary: { summary: {
total_engines: total, total_engines: total,