Python中如何解决接口部分请求超时导致整个接口不可用的问题?

1. 语言: python
2. 框架: tornado+gevent 。。我这里是把 tornado 当 flask 来用的
3. 在对于路由 url_pathA的处理里面:我需要向 根据参数来决定 向 urlA 还是 urlB 请求,再根据请求结果响应.设置了超时为 1s
4. 对于 url_pathA,supervisor 起两个进程来处理

现有遇到的问题是 urlA 没有响应,导致只有超时响应。。 而现在其他请求( handler 不是请求 urlA 的请求)也没有响应了,我知道的原因是因为urlA导致的,把请求要urlA的请求干掉响应就正常了,但是这不解决办法,我想知道 这种问题应该怎么解决?


Python中如何解决接口部分请求超时导致整个接口不可用的问题?

9 回复

处理多个请求的时候,应该是并行的啊,你这个怎么感觉成了串行的了。


核心思路: 别让一个慢请求拖垮整个服务。用异步或并发处理,给每个请求单独设超时,一个挂了不影响别的。

具体做法(异步推荐):asyncio + aiohttp,每个请求独立跑,用 asyncio.wait_foraiohttp.ClientTimeout 控制单个请求的超时。

import asyncio
import aiohttp
from aiohttp import ClientTimeout

async def fetch_one(session, url, timeout_sec):
    try:
        # 为单个请求设置超时
        async with session.get(url, timeout=ClientTimeout(total=timeout_sec)) as resp:
            return await resp.text()
    except asyncio.TimeoutError:
        print(f"请求 {url} 超时")
        return None
    except Exception as e:
        print(f"请求 {url} 出错: {e}")
        return None

async def main():
    urls = ["http://api1.example.com", "http://api2.example.com", "http://slow-api.example.com"]
    timeout_per_request = 5  # 每个请求最多等5秒

    async with aiohttp.ClientSession() as session:
        tasks = [fetch_one(session, url, timeout_per_request) for url in urls]
        results = await asyncio.gather(*tasks, return_exceptions=True) # 一个失败不影响其他

    for url, result in zip(urls, results):
        if isinstance(result, Exception):
            print(f"{url}: 失败 - {result}")
        else:
            print(f"{url}: 成功")

if __name__ == "__main__":
    asyncio.run(main())

同步方案备用: 如果非得用同步(比如 requests),上 concurrent.futures.ThreadPoolExecutor,配合 requeststimeout 参数。

import concurrent.futures
import requests

def fetch_one(url, timeout_sec):
    try:
        resp = requests.get(url, timeout=timeout_sec)
        return resp.text
    except requests.exceptions.Timeout:
        print(f"请求 {url} 超时")
        return None
    except Exception as e:
        print(f"请求 {url} 出错: {e}")
        return None

urls = ["http://api1.example.com", "http://api2.example.com", "http://slow-api.example.com"]
timeout_per_request = 5

with concurrent.futures.ThreadPoolExecutor(max_workers=len(urls)) as executor:
    future_to_url = {executor.submit(fetch_one, url, timeout_per_request): url for url in urls}
    for future in concurrent.futures.as_completed(future_to_url):
        url = future_to_url[future]
        try:
            result = future.result()
            print(f"{url}: 完成")
        except Exception as e:
            print(f"{url}: 异常 - {e}")

总结: 核心就是隔离加超时,异步 asyncio 是更现代高效的选择。

什么意思 ?我的意思对于接口 A ,只有两个进程来响应,因为一部分请求需要 1S 来响应,导致其他请求在排队,这种问题应该怎么解决呢?

打 patch 生效了么?用了阻塞的 C 库?

不懂,我用的 request 库。。应该生效了吧。。

要用 tornado 的异步起来

tornado 没有异步 orm ,用不起来了。。而且现在很多都是用 peewee 做 orm 的

不要用 requests ,用 tornado 自己的 AsyncHttpClient 。
不用异步 ORM 不代表完全不能用异步,如果数据库查询成了瓶颈,那就要优化数据库。但你这里很明显是 requests 网络请求阻塞了线程啦。

直接使用异步操作吧。这样就不会阻塞当前线程了。

回到顶部