Publishing to cluster/workers

This commit is contained in:
John Haverlack 2026-02-01 12:57:47 -09:00
parent e1ffcaa696
commit 3b9ad5d7a7
4 changed files with 120 additions and 7 deletions

View File

@ -320,7 +320,6 @@ function startSDLStatusPub() {
? sdlCfg.update_interval.cluster_status ? sdlCfg.update_interval.cluster_status
: 10000; : 10000;
// config.modules.mqtt.topics.sdl-mgr.pub.sdl_cluster-status
const statusTopic = mqttCfg.topics?.[module]?.pub?.['sdl_cluster-status']; const statusTopic = mqttCfg.topics?.[module]?.pub?.['sdl_cluster-status'];
if (!statusTopic) { if (!statusTopic) {
log(`${module}: ${statusTopic} not configured`); log(`${module}: ${statusTopic} not configured`);
@ -344,6 +343,12 @@ function startSDLStatusPub() {
} }
function publishStatus(client, topic) { 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 //get ip addr
const interfaces = os.networkInterfaces(); const interfaces = os.networkInterfaces();
let ip_addr = null; 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}` update_cmd: `curl -s http://${ip_addr}:${config.modules.web.port}/dist/install-sdl-wkr.sh | bash -s ${ip_addr}`
}, },
cluster: config.cluster, cluster: config.cluster,
resources: updatedState.meta.stats.resources, // ✅ Add cluster resources
workers: updatedState.meta.stats.workers, // ✅ Add worker counts
modules: Object.fromEntries( modules: Object.fromEntries(
Object.entries(config.modules).map(([name, mod]) => [ Object.entries(config.modules).map(([name, mod]) => [
name, 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() { function startUdpBeacon() {
let sdlCfg = config.modules['sdl-mgr']; let sdlCfg = config.modules['sdl-mgr'];
// log(`${module}: DEBUG: SDL config: ${JSON.stringify(sdlCfg, null, 2)}`, true); // log(`${module}: DEBUG: SDL config: ${JSON.stringify(sdlCfg, null, 2)}`, true);
@ -547,6 +626,7 @@ function startUdpBeacon() {
// Entry point (ESM-safe) // Entry point (ESM-safe)
// ------------------------------- // -------------------------------
startSDLStatusPub(); startSDLStatusPub();
startWorkersPub(); // ✅ Start workers publisher
startUdpBeacon(); startUdpBeacon();
loadClusterState(config); loadClusterState(config);
startJoinHandler(); startJoinHandler();

View File

@ -4,7 +4,7 @@
"update_interval": { "update_interval": {
"udp_beacon": 2000, "udp_beacon": 2000,
"cluster_status": 10000, "cluster_status": 10000,
"cluster_workers": 4000, "cluster_workers": 10000,
"cluster_telemetry": 3000 "cluster_telemetry": 3000
}, },
"expiration_timeout": { "expiration_timeout": {

View File

@ -303,24 +303,54 @@ function renderModulesTable(msg) {
</tr> </tr>
`; `;
// Workers stats
const workers = msg.msg.workers || { allocated: 0, available: 0, used: 0 };
sdl_html += ` sdl_html += `
<tr> <tr>
<th><span class="fa fa-microchip" title="CPU Cores" style="font-size:1.2em"></span> CPU</th> <th>SDL Workers (active/total)</th>
<td class="dash-val" style=" font-size:1em"></td> <td class="dash-val" style="font-size:1em">
<span class="dash-val">${workers.available}</span> / ${workers.allocated}
</td>
</tr> </tr>
`; `;
// CPU resources
const cpus = msg.msg.resources?.cpus || { allocated: 0, available: 0, used: 0 };
sdl_html += `
<tr>
<th><span class="fa fa-microchip" title="CPU Cores" style="font-size:1.2em"></span> CPU Cores</th>
<td class="dash-val" style="font-size:1em">
<span class="dash-val">${cpus.available}</span> / ${cpus.allocated}
${cpus.used > 0 ? `<span style="font-size:0.8em">(${cpus.used} in use)</span>` : ''}
</td>
</tr>
`;
// 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 += ` sdl_html += `
<tr> <tr>
<th><span class="fa fa-memory" title="RAM" style="font-size:1.2em"></span> RAM</th> <th><span class="fa fa-memory" title="RAM" style="font-size:1.2em"></span> RAM</th>
<td class="dash-val" style=" font-size:1em"></td> <td class="dash-val" style="font-size:1em">
<span class="dash-val">${memAvailGB}</span> / ${memAllocGB} GB
${memUsedGB > 0 ? `<span style="font-size:0.8em">(${memUsedGB} GB in use)</span>` : ''}
</td>
</tr> </tr>
`; `;
// GPU resources
const gpus = msg.msg.resources?.gpus || { allocated: 0, available: 0, used: 0 };
sdl_html += ` sdl_html += `
<tr> <tr>
<th><span class="fa fa-dice-d20" title="GPU" style="font-size:1.2em"></span> GPU</th> <th><span class="fa fa-dice-d20" title="GPU" style="font-size:1.2em"></span> GPU</th>
<td class="dash-val" style=" font-size:1em"></td> <td class="dash-val" style="font-size:1em">
<span class="dash-val">${gpus.available}</span> / ${gpus.allocated}
${gpus.used > 0 ? `<span style="font-size:0.8em">(${gpus.used} in use)</span>` : ''}
</td>
</tr> </tr>
`; `;

View File

@ -3,8 +3,11 @@
</div> </div>
<div class="col-4" id="dash-sdl-mgr-info"> <div class="col-4" id="dash-sdl-mgr-info">
</div> </div>
<div class="col-3" id="dash-modules"> <div class="col-2" id="dash-modules">
<div id="dash-modules-list"></div> <div id="dash-modules-list"></div>
<div id="dash-modules-age"></div> <div id="dash-modules-age"></div>
</div> </div>
<div class="col-8" id="dash-sdl-wkrs">
<h5>SDL Workers</h5>
</div>
</div> </div>