From 22b9427ca545836b8b178fe598e555793538a73d Mon Sep 17 00:00:00 2001 From: cnbugs Date: Mon, 10 Aug 2026 23:35:30 +0800 Subject: [PATCH] =?UTF-8?q?fix(socks5):=20=E5=8E=BB=E6=8E=89=20=5Frecord?= =?UTF-8?q?=5Fstats=20=E9=87=8C=E5=AF=B9=E5=90=8C=E6=AD=A5=E6=96=B9?= =?UTF-8?q?=E6=B3=95=20add=5Ftraffic=20=E7=9A=84=20await?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 回归: ee8c0b8 引入的 _forward timeout 修复没改 _record_stats, 但烟雾测试里 FakeUserService.add_traffic 误写成 async def 掩盖了 这个 bug。生产机 15:32:08 命中: socks.engine: 记录统计失败: object NoneType can't be used in 'await' gunicorn: [CRITICAL] WORKER TIMEOUT (pid:428355) gunicorn: Error handling request (no URI read) add_traffic 是 UserService 里的 def (非 async), 不能 await。错误地 await 一个 None 返回值会让 worker 在协程上下文里抛 TypeError, 被 _record_stats 的 except 吃掉, 但 worker 进入不可服务状态, 触发 30s gunicorn timeout, 表现就是 40080 实例莫名停止。 注意 log_event 是 async, 仍需 await; add_traffic 是 def, 不 await。 修法: engine/server.py:472 去掉 await, 同步调用 add_traffic tests/smoke_tunnel_timeout.py FakeUserService.add_traffic 改为 def, 模拟真实 UserService 签名, 防止烟雾测试再次漏掉此类 bug 线上已临时恢复 40080 (curl POST /api/instances/2/restart), --- engine/server.py | 6 +++++- tests/smoke_tunnel_timeout.py | 2 +- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/engine/server.py b/engine/server.py index b99cbae..91f8d29 100644 --- a/engine/server.py +++ b/engine/server.py @@ -469,7 +469,11 @@ class ConnectionHandler: # 更新用户流量 if self.username and (self.bytes_in or self.bytes_out): - await self.user_service.add_traffic(self.username, self.bytes_in, self.bytes_out) + # add_traffic 是同步方法(UserService.add_traffic 是 def, 非 async), + # 不能 await。错误地 await 一个 None 返回值会让 worker 在 + # 协程上下文里抛 TypeError, 进而触发 30s gunicorn worker timeout, + # 表现就是"实例莫名停止"——这就是当前线上 40080 实例掉线的根因。 + self.user_service.add_traffic(self.username, self.bytes_in, self.bytes_out) except Exception as e: log.error("记录统计失败: %s", e) diff --git a/tests/smoke_tunnel_timeout.py b/tests/smoke_tunnel_timeout.py index 14ccf00..d51307d 100644 --- a/tests/smoke_tunnel_timeout.py +++ b/tests/smoke_tunnel_timeout.py @@ -32,7 +32,7 @@ class FakeUser: class FakeUserService: def get_user(self, name): return FakeUser() def get_active_connections(self, name): return 0 - async def add_traffic(self, *a, **kw): pass + def add_traffic(self, *a, **kw): pass # 同步, 不要 await (见 services/user_service.py:162) async def log_event(self, *a, **kw): pass