diff --git a/sdl-mgr/app/modules/sdl-mgr/index.js b/sdl-mgr/app/modules/sdl-mgr/index.js index 9d1a3ba..715a07b 100644 --- a/sdl-mgr/app/modules/sdl-mgr/index.js +++ b/sdl-mgr/app/modules/sdl-mgr/index.js @@ -320,7 +320,6 @@ function startSDLStatusPub() { ? sdlCfg.update_interval.cluster_status : 10000; - // config.modules.mqtt.topics.sdl-mgr.pub.sdl_cluster-status const statusTopic = mqttCfg.topics?.[module]?.pub?.['sdl_cluster-status']; if (!statusTopic) { log(`${module}: ${statusTopic} not configured`); @@ -344,6 +343,12 @@ function startSDLStatusPub() { } function publishStatus(client, topic) { + // Load current cluster state + const clusterState = loadClusterState(config); + + // Recompute stats to get latest resource totals + const updatedState = computeStats(clusterState); + //get ip addr const interfaces = os.networkInterfaces(); let ip_addr = null; @@ -383,6 +388,8 @@ function publishStatus(client, topic) { update_cmd: `curl -s http://${ip_addr}:${config.modules.web.port}/dist/install-sdl-wkr.sh | bash -s ${ip_addr}` }, cluster: config.cluster, + resources: updatedState.meta.stats.resources, // ✅ Add cluster resources + workers: updatedState.meta.stats.workers, // ✅ Add worker counts modules: Object.fromEntries( Object.entries(config.modules).map(([name, mod]) => [ name, @@ -407,6 +414,78 @@ function publishStatus(client, topic) { } +// ✅ NEW: Publish individual worker details +function startWorkersPub() { + const sdlCfg = config.modules[module]; + const mqttCfg = config.modules.mqtt; + + if (!sdlCfg?.enabled) { + log(`${module}: disabled, not publishing workers`); + return; + } + + if (!mqttCfg?.enabled) { + log(`${module}: MQTT disabled, cannot publish workers`); + return; + } + + const workersInterval = + Number.isInteger(sdlCfg.update_interval.cluster_workers) && + sdlCfg.update_interval.cluster_workers > 0 + ? sdlCfg.update_interval.cluster_workers + : 10000; + + const workersTopic = mqttCfg.topics?.[module]?.pub?.['sdl_cluster-workers']; + if (!workersTopic) { + log(`${module}: sdl_cluster-workers topic not configured`); + return; + } + + const mqttUrl = `mqtt://127.0.0.1:${mqttCfg.mqtt_port}`; + const client = mqtt.connect(mqttUrl); + + client.on('connect', () => { + log(`${module}: workers publisher connected to MQTT at ${mqttUrl}`); + + publishWorkers(client, workersTopic); + setInterval(() => publishWorkers(client, workersTopic), workersInterval); + }); + + client.on('error', err => { + log(`${module}: workers publisher MQTT error: ${err}`); + }); +} + +function publishWorkers(client, topic) { + // Load current cluster state + const clusterState = loadClusterState(config); + + const workersMsg = { + ts: new Date().toISOString(), + sdl_id: config.identity.sdl_id, + role: 'sdl-mgr', + host: config.identity.hostname, + type: 'cluster-workers', + msg: { + workers: clusterState.workers + } + }; + + client.publish( + topic, + JSON.stringify(workersMsg), + { qos: 1, retain: true }, + err => { + if (err) { + log(`${module}: failed to publish workers: ${err}`); + } else { + // log(`${module}: published workers to ${topic}`); + } + } + ); +} + + function startUdpBeacon() { let sdlCfg = config.modules['sdl-mgr']; // log(`${module}: DEBUG: SDL config: ${JSON.stringify(sdlCfg, null, 2)}`, true); @@ -547,6 +626,7 @@ function startUdpBeacon() { // Entry point (ESM-safe) // ------------------------------- startSDLStatusPub(); +startWorkersPub(); // ✅ Start workers publisher startUdpBeacon(); loadClusterState(config); startJoinHandler(); \ No newline at end of file diff --git a/sdl-mgr/conf/modules/sdl-mgr.json b/sdl-mgr/conf/modules/sdl-mgr.json index 5124e4d..049e810 100644 --- a/sdl-mgr/conf/modules/sdl-mgr.json +++ b/sdl-mgr/conf/modules/sdl-mgr.json @@ -4,7 +4,7 @@ "update_interval": { "udp_beacon": 2000, "cluster_status": 10000, - "cluster_workers": 4000, + "cluster_workers": 10000, "cluster_telemetry": 3000 }, "expiration_timeout": { diff --git a/sdl-mgr/html/js/dash.js b/sdl-mgr/html/js/dash.js index dfc2da2..6d616e6 100644 --- a/sdl-mgr/html/js/dash.js +++ b/sdl-mgr/html/js/dash.js @@ -303,24 +303,54 @@ function renderModulesTable(msg) { `; + // Workers stats + const workers = msg.msg.workers || { allocated: 0, available: 0, used: 0 }; sdl_html += ` - CPU - + SDL Workers (active/total) + + ${workers.available} / ${workers.allocated} + `; + // CPU resources + const cpus = msg.msg.resources?.cpus || { allocated: 0, available: 0, used: 0 }; + sdl_html += ` + + CPU Cores + + ${cpus.available} / ${cpus.allocated} + ${cpus.used > 0 ? `(${cpus.used} in use)` : ''} + + + `; + + // Memory resources + const memory = msg.msg.resources?.memory || { allocated: 0, available: 0, used: 0 }; + const memAllocGB = (memory.allocated / 1024).toFixed(1); + const memAvailGB = (memory.available / 1024).toFixed(1); + const memUsedGB = memory.used > 0 ? (memory.used / 1024).toFixed(1) : 0; + sdl_html += ` RAM - + + ${memAvailGB} / ${memAllocGB} GB + ${memUsedGB > 0 ? `(${memUsedGB} GB in use)` : ''} + `; + // GPU resources + const gpus = msg.msg.resources?.gpus || { allocated: 0, available: 0, used: 0 }; sdl_html += ` GPU - + + ${gpus.available} / ${gpus.allocated} + ${gpus.used > 0 ? `(${gpus.used} in use)` : ''} + `; diff --git a/sdl-mgr/html/md/dash.md b/sdl-mgr/html/md/dash.md index 340d154..ebf880f 100644 --- a/sdl-mgr/html/md/dash.md +++ b/sdl-mgr/html/md/dash.md @@ -3,8 +3,11 @@
-
+
+
+
SDL Workers
+
\ No newline at end of file