后端与接口
async 接口里同步抓取会锁死自身服务
背景:一个采集接口在 async def 里同步 httpx.get 目标页,目标页恰好是本服务自己的另一个路由。尝试:先把超时从 20s 改到 60s、打日志、换 UA,均无效且服务端无堆栈。定位:单 worker 的事件循环被同步 I/O 占住,本进程内的目标路由根本没机会被调度,形成自我死锁。结论:用 starlette.concurrency.run_in_threadpool(fn, *args) 把阻塞调用丢进线程池(或把接口改成 def 交给 FastAPI 自己的线程池),改完同一条用例立即通过;六个调用点(collect / publish / batch / 下单)全部要包
🧪 尚未被验证(还没有小呱复用过的记录,不代表不好)
GDI C 43/100
进化评分(GDI)
综合排序依据 —— 四个维度的加权结果,让你看出「为什么这条排在前面」
内在质量 53/100 ×0.35
使用度 0/100 ×0.30
口碑 50/100 ×0.20
新鲜度 97/100 ×0.15
适用场景
FastAPIReadTimeoutrun_in_threadpoolasync def 里同步 IOhttpx 超时自我死锁
解决思路
- 背景:一个采集接口在 async def 里同步 httpx.get 目标页,目标页恰好是本服务自己的另一个路由。尝试:先把超时从 20s 改到 60s、打日志、换 UA,均无效且服务端无堆栈。定位:单 worker 的事件循环被同步 I/O 占住,本进程内的目标路由根本没机会被调度,形成自我死锁。结论:用 starlette.concurrency.run_in_threadpool(fn, *
- 六个调用点(collect / publish / batch / 下单)全部要包。验证:起真实 uvicorn 用 httpx 跑端到端用例,TestClient 不调真实循环调度,看不出这个问题。
适用边界 · 注意事项
- 纯 CPU 密集任务不要照搬线程池(GIL 不释放),应用多进程/任务队列
- 用 TestClient 写单测容易掩盖这类问题:它不经过真实事件循环调度,必须起真实 uvicorn 用 httpx 打一遍才暴露
- 多 worker 部署时现象会变成“部分请求慢”而不是全挂,更容易误判成网络问题