You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Azure虚拟机上FastAPI调用AWS Bedrock闲置后超时问题

Azure VM上FastAPI调用AWS Bedrock闲置后首次请求超时问题解决方案

问题概述

在Azure虚拟机部署的FastAPI应用中,通过langchain-aws的ChatBedrockConverse调用AWS Bedrock服务时,闲置数分钟后的首次请求会触发botocore.exceptions.ReadTimeoutError(达到默认60秒超时限制),后续请求可立即成功,直到下一次闲置期。已验证:

  • 相同容器化应用在AWS EC2实例上运行无此问题
  • 同一Azure VM上,使用AWS CLI、直接基于botocore的Python脚本调用Bedrock均正常,仅长期运行的FastAPI/Uvicorn进程内出现该问题

错误栈:

File "/app/.venv/lib/python3.13/site-packages/botocore/endpoint.py", line 383, in _send
  return self.http_session.send(request)
         ~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^
File "/app/.venv/lib/python3.13/site-packages/botocore/httpsession.py", line 501, in send
  raise ReadTimeoutError(endpoint_url=request.url, error=e)
botocore.exceptions.ReadTimeoutError: Read timeout on endpoint URL: "https://bedrock-runtime.us-east-1.amazonaws.com/model/us.anthropic.claude-3-5-sonnet-20241022-v2%3A0/converse"

问题根源

问题出在长期运行的Uvicorn进程中,botocore维护的HTTP连接池内的闲置连接被Azure网络或AWS端主动关闭,但客户端未检测到连接失效,复用了无效连接。当应用闲置时,TCP连接长时间无数据传输,触发网络层超时断开(如Azure负载均衡或AWS端节点的闲置超时机制),但botocore连接池仍认为该连接可用,首次请求复用无效连接时就会超时;后续请求会创建新的有效连接,因此恢复正常。

解决方案

1. 配置连接池闲置超时,主动回收旧连接

修改LangChainBedrockClient中的botocore.Config,添加闲置连接超时设置,让客户端主动关闭超过阈值的闲置连接,避免复用无效连接:

class LangChainBedrockClient:
    def __init__(self, region='us-east-1', timeout=60):
        self.region = region
        self.timeout = timeout
        self.model_id = 'us.anthropic.claude-3-5-sonnet-20241022-v2:0' 
        self.config = Config(
            region_name=region,
            read_timeout=timeout,
            connect_timeout=timeout,
            retries={'max_attempts': 5, 'mode': 'adaptive'},
            max_pool_connections=10,
            tcp_keepalive=True,
            # 设置闲置连接超时为5分钟(300秒),小于Azure/AWS的默认闲置断开时间
            idle_connection_timeout=300
        )
        self.llm = ChatBedrockConverse(model=self.model_id, region_name=region, config=self.config, temperature=0.1, max_tokens=4096, top_p=0.9)
        logger.info(f"Initialized LangChain BedrockConverse client with model: {self.model_id}")

2. 禁用连接复用(低并发场景适用)

如果应用并发量不高,可直接禁用连接复用,每次请求创建新连接:

class LangChainBedrockClient:
    def __init__(self, region='us-east-1', timeout=60):
        self.region = region
        self.timeout = timeout
        self.model_id = 'us.anthropic.claude-3-5-sonnet-20241022-v2:0' 
        self.config = Config(
            region_name=region,
            read_timeout=timeout,
            connect_timeout=timeout,
            retries={'max_attempts': 5, 'mode': 'adaptive'},
            # 禁用连接池复用
            pool_maxsize=1,
            pool_connections=1,
            keepalive=False
        )
        self.llm = ChatBedrockConverse(model=self.model_id, region_name=region, config=self.config, temperature=0.1, max_tokens=4096, top_p=0.9)
        logger.info(f"Initialized LangChain BedrockConverse client with model: {self.model_id}")

3. 实现请求前连接健康检查

自定义botocore的HTTP会话,在超时后自动清空连接池并重试:

import boto3
from botocore.httpsession import URLLib3Session
from botocore.exceptions import ReadTimeoutError

class HealthCheckedSession(URLLib3Session):
    def send(self, request):
        try:
            return super().send(request)
        except ReadTimeoutError:
            # 超时后清空连接池,下次请求创建新连接
            self._adapter.clear()
            return super().send(request)

class LangChainBedrockClient:
    def __init__(self, region='us-east-1', timeout=60):
        self.region = region
        self.timeout = timeout
        self.model_id = 'us.anthropic.claude-3-5-sonnet-20241022-v2:0' 
        self.config = Config(
            region_name=region,
            read_timeout=timeout,
            connect_timeout=timeout,
            retries={'max_attempts': 5, 'mode': 'adaptive'}
        )
        # 使用自定义会话创建Bedrock客户端
        session = boto3.Session(region_name=region)
        bedrock_runtime = session.client('bedrock-runtime', config=self.config)
        bedrock_runtime._endpoint.http_session = HealthCheckedSession()
        self.llm = ChatBedrockConverse(model=self.model_id, client=bedrock_runtime, temperature=0.1, max_tokens=4096, top_p=0.9)
        logger.info(f"Initialized LangChain BedrockConverse client with model: {self.model_id}")

4. 定期预热连接,避免闲置断开

利用现有/warmup端点,添加定时线程定期发送测试请求,保持连接池活跃:

import threading
import time

def periodic_warmup():
    while True:
        logger.info("Performing periodic warmup to keep connections alive")
        # 发送简单测试请求
        bedrock_client.send_message(message="warmup")
        # 每隔4分钟执行一次(小于闲置超时时间)
        time.sleep(240)

# 应用启动时启动预热线程
if __name__ == "__main__":
    import sys
    if len(sys.argv) > 1 and sys.argv[1] == 'client':
        simulate_requests()
    else:
        warmup_thread = threading.Thread(target=periodic_warmup, daemon=True)
        warmup_thread.start()
        print("To run the FastAPI server, use the command:\nuvicorn main:app --reload --port 8004")
        print("\nTo run the client simulation in a separate terminal, use the command:\npython main.py client")

验证建议

  1. 部署修改后的应用,闲置5分钟以上发起首次请求,检查是否仍超时
  2. 观察后续请求的响应时间,确认恢复正常
  3. 查看日志中的连接相关信息,验证连接池配置是否生效

内容的提问来源于stack exchange,提问作者Surya

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.12 18:08:10