From 7c7dd2bc352c91963ece06f3176a032ee7ab462f Mon Sep 17 00:00:00 2001 From: Claudomator Agent Date: Mon, 9 Mar 2026 05:02:36 +0000 Subject: executor: fix map leaks in activePerAgent and rateLimited activePerAgent: delete zero-count entries after decrement so the map doesn't accumulate stale keys for agent types that are no longer active. rateLimited: delete entries whose deadline has passed when reading them (in both the classifier block and the execute() pre-flight), so stale entries are cleaned up on the next check rather than accumulating forever. Both fixes are covered by new regression tests. Co-Authored-By: Claude Sonnet 4.6 --- internal/executor/executor.go | 12 ++++++++++++ 1 file changed, 12 insertions(+) (limited to 'internal/executor/executor.go') diff --git a/internal/executor/executor.go b/internal/executor/executor.go index 9dd37ae..1c9e667 100644 --- a/internal/executor/executor.go +++ b/internal/executor/executor.go @@ -179,6 +179,9 @@ func (p *Pool) executeResume(ctx context.Context, t *task.Task, exec *storage.Ex p.mu.Lock() p.active-- p.activePerAgent[agentType]-- + if p.activePerAgent[agentType] == 0 { + delete(p.activePerAgent, agentType) + } p.mu.Unlock() select { case p.doneCh <- struct{}{}: @@ -296,6 +299,9 @@ func (p *Pool) execute(ctx context.Context, t *task.Task) { now := time.Now() for agent := range p.runners { activeTasks[agent] = p.activePerAgent[agent] + if deadline, ok := p.rateLimited[agent]; ok && now.After(deadline) { + delete(p.rateLimited, agent) + } activeUntil := p.rateLimited[agent] isLimited := now.Before(activeUntil) rateLimited[agent] = isLimited @@ -326,6 +332,9 @@ func (p *Pool) execute(ctx context.Context, t *task.Task) { } p.mu.Lock() + if deadline, ok := p.rateLimited[agentType]; ok && time.Now().After(deadline) { + delete(p.rateLimited, agentType) + } p.activePerAgent[agentType]++ p.mu.Unlock() @@ -333,6 +342,9 @@ func (p *Pool) execute(ctx context.Context, t *task.Task) { p.mu.Lock() p.active-- p.activePerAgent[agentType]-- + if p.activePerAgent[agentType] == 0 { + delete(p.activePerAgent, agentType) + } p.mu.Unlock() select { case p.doneCh <- struct{}{}: -- cgit v1.2.3