mirror of
https://github.com/Kpa-clawbot/meshcore-analyzer.git
synced 2026-03-30 18:15:47 +00:00
Compare commits
2 Commits
fix/packet
...
fix/cache-
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
499a6db2cc | ||
|
|
ec35b291ee |
13
server.js
13
server.js
@@ -207,6 +207,13 @@ class TTLCache {
|
|||||||
if (key.startsWith(prefix)) this.store.delete(key);
|
if (key.startsWith(prefix)) this.store.delete(key);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
debouncedInvalidateBulkHealth() {
|
||||||
|
if (this._bulkHealthTimer) return;
|
||||||
|
this._bulkHealthTimer = setTimeout(() => {
|
||||||
|
this._bulkHealthTimer = null;
|
||||||
|
this.invalidate('bulk-health');
|
||||||
|
}, 30000);
|
||||||
|
}
|
||||||
debouncedInvalidateAll() {
|
debouncedInvalidateAll() {
|
||||||
if (this._debounceTimer) return;
|
if (this._debounceTimer) return;
|
||||||
this._debounceTimer = setTimeout(() => {
|
this._debounceTimer = setTimeout(() => {
|
||||||
@@ -410,7 +417,7 @@ app.get('/api/perf', (req, res) => {
|
|||||||
avgMs: perfStats.requests ? Math.round(perfStats.totalMs / perfStats.requests * 10) / 10 : 0,
|
avgMs: perfStats.requests ? Math.round(perfStats.totalMs / perfStats.requests * 10) / 10 : 0,
|
||||||
endpoints: Object.fromEntries(sorted),
|
endpoints: Object.fromEntries(sorted),
|
||||||
slowQueries: perfStats.slowQueries.slice(-20),
|
slowQueries: perfStats.slowQueries.slice(-20),
|
||||||
cache: { size: cache.size, hits: cache.hits, misses: cache.misses, staleHits: cache.staleHits, recomputes: cache.recomputes, hitRate: cache.hits + cache.misses > 0 ? Math.round(cache.hits / (cache.hits + cache.misses) * 1000) / 10 : 0 },
|
cache: { size: cache.size, hits: cache.hits, misses: cache.misses, staleHits: cache.staleHits, recomputes: cache.recomputes, hitRate: cache.hits + cache.staleHits + cache.misses > 0 ? Math.round((cache.hits + cache.staleHits) / (cache.hits + cache.staleHits + cache.misses) * 1000) / 10 : 0 },
|
||||||
packetStore: pktStore.getStats(),
|
packetStore: pktStore.getStats(),
|
||||||
sqlite: (() => {
|
sqlite: (() => {
|
||||||
try {
|
try {
|
||||||
@@ -519,7 +526,7 @@ app.get('/api/health', (req, res) => {
|
|||||||
misses: cache.misses,
|
misses: cache.misses,
|
||||||
staleHits: cache.staleHits,
|
staleHits: cache.staleHits,
|
||||||
recomputes: cache.recomputes,
|
recomputes: cache.recomputes,
|
||||||
hitRate: cache.hits + cache.misses > 0 ? Math.round(cache.hits / (cache.hits + cache.misses) * 1000) / 10 : 0,
|
hitRate: cache.hits + cache.staleHits + cache.misses > 0 ? Math.round((cache.hits + cache.staleHits) / (cache.hits + cache.staleHits + cache.misses) * 1000) / 10 : 0,
|
||||||
},
|
},
|
||||||
websocket: {
|
websocket: {
|
||||||
clients: wsClients,
|
clients: wsClients,
|
||||||
@@ -723,7 +730,7 @@ for (const source of mqttSources) {
|
|||||||
// Invalidate this node's caches on advert
|
// Invalidate this node's caches on advert
|
||||||
cache.invalidate('node:' + p.pubKey);
|
cache.invalidate('node:' + p.pubKey);
|
||||||
cache.invalidate('health:' + p.pubKey);
|
cache.invalidate('health:' + p.pubKey);
|
||||||
cache.invalidate('bulk-health');
|
cache.debouncedInvalidateBulkHealth();
|
||||||
|
|
||||||
// Cross-reference: if this node's pubkey matches an existing observer, backfill observer name
|
// Cross-reference: if this node's pubkey matches an existing observer, backfill observer name
|
||||||
if (p.name && p.pubKey) {
|
if (p.name && p.pubKey) {
|
||||||
|
|||||||
@@ -1254,6 +1254,24 @@ seedTestData();
|
|||||||
lastPathSeenMap.delete(liveNode);
|
lastPathSeenMap.delete(liveNode);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// ── Cache hit rate includes stale hits ──
|
||||||
|
await t('Cache hitRate includes staleHits in formula', async () => {
|
||||||
|
cache.clear();
|
||||||
|
cache.hits = 0;
|
||||||
|
cache.misses = 0;
|
||||||
|
cache.staleHits = 0;
|
||||||
|
// Simulate: 3 hits, 2 stale hits, 5 misses => rate = (3+2)/(3+2+5) = 50%
|
||||||
|
cache.hits = 3;
|
||||||
|
cache.staleHits = 2;
|
||||||
|
cache.misses = 5;
|
||||||
|
const r = await request(app).get('/api/health').expect(200);
|
||||||
|
assert(r.body.cache.hitRate === 50, 'hitRate should be (hits+staleHits)/(hits+staleHits+misses) = 50%, got ' + r.body.cache.hitRate);
|
||||||
|
// Reset
|
||||||
|
cache.hits = 0;
|
||||||
|
cache.misses = 0;
|
||||||
|
cache.staleHits = 0;
|
||||||
|
});
|
||||||
|
|
||||||
// ── Summary ──
|
// ── Summary ──
|
||||||
console.log(`\n═══ Server Route Tests: ${passed} passed, ${failed} failed ═══`);
|
console.log(`\n═══ Server Route Tests: ${passed} passed, ${failed} failed ═══`);
|
||||||
if (failed > 0) process.exit(1);
|
if (failed > 0) process.exit(1);
|
||||||
|
|||||||
Reference in New Issue
Block a user