fix: 防止网关并发连接并优化重连逻辑
This commit is contained in:
@@ -48,9 +48,15 @@ export async function startGateway(ctx: GatewayContext): Promise<void> {
|
|||||||
let lastSeq: number | null = null;
|
let lastSeq: number | null = null;
|
||||||
let lastConnectTime: number = 0; // 上次连接成功的时间
|
let lastConnectTime: number = 0; // 上次连接成功的时间
|
||||||
let quickDisconnectCount = 0; // 连续快速断开次数
|
let quickDisconnectCount = 0; // 连续快速断开次数
|
||||||
|
let isConnecting = false; // 防止并发连接
|
||||||
|
let reconnectTimer: ReturnType<typeof setTimeout> | null = null; // 重连定时器
|
||||||
|
|
||||||
abortSignal.addEventListener("abort", () => {
|
abortSignal.addEventListener("abort", () => {
|
||||||
isAborted = true;
|
isAborted = true;
|
||||||
|
if (reconnectTimer) {
|
||||||
|
clearTimeout(reconnectTimer);
|
||||||
|
reconnectTimer = null;
|
||||||
|
}
|
||||||
cleanup();
|
cleanup();
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -76,11 +82,18 @@ export async function startGateway(ctx: GatewayContext): Promise<void> {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 取消已有的重连定时器
|
||||||
|
if (reconnectTimer) {
|
||||||
|
clearTimeout(reconnectTimer);
|
||||||
|
reconnectTimer = null;
|
||||||
|
}
|
||||||
|
|
||||||
const delay = customDelay ?? getReconnectDelay();
|
const delay = customDelay ?? getReconnectDelay();
|
||||||
reconnectAttempts++;
|
reconnectAttempts++;
|
||||||
log?.info(`[qqbot:${account.accountId}] Reconnecting in ${delay}ms (attempt ${reconnectAttempts})`);
|
log?.info(`[qqbot:${account.accountId}] Reconnecting in ${delay}ms (attempt ${reconnectAttempts})`);
|
||||||
|
|
||||||
setTimeout(() => {
|
reconnectTimer = setTimeout(() => {
|
||||||
|
reconnectTimer = null;
|
||||||
if (!isAborted) {
|
if (!isAborted) {
|
||||||
connect();
|
connect();
|
||||||
}
|
}
|
||||||
@@ -88,6 +101,13 @@ export async function startGateway(ctx: GatewayContext): Promise<void> {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const connect = async () => {
|
const connect = async () => {
|
||||||
|
// 防止并发连接
|
||||||
|
if (isConnecting) {
|
||||||
|
log?.debug?.(`[qqbot:${account.accountId}] Already connecting, skip`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
isConnecting = true;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
cleanup();
|
cleanup();
|
||||||
|
|
||||||
@@ -349,6 +369,7 @@ export async function startGateway(ctx: GatewayContext): Promise<void> {
|
|||||||
|
|
||||||
ws.on("open", () => {
|
ws.on("open", () => {
|
||||||
log?.info(`[qqbot:${account.accountId}] WebSocket connected`);
|
log?.info(`[qqbot:${account.accountId}] WebSocket connected`);
|
||||||
|
isConnecting = false; // 连接完成,释放锁
|
||||||
reconnectAttempts = 0; // 连接成功,重置重试计数
|
reconnectAttempts = 0; // 连接成功,重置重试计数
|
||||||
lastConnectTime = Date.now(); // 记录连接时间
|
lastConnectTime = Date.now(); // 记录连接时间
|
||||||
});
|
});
|
||||||
@@ -485,6 +506,7 @@ export async function startGateway(ctx: GatewayContext): Promise<void> {
|
|||||||
|
|
||||||
ws.on("close", (code, reason) => {
|
ws.on("close", (code, reason) => {
|
||||||
log?.info(`[qqbot:${account.accountId}] WebSocket closed: ${code} ${reason.toString()}`);
|
log?.info(`[qqbot:${account.accountId}] WebSocket closed: ${code} ${reason.toString()}`);
|
||||||
|
isConnecting = false; // 释放锁
|
||||||
|
|
||||||
// 检测是否是快速断开(连接后很快就断了)
|
// 检测是否是快速断开(连接后很快就断了)
|
||||||
const connectionDuration = Date.now() - lastConnectTime;
|
const connectionDuration = Date.now() - lastConnectTime;
|
||||||
@@ -492,12 +514,17 @@ export async function startGateway(ctx: GatewayContext): Promise<void> {
|
|||||||
quickDisconnectCount++;
|
quickDisconnectCount++;
|
||||||
log?.info(`[qqbot:${account.accountId}] Quick disconnect detected (${connectionDuration}ms), count: ${quickDisconnectCount}`);
|
log?.info(`[qqbot:${account.accountId}] Quick disconnect detected (${connectionDuration}ms), count: ${quickDisconnectCount}`);
|
||||||
|
|
||||||
// 如果连续快速断开超过阈值,清除 session 重新 identify
|
// 如果连续快速断开超过阈值,清除 session 并等待更长时间
|
||||||
if (quickDisconnectCount >= MAX_QUICK_DISCONNECT_COUNT) {
|
if (quickDisconnectCount >= MAX_QUICK_DISCONNECT_COUNT) {
|
||||||
log?.info(`[qqbot:${account.accountId}] Too many quick disconnects, clearing session to re-identify`);
|
log?.info(`[qqbot:${account.accountId}] Too many quick disconnects, clearing session and waiting longer`);
|
||||||
sessionId = null;
|
sessionId = null;
|
||||||
lastSeq = null;
|
lastSeq = null;
|
||||||
quickDisconnectCount = 0;
|
quickDisconnectCount = 0;
|
||||||
|
// 快速断开太多次,等待更长时间再重连
|
||||||
|
if (!isAborted && code !== 1000) {
|
||||||
|
scheduleReconnect(RATE_LIMIT_DELAY);
|
||||||
|
}
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// 连接持续时间够长,重置计数
|
// 连接持续时间够长,重置计数
|
||||||
@@ -518,6 +545,7 @@ export async function startGateway(ctx: GatewayContext): Promise<void> {
|
|||||||
});
|
});
|
||||||
|
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
|
isConnecting = false; // 释放锁
|
||||||
const errMsg = String(err);
|
const errMsg = String(err);
|
||||||
log?.error(`[qqbot:${account.accountId}] Connection failed: ${err}`);
|
log?.error(`[qqbot:${account.accountId}] Connection failed: ${err}`);
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user