Skip to content

feat(router): add agent-type concurrency limiting#634

Merged
zbigniewsobiecki merged 1 commit intodevfrom
feat/agent-type-concurrency-limiting
Mar 7, 2026
Merged

feat(router): add agent-type concurrency limiting#634
zbigniewsobiecki merged 1 commit intodevfrom
feat/agent-type-concurrency-limiting

Conversation

@zbigniewsobiecki
Copy link
Copy Markdown
Member

Summary

  • Add per-agent-type concurrency limits to prevent multiple instances of the same agent type running simultaneously for a project
  • Configurable via agent_configs.max_concurrency (DB column, dashboard UI, CLI)
  • Two-layer lock: in-memory fast path + DB authoritative count
  • Trigger-level dedup (60s TTL) suppresses batch webhook re-triggers
  • Shared checkAgentTypeConcurrency() eliminates code duplication across 3 webhook handlers

Code review fixes included

This PR also incorporates fixes from a thorough code review of the initial implementation:

  1. CRITICAL — Fixed double-counting: isAgentTypeLocked now uses Math.max(dbCount, inMemoryCount) instead of summing, preventing false positives during the enqueued→running transition
  2. Removed unnecessary try-catch around routerConfig.workerTimeoutMs (module-level constant never throws)
  3. Deduplicated checkAgentTypeConcurrency — extracted shared function, deleted 3 near-identical copies
  4. Fixed dashboard job agentType extractionextractAgentType() now checks triggerResult?.agentType then falls back to top-level agentType
  5. Added error handlinggetMaxConcurrency() DB failures are caught gracefully (proceeds without limit)
  6. Added 5-second TTL cache to getMaxConcurrency() to reduce DB queries on webhook batches
  7. Added dedup map cleanup — periodic eviction when map exceeds 100 entries
  8. Added concurrency-blocked tests to all 3 webhook handler test suites + 5 checkAgentTypeConcurrency tests
  9. Consolidated key functions — merged makeConcurrencyKey/makeDedupKey into single makeKey
  10. Added CHECK constraintmax_concurrency IS NULL OR max_concurrency > 0 in migration

Test plan

  • npm run typecheck — clean
  • npm run lint — clean
  • npx vitest run tests/unit/router/agent-type-lock.test.ts — 24 tests pass
  • npm test — full suite 3868 tests pass
  • Pre-commit hooks (lint + typecheck) pass
  • Pre-push hooks (full test suite) pass

🤖 Generated with Claude Code

Add per-agent-type concurrency limits to prevent multiple instances of the
same agent type running simultaneously for a project.

Core implementation:
- New `agent_configs.max_concurrency` column with CHECK constraint
- Two-layer lock in `src/router/agent-type-lock.ts`:
  1. In-memory concurrency map (fast path, TTL safety net)
  2. DB count of running `agent_runs` (authoritative, survives restarts)
- Trigger-level dedup (60s TTL) suppresses batch webhook re-triggers
- Shared `checkAgentTypeConcurrency()` consolidates logic from 3 handlers

Key design decisions:
- Use `Math.max(dbCount, inMemoryCount)` instead of sum to avoid
  double-counting during the enqueued→running transition
- 5-second TTL cache on `getMaxConcurrency()` DB queries
- Graceful fallback (no limit) when DB is unreachable
- Periodic cleanup of dedup map when it exceeds 100 entries

Dashboard & CLI:
- Agent config forms expose Max Concurrency field
- `cascade agents create/update --max-concurrency N`
- Agent configs table shows concurrency column

Container manager:
- `extractAgentType()` handles both trigger-based and dashboard jobs
- Worker cleanup releases agent-type locks on exit
- `detachAll()` clears all agent-type locks on shutdown

Tests: 24 unit tests for agent-type-lock, concurrency-blocked tests added
to all 3 webhook handler test suites (3868 total tests passing).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@zbigniewsobiecki zbigniewsobiecki merged commit 61ec4a5 into dev Mar 7, 2026
6 checks passed
@zbigniewsobiecki zbigniewsobiecki deleted the feat/agent-type-concurrency-limiting branch March 7, 2026 05:52
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant