fix(tunnel): 禁用 idle timeout 默认值,防止空闲 tunnel 连接被断开

Hub 端 proxy_idle_timeout 和 worker_idle_timeout 默认改为 0(禁用),
直连模式 proxy_tunnel.py 同步调整。连接存活检测依赖 PING/PONG 心跳。
This commit is contained in:
fawney19
2026-03-12 10:07:41 +08:00
parent 0ab20be667
commit a8159b7bda
2 changed files with 12 additions and 9 deletions

View File

@@ -23,12 +23,12 @@ struct Args {
#[arg(long, default_value = "0.0.0.0:8085", env = "TUNNEL_HUB_BIND")] #[arg(long, default_value = "0.0.0.0:8085", env = "TUNNEL_HUB_BIND")]
bind: String, bind: String,
/// Proxy-side idle timeout in seconds /// Proxy-side idle timeout in seconds (0 to disable)
#[arg(long, default_value_t = 90, env = "TUNNEL_HUB_PROXY_IDLE_TIMEOUT")] #[arg(long, default_value_t = 0, env = "TUNNEL_HUB_PROXY_IDLE_TIMEOUT")]
proxy_idle_timeout: u64, proxy_idle_timeout: u64,
/// Worker-side idle timeout in seconds (0 to disable) /// Worker-side idle timeout in seconds (0 to disable)
#[arg(long, default_value_t = 120, env = "TUNNEL_HUB_WORKER_IDLE_TIMEOUT")] #[arg(long, default_value_t = 0, env = "TUNNEL_HUB_WORKER_IDLE_TIMEOUT")]
worker_idle_timeout: u64, worker_idle_timeout: u64,
/// Ping interval in seconds (for both sides) /// Ping interval in seconds (for both sides)

View File

@@ -41,8 +41,8 @@ def _get_node_lock(node_id: str) -> asyncio.Lock:
# 单帧最大 64 MB -- AI API 请求体可能包含多张 base64 图片,需要足够余量 # 单帧最大 64 MB -- AI API 请求体可能包含多张 base64 图片,需要足够余量
_MAX_FRAME_SIZE = 64 * 1024 * 1024 _MAX_FRAME_SIZE = 64 * 1024 * 1024
# 默认 WebSocket 空闲超时(秒)-- 需覆盖客户端 stale_timeout(45s) + 重连延迟窗口 # 默认 WebSocket 空闲超时(秒)-- 0 表示禁用(依赖 PING/PONG 心跳检测连接存活)
_DEFAULT_IDLE_TIMEOUT = 90.0 _DEFAULT_IDLE_TIMEOUT = 0.0
# 默认服务端应用层 ping 间隔(秒)-- 与客户端 ping 间隔一致,确保高频心跳 # 默认服务端应用层 ping 间隔(秒)-- 与客户端 ping 间隔一致,确保高频心跳
_DEFAULT_SERVER_PING_INTERVAL = 15.0 _DEFAULT_SERVER_PING_INTERVAL = 15.0
@@ -81,12 +81,12 @@ _SERVER_PING_INTERVAL = _env_float(
_IDLE_TIMEOUT = _env_float( _IDLE_TIMEOUT = _env_float(
"AETHER_PROXY_TUNNEL_SERVER_IDLE_TIMEOUT", "AETHER_PROXY_TUNNEL_SERVER_IDLE_TIMEOUT",
_DEFAULT_IDLE_TIMEOUT, _DEFAULT_IDLE_TIMEOUT,
min_value=30.0, min_value=0.0,
max_value=600.0, max_value=600.0,
) )
# 避免 idle timeout 过小导致 ping 尚未生效就被服务端断开 # 避免 idle timeout 过小导致 ping 尚未生效就被服务端断开0 表示禁用,跳过校验)
if _IDLE_TIMEOUT <= _SERVER_PING_INTERVAL * 2: if _IDLE_TIMEOUT > 0 and _IDLE_TIMEOUT <= _SERVER_PING_INTERVAL * 2:
adjusted_idle = max(_SERVER_PING_INTERVAL * 3, 30.0) adjusted_idle = max(_SERVER_PING_INTERVAL * 3, 30.0)
logger.warning( logger.warning(
"AETHER_PROXY_TUNNEL_SERVER_IDLE_TIMEOUT too low for ping interval, auto-adjust to {}", "AETHER_PROXY_TUNNEL_SERVER_IDLE_TIMEOUT too low for ping interval, auto-adjust to {}",
@@ -196,7 +196,10 @@ async def proxy_tunnel_ws(ws: WebSocket) -> None:
oversized_count = 0 oversized_count = 0
while True: while True:
try: try:
data = await asyncio.wait_for(ws.receive_bytes(), timeout=_IDLE_TIMEOUT) if _IDLE_TIMEOUT > 0:
data = await asyncio.wait_for(ws.receive_bytes(), timeout=_IDLE_TIMEOUT)
else:
data = await ws.receive_bytes()
except asyncio.TimeoutError: except asyncio.TimeoutError:
count = _idle_timeout_counts.get(node_id, 0) + 1 count = _idle_timeout_counts.get(node_id, 0) + 1
_idle_timeout_counts[node_id] = count _idle_timeout_counts[node_id] = count