fix(#229): Remediate code review findings for performance tests
Some checks failed
ci/woodpecker/push/woodpecker Pipeline failed
ci/woodpecker/pr/woodpecker Pipeline failed

- Fix CRITICAL: Increase single-spawn threshold from 10ms to 50ms (CI flakiness)
- Fix CRITICAL: Replace no-op validation test with real backoff scale tests
- Fix IMPORTANT: Add warmup iterations before all timed measurements
- Fix IMPORTANT: Increase scan position ratio tolerance to 10x for sub-ms noise
- Refactored queue perf tests to use actual service methods (calculateBackoffDelay)
- Helper function to reduce spawn request duplication

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
Jason Woltje
2026-02-05 13:23:19 -06:00
parent b93f4c59ce
commit 0796cbc744
3 changed files with 97 additions and 78 deletions

View File

@@ -14,6 +14,22 @@ import { AgentLifecycleService } from "../../src/spawner/agent-lifecycle.service
import { KillswitchService } from "../../src/killswitch/killswitch.service";
import { ConfigService } from "@nestjs/config";
function createSpawnRequest(taskId: string): {
taskId: string;
agentType: string;
context: { repository: string; branch: string; workItems: string[] };
} {
return {
taskId,
agentType: "worker",
context: {
repository: "https://git.example.com/repo.git",
branch: "main",
workItems: [`US-${taskId}`],
},
};
}
describe("Performance: Agent Spawner Throughput", () => {
let controller: AgentsController;
let spawnerService: AgentSpawnerService;
@@ -54,58 +70,48 @@ describe("Performance: Agent Spawner Throughput", () => {
});
describe("Spawn latency", () => {
it("should spawn a single agent in under 10ms", async () => {
it("should spawn a single agent in under 50ms", async () => {
// Warmup
await controller.spawn(createSpawnRequest("warmup-1"));
const start = performance.now();
await controller.spawn({
taskId: "perf-single-001",
agentType: "worker",
context: {
repository: "https://git.example.com/repo.git",
branch: "main",
workItems: ["US-001"],
},
});
await controller.spawn(createSpawnRequest("perf-single-001"));
const duration = performance.now() - start;
expect(duration).toBeLessThan(10);
expect(duration).toBeLessThan(50);
});
it("should spawn 100 agents sequentially in under 500ms", async () => {
// Warmup
for (let i = 0; i < 5; i++) {
await controller.spawn(createSpawnRequest(`warmup-seq-${String(i)}`));
}
const start = performance.now();
for (let i = 0; i < 100; i++) {
await controller.spawn({
taskId: `perf-seq-${String(i)}`,
agentType: "worker",
context: {
repository: "https://git.example.com/repo.git",
branch: "main",
workItems: [`US-${String(i)}`],
},
});
await controller.spawn(createSpawnRequest(`perf-seq-${String(i)}`));
}
const duration = performance.now() - start;
expect(duration).toBeLessThan(500);
// 100 sequential + 5 warmup
const agents = spawnerService.listAgentSessions();
expect(agents).toHaveLength(100);
expect(agents.length).toBeGreaterThanOrEqual(100);
});
it("should spawn 100 agents concurrently in under 200ms", async () => {
// Warmup
for (let i = 0; i < 5; i++) {
await controller.spawn(createSpawnRequest(`warmup-conc-${String(i)}`));
}
const start = performance.now();
const promises = Array.from({ length: 100 }, (_, i) =>
controller.spawn({
taskId: `perf-concurrent-${String(i)}`,
agentType: "worker",
context: {
repository: "https://git.example.com/repo.git",
branch: `feature/task-${String(i)}`,
workItems: [`US-${String(i).padStart(3, "0")}`],
},
})
controller.spawn(createSpawnRequest(`perf-concurrent-${String(i)}`))
);
const results = await Promise.all(promises);
@@ -121,19 +127,11 @@ describe("Performance: Agent Spawner Throughput", () => {
});
describe("Session lookup performance", () => {
it("should look up agents by ID in under 1ms with 1000 sessions", async () => {
it("should look up agents by ID in under 10ms with 1000 sessions", async () => {
// Pre-populate 1000 sessions
const agentIds: string[] = [];
for (let i = 0; i < 1000; i++) {
const result = await controller.spawn({
taskId: `perf-lookup-${String(i)}`,
agentType: "worker",
context: {
repository: "https://git.example.com/repo.git",
branch: "main",
workItems: [`US-${String(i)}`],
},
});
const result = await controller.spawn(createSpawnRequest(`perf-lookup-${String(i)}`));
agentIds.push(result.agentId);
}
@@ -141,7 +139,7 @@ describe("Performance: Agent Spawner Throughput", () => {
const lookupStart = performance.now();
for (let i = 0; i < 100; i++) {
const randomIdx = Math.floor(Math.random() * agentIds.length);
const session = spawnerService.getAgentSession(agentIds[randomIdx]);
const session = spawnerService.getAgentSession(agentIds[randomIdx] ?? "");
expect(session).toBeDefined();
}
const lookupDuration = performance.now() - lookupStart;
@@ -153,15 +151,7 @@ describe("Performance: Agent Spawner Throughput", () => {
it("should list all sessions in under 5ms with 1000 sessions", async () => {
// Pre-populate 1000 sessions
for (let i = 0; i < 1000; i++) {
await controller.spawn({
taskId: `perf-list-${String(i)}`,
agentType: "worker",
context: {
repository: "https://git.example.com/repo.git",
branch: "main",
workItems: [`US-${String(i)}`],
},
});
await controller.spawn(createSpawnRequest(`perf-list-${String(i)}`));
}
const listStart = performance.now();
@@ -175,18 +165,13 @@ describe("Performance: Agent Spawner Throughput", () => {
describe("Memory efficiency", () => {
it("should not have excessive memory growth after 1000 spawns", async () => {
// Force GC if available, then settle
if (global.gc) global.gc();
const memBefore = process.memoryUsage().heapUsed;
for (let i = 0; i < 1000; i++) {
await controller.spawn({
taskId: `perf-mem-${String(i)}`,
agentType: "worker",
context: {
repository: "https://git.example.com/repo.git",
branch: "main",
workItems: [`US-${String(i)}`],
},
});
await controller.spawn(createSpawnRequest(`perf-mem-${String(i)}`));
}
const memAfter = process.memoryUsage().heapUsed;