mirror of
https://github.com/Ark0N/Codeman.git
synced 2026-10-08 00:19:42 +02:00
feat: enhance /api/debug/memory endpoint with comprehensive metrics
- Add getStats() method to SubagentWatcher for internal resource tracking - Return detailed Map sizes for all server and subagent Maps - Track file watchers, directory watchers, and transcript watchers separately - Track all timer types (respawn, idle, pending starts) - Add totals for quick overview of resource usage - Useful for debugging memory leaks and resource exhaustion The enhanced endpoint now returns: - Memory usage (heap, external, array buffers) - Map sizes by component (server, subagent watcher) - Watcher counts (file, directory, transcript) - Timer counts by type - Spawn agent statistics Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -419,6 +419,36 @@ export class SubagentWatcher extends EventEmitter {
|
|||||||
return this.getProjectHash(workingDir);
|
return this.getProjectHash(workingDir);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get internal statistics for memory monitoring.
|
||||||
|
* Returns counts of internal Maps and resources.
|
||||||
|
*/
|
||||||
|
getStats(): {
|
||||||
|
agentCount: number;
|
||||||
|
fileWatcherCount: number;
|
||||||
|
dirWatcherCount: number;
|
||||||
|
idleTimerCount: number;
|
||||||
|
pendingToolCallsCount: number;
|
||||||
|
knownDirsCount: number;
|
||||||
|
filePositionsCount: number;
|
||||||
|
} {
|
||||||
|
// Count pending tool calls across all agents
|
||||||
|
let pendingToolCallsCount = 0;
|
||||||
|
for (const agentCalls of this.pendingToolCalls.values()) {
|
||||||
|
pendingToolCallsCount += agentCalls.size;
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
agentCount: this.agentInfo.size,
|
||||||
|
fileWatcherCount: this.fileWatchers.size,
|
||||||
|
dirWatcherCount: this.dirWatchers.size,
|
||||||
|
idleTimerCount: this.idleTimers.size,
|
||||||
|
pendingToolCallsCount,
|
||||||
|
knownDirsCount: this.knownSubagentDirs.size,
|
||||||
|
filePositionsCount: this.filePositions.size,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get recent subagents (modified within specified minutes)
|
* Get recent subagents (modified within specified minutes)
|
||||||
*/
|
*/
|
||||||
|
|||||||
+44
-10
@@ -494,9 +494,34 @@ export class WebServer extends EventEmitter {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// Debug/monitoring endpoint - lightweight, only runs when called
|
// Debug/monitoring endpoint - lightweight, only runs when called
|
||||||
|
// Returns comprehensive memory metrics for debugging memory leaks
|
||||||
this.app.get('/api/debug/memory', async () => {
|
this.app.get('/api/debug/memory', async () => {
|
||||||
const mem = process.memoryUsage();
|
const mem = process.memoryUsage();
|
||||||
const spawnState = this.spawnOrchestrator.getState();
|
const spawnState = this.spawnOrchestrator.getState();
|
||||||
|
const subagentStats = subagentWatcher.getStats();
|
||||||
|
|
||||||
|
// Calculate total Map entries for memory estimation
|
||||||
|
const serverMapSizes = {
|
||||||
|
sessions: this.sessions.size,
|
||||||
|
sseClients: this.sseClients.size,
|
||||||
|
respawnControllers: this.respawnControllers.size,
|
||||||
|
runSummaryTrackers: this.runSummaryTrackers.size,
|
||||||
|
transcriptWatchers: this.transcriptWatchers.size,
|
||||||
|
scheduledRuns: this.scheduledRuns.size,
|
||||||
|
terminalBatches: this.terminalBatches.size,
|
||||||
|
outputBatches: this.outputBatches.size,
|
||||||
|
taskUpdateBatches: this.taskUpdateBatches.size,
|
||||||
|
stateUpdatePending: this.stateUpdatePending.size,
|
||||||
|
lastRecordedTokens: this.lastRecordedTokens.size,
|
||||||
|
pendingRespawnStarts: this.pendingRespawnStarts.size,
|
||||||
|
respawnTimers: this.respawnTimers.size,
|
||||||
|
activePlanOrchestrators: this.activePlanOrchestrators.size,
|
||||||
|
cleaningUp: this.cleaningUp.size,
|
||||||
|
};
|
||||||
|
|
||||||
|
const totalServerMapEntries = Object.values(serverMapSizes).reduce((a, b) => a + b, 0);
|
||||||
|
const totalSubagentMapEntries = Object.values(subagentStats).reduce((a, b) => a + b, 0);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
memory: {
|
memory: {
|
||||||
rss: mem.rss,
|
rss: mem.rss,
|
||||||
@@ -510,17 +535,26 @@ export class WebServer extends EventEmitter {
|
|||||||
arrayBuffers: mem.arrayBuffers,
|
arrayBuffers: mem.arrayBuffers,
|
||||||
arrayBuffersMB: Math.round(mem.arrayBuffers / 1024 / 1024 * 10) / 10,
|
arrayBuffersMB: Math.round(mem.arrayBuffers / 1024 / 1024 * 10) / 10,
|
||||||
},
|
},
|
||||||
counts: {
|
mapSizes: {
|
||||||
sessions: this.sessions.size,
|
server: serverMapSizes,
|
||||||
sseClients: this.sseClients.size,
|
subagentWatcher: subagentStats,
|
||||||
respawnControllers: this.respawnControllers.size,
|
totals: {
|
||||||
runSummaryTrackers: this.runSummaryTrackers.size,
|
serverEntries: totalServerMapEntries,
|
||||||
scheduledRuns: this.scheduledRuns.size,
|
subagentEntries: totalSubagentMapEntries,
|
||||||
terminalBatches: this.terminalBatches.size,
|
allEntries: totalServerMapEntries + totalSubagentMapEntries,
|
||||||
outputBatches: this.outputBatches.size,
|
},
|
||||||
pendingRespawnStarts: this.pendingRespawnStarts.size,
|
},
|
||||||
|
watchers: {
|
||||||
|
fileWatchers: subagentStats.fileWatcherCount,
|
||||||
|
dirWatchers: subagentStats.dirWatcherCount,
|
||||||
|
transcriptWatchers: this.transcriptWatchers.size,
|
||||||
|
total: subagentStats.fileWatcherCount + subagentStats.dirWatcherCount + this.transcriptWatchers.size,
|
||||||
|
},
|
||||||
|
timers: {
|
||||||
respawnTimers: this.respawnTimers.size,
|
respawnTimers: this.respawnTimers.size,
|
||||||
subagents: subagentWatcher.getSubagents().length,
|
pendingRespawnStarts: this.pendingRespawnStarts.size,
|
||||||
|
subagentIdleTimers: subagentStats.idleTimerCount,
|
||||||
|
total: this.respawnTimers.size + this.pendingRespawnStarts.size + subagentStats.idleTimerCount,
|
||||||
},
|
},
|
||||||
spawn: {
|
spawn: {
|
||||||
activeAgents: spawnState.activeCount,
|
activeAgents: spawnState.activeCount,
|
||||||
|
|||||||
Reference in New Issue
Block a user