fix: serve cached server data before background sync

This commit is contained in:
Luca Sacchi Ricciardi
2026-04-25 15:57:37 +02:00
parent f60781bd7f
commit 9649f2ccfb
4 changed files with 306 additions and 46 deletions
+66 -27
View File
@@ -26,6 +26,9 @@ class LLMMonitorApp {
this.updateServerContextUI();
// Caricare dati da localStorage prima di qualsiasi sync di rete.
this.loadFromLocalStorage();
// Inizializzare il Web Worker
if (typeof Worker !== 'undefined') {
this.worker = new Worker('/static/js/data-sync.worker.js');
@@ -35,19 +38,22 @@ class LLMMonitorApp {
// Fallback: sincronizzazione nel main thread
this.syncDataInMainThread();
};
const shouldSyncImmediately = this.shouldSyncImmediately();
this.worker.postMessage({
type: "SET_SERVER",
serverId: this.activeServer.id,
host: this.activeServer.host
host: this.activeServer.host,
syncImmediately: shouldSyncImmediately,
lastSyncTimestamp: this.getLatestCacheTimestamp()
});
} else {
if (shouldSyncImmediately) {
this.renderLoadingState();
}
} else if (this.shouldSyncImmediately()) {
console.warn("Web Workers not supported, using main thread");
this.syncDataInMainThread();
}
// Caricare dati da localStorage
this.loadFromLocalStorage();
// Listener al pulsante manuale
document.getElementById("refresh-btn")?.addEventListener("click", () => {
this.requestSync();
@@ -73,31 +79,23 @@ class LLMMonitorApp {
// Caricare dati da localStorage
loadFromLocalStorage() {
const healthStr = localStorage.getItem(this.getStorageKey("health"));
const modelsStr = localStorage.getItem(this.getStorageKey("models"));
const health = readServerCache(this.activeServer.id, "health");
const models = readServerCache(this.activeServer.id, "models");
if (healthStr) {
try {
this.lastData.health = JSON.parse(healthStr);
this.renderHealth(this.lastData.health);
} catch (e) {
console.error("Error parsing health data:", e);
}
if (health) {
this.lastData.health = health;
this.renderHealth(this.lastData.health);
}
if (modelsStr) {
try {
this.lastData.models = JSON.parse(modelsStr);
this.renderModels(this.lastData.models);
} catch (e) {
console.error("Error parsing models data:", e);
}
if (models) {
this.lastData.models = models;
this.renderModels(this.lastData.models);
}
}
// Gestire messaggi dal Worker
handleWorkerMessage(event) {
const { type, health, modelsData, serverId } = event.data;
const { type, health, modelsData, runningData, serverId } = event.data;
if (serverId && this.activeServer && serverId !== this.activeServer.id) {
return;
@@ -107,7 +105,7 @@ class LLMMonitorApp {
if (health && JSON.stringify(this.lastData.health) !== JSON.stringify(health)) {
this.lastData.health = health;
try {
localStorage.setItem(this.getStorageKey("health"), JSON.stringify(health));
writeServerCache(this.activeServer.id, "health", health);
} catch (error) {
console.warn("Cannot persist health in localStorage:", error);
}
@@ -117,7 +115,7 @@ class LLMMonitorApp {
if (modelsData && JSON.stringify(this.lastData.models) !== JSON.stringify(modelsData)) {
this.lastData.models = modelsData;
try {
localStorage.setItem(this.getStorageKey("models"), JSON.stringify(modelsData));
writeServerCache(this.activeServer.id, "models", modelsData);
} catch (error) {
console.warn("Cannot persist models in localStorage:", error);
}
@@ -126,6 +124,14 @@ class LLMMonitorApp {
this.showModelDetails(this.selectedModelName);
}
}
if (runningData) {
try {
writeServerCache(this.activeServer.id, "running", runningData);
} catch (error) {
console.warn("Cannot persist running models in localStorage:", error);
}
}
}
}
@@ -365,7 +371,7 @@ class LLMMonitorApp {
if (response.ok) {
const health = await response.json();
this.lastData.health = health;
localStorage.setItem(this.getStorageKey("health"), JSON.stringify(health));
writeServerCache(this.activeServer.id, "health", health);
this.renderHealth(health);
}
} catch (error) {
@@ -396,7 +402,7 @@ class LLMMonitorApp {
timestamp: new Date().toISOString()
};
this.lastData.models = modelsData;
localStorage.setItem(this.getStorageKey("models"), JSON.stringify(modelsData));
writeServerCache(this.activeServer.id, "models", modelsData);
this.renderModels(modelsData);
if (this.selectedModelName) {
this.showModelDetails(this.selectedModelName);
@@ -408,7 +414,22 @@ class LLMMonitorApp {
}
getStorageKey(suffix) {
return `llm_monitor_${suffix}_${this.activeServer.id}`;
return getServerStorageKey(this.activeServer.id, suffix);
}
shouldSyncImmediately() {
const health = readServerCache(this.activeServer.id, "health");
const models = readServerCache(this.activeServer.id, "models");
if (!health || !models) {
return true;
}
return isCacheStale(this.getLatestCacheTimestamp());
}
getLatestCacheTimestamp() {
return getLatestServerCacheTimestamp(this.activeServer.id, ["health", "models", "running"]);
}
buildApiUrl(path) {
@@ -463,6 +484,24 @@ class LLMMonitorApp {
`;
}
}
renderLoadingState() {
if (this.lastData.models) {
return;
}
const container = document.getElementById("models-container");
if (!container) {
return;
}
container.innerHTML = `
<div class="text-center py-8">
<div class="animate-spin inline-block w-8 h-8 border-4 border-gray-600 border-t-purple-500 rounded-full"></div>
<p class="text-gray-400 mt-4">Loading models...</p>
</div>
`;
}
}
// Inizializzare l'app quando il DOM è pronto