mirror of
https://github.com/Ark0N/Codeman.git
synced 2026-09-30 12:39: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);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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)
|
||||
*/
|
||||
|
||||
+44
-10
@@ -494,9 +494,34 @@ export class WebServer extends EventEmitter {
|
||||
});
|
||||
|
||||
// Debug/monitoring endpoint - lightweight, only runs when called
|
||||
// Returns comprehensive memory metrics for debugging memory leaks
|
||||
this.app.get('/api/debug/memory', async () => {
|
||||
const mem = process.memoryUsage();
|
||||
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 {
|
||||
memory: {
|
||||
rss: mem.rss,
|
||||
@@ -510,17 +535,26 @@ export class WebServer extends EventEmitter {
|
||||
arrayBuffers: mem.arrayBuffers,
|
||||
arrayBuffersMB: Math.round(mem.arrayBuffers / 1024 / 1024 * 10) / 10,
|
||||
},
|
||||
counts: {
|
||||
sessions: this.sessions.size,
|
||||
sseClients: this.sseClients.size,
|
||||
respawnControllers: this.respawnControllers.size,
|
||||
runSummaryTrackers: this.runSummaryTrackers.size,
|
||||
scheduledRuns: this.scheduledRuns.size,
|
||||
terminalBatches: this.terminalBatches.size,
|
||||
outputBatches: this.outputBatches.size,
|
||||
pendingRespawnStarts: this.pendingRespawnStarts.size,
|
||||
mapSizes: {
|
||||
server: serverMapSizes,
|
||||
subagentWatcher: subagentStats,
|
||||
totals: {
|
||||
serverEntries: totalServerMapEntries,
|
||||
subagentEntries: totalSubagentMapEntries,
|
||||
allEntries: totalServerMapEntries + totalSubagentMapEntries,
|
||||
},
|
||||
},
|
||||
watchers: {
|
||||
fileWatchers: subagentStats.fileWatcherCount,
|
||||
dirWatchers: subagentStats.dirWatcherCount,
|
||||
transcriptWatchers: this.transcriptWatchers.size,
|
||||
total: subagentStats.fileWatcherCount + subagentStats.dirWatcherCount + this.transcriptWatchers.size,
|
||||
},
|
||||
timers: {
|
||||
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: {
|
||||
activeAgents: spawnState.activeCount,
|
||||
|
||||
Reference in New Issue
Block a user