feat(framework): net 候选服务器轮询策略
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,21 @@
|
|||||||
|
/** 候选服务器轮询。docs/protocol/01 §7.3。 */
|
||||||
|
export class ReconnectPolicy {
|
||||||
|
private servers: string[];
|
||||||
|
private index = 0;
|
||||||
|
private failCount = 0;
|
||||||
|
constructor(servers: string | string[], private rotateEvery: number) {
|
||||||
|
this.servers = Array.isArray(servers) ? servers.slice() : [servers];
|
||||||
|
}
|
||||||
|
current(): string { return this.servers[this.index]; }
|
||||||
|
/** 记一次连接失败,按 rotateEvery 轮换候选,返回新的 current。 */
|
||||||
|
onFailure(): string {
|
||||||
|
this.failCount++;
|
||||||
|
if (this.servers.length > 1 && this.failCount % this.rotateEvery === 0) {
|
||||||
|
this.index = (this.index + 1) % this.servers.length;
|
||||||
|
}
|
||||||
|
return this.current();
|
||||||
|
}
|
||||||
|
reset(): void { this.failCount = 0; }
|
||||||
|
/** 服务器切换指令:改用指定地址。docs/protocol/01 §7.4。 */
|
||||||
|
setCurrent(server: string): void { this.servers = [server]; this.index = 0; this.failCount = 0; }
|
||||||
|
}
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
import { test } from 'node:test';
|
||||||
|
import assert from 'node:assert/strict';
|
||||||
|
import { ReconnectPolicy } from '../../YouleNexus/assets/framework/net/reconnect.ts';
|
||||||
|
|
||||||
|
test('单服务器:失败永不轮换', () => {
|
||||||
|
const p = new ReconnectPolicy('ws://a', 3);
|
||||||
|
assert.equal(p.current(), 'ws://a');
|
||||||
|
for (let i = 0; i < 10; i++) assert.equal(p.onFailure(), 'ws://a');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('多服务器:每 3 次失败轮换下一个', () => {
|
||||||
|
const p = new ReconnectPolicy(['ws://a', 'ws://b', 'ws://c'], 3);
|
||||||
|
assert.equal(p.onFailure(), 'ws://a'); // 1
|
||||||
|
assert.equal(p.onFailure(), 'ws://a'); // 2
|
||||||
|
assert.equal(p.onFailure(), 'ws://b'); // 3 → 轮换
|
||||||
|
assert.equal(p.onFailure(), 'ws://b'); // 4
|
||||||
|
assert.equal(p.onFailure(), 'ws://b'); // 5
|
||||||
|
assert.equal(p.onFailure(), 'ws://c'); // 6 → 轮换
|
||||||
|
});
|
||||||
|
|
||||||
|
test('reset 清零失败计数', () => {
|
||||||
|
const p = new ReconnectPolicy(['ws://a', 'ws://b'], 3);
|
||||||
|
p.onFailure(); p.onFailure();
|
||||||
|
p.reset();
|
||||||
|
assert.equal(p.onFailure(), 'ws://a'); // 计数从 1 起,未到 3,不轮换
|
||||||
|
});
|
||||||
|
|
||||||
|
test('setCurrent 切换到指定服务器(服务器切换指令)', () => {
|
||||||
|
const p = new ReconnectPolicy(['ws://a', 'ws://b'], 3);
|
||||||
|
p.setCurrent('ws://room1');
|
||||||
|
assert.equal(p.current(), 'ws://room1');
|
||||||
|
});
|
||||||
Reference in New Issue
Block a user