session-pool-max.test.js
2.92 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
/**
* 机器级会话上限(27-P3C §15.5 第 2 条)。
*
* 为什么要这条守卫:池子里每个 session 是一个**常驻** claude CLI 子进程(约 200-300MB RSS),
* 而 `sessions.size` 在此之前没有任何人过问 —— 一次心跳泄漏攒到过 82 个进程 / 17.5 GB。
* 批 4 又刚把公司级并行放开(单公司上限 20),机器上同时能起多少完全没闸门。
*
* 这里**不起真进程**:直接往 `pool.sessions` 里塞假 session,只验腾位置的判据本身
* (挑最久空闲的、在途的不许动、全在途就抛)。真起进程的路径由 agent-manager 的用例覆盖。
*/
import { describe, it, expect, beforeEach, afterEach } from 'vitest';
import { createRequire } from 'module';
const require_ = createRequire(import.meta.url);
const { SessionPool, SessionPoolFullError, DEFAULT_MAX_SESSIONS } = require_('../../src/core/session-pool');
describe('SessionPool 机器级上限', () => {
let pool;
const OLD = process.env.AGENT_MAX_SESSIONS;
beforeEach(() => { pool = new SessionPool(); });
afterEach(() => {
if (OLD === undefined) delete process.env.AGENT_MAX_SESSIONS;
else process.env.AGENT_MAX_SESSIONS = OLD;
});
/** 塞一个假 session;idleSince 为 null = 在途 */
function seed(key, idleSince) {
pool.sessions.set(key, { key, idleSince, protocol: null, launcher: null, idleTimer: null });
}
it('缺省上限是 12,且从 env 调用时读(不是模块加载时快照)', () => {
expect(DEFAULT_MAX_SESSIONS).toBe(12);
process.env.AGENT_MAX_SESSIONS = '3';
seed('a', 100); seed('b', 200); seed('c', 300);
pool._evictForRoom(); // 3/3 满 → 该腾一个
expect(pool.sessions.size).toBe(2);
expect(pool.sessions.has('a')).toBe(false); // 挑的是最久空闲的那个
});
it('在途的会话不许被腾走', () => {
process.env.AGENT_MAX_SESSIONS = '2';
seed('inflight', null); // 在途
seed('idle', 100);
pool._evictForRoom();
expect(pool.sessions.has('inflight')).toBe(true);
expect(pool.sessions.has('idle')).toBe(false);
});
it('全部在途时抛 SessionPoolFullError —— 不静默放行', () => {
process.env.AGENT_MAX_SESSIONS = '2';
seed('x', null); seed('y', null);
expect(() => pool._evictForRoom()).toThrow(SessionPoolFullError);
// 关键:一个都没被杀(在途的动不得),也没有偷偷放行
expect(pool.sessions.size).toBe(2);
});
it('没满时什么都不做', () => {
process.env.AGENT_MAX_SESSIONS = '5';
seed('a', 100); seed('b', 200);
pool._evictForRoom();
expect(pool.sessions.size).toBe(2);
});
it('非法配置回落缺省,不当成无限', () => {
for (const bad of ['0', '-1', 'abc', '']) {
process.env.AGENT_MAX_SESSIONS = bad;
const { maxSessions } = require_('../../src/core/session-pool');
expect(maxSessions()).toBe(DEFAULT_MAX_SESSIONS);
}
});
});