FastAPI中gRPC客户端依赖注入合理性确认及报错排查
问题解答
1. 依赖注入gRPC Stub是否为正确方案?
是合理的方案,和FastAPI管理数据库会话的思路一致,核心优势:
- 集中管理gRPC连接的创建与销毁,避免重复代码
- 保证通道资源在请求结束后正确释放
- 统一配置gRPC客户端参数(如代理、超时等)
更推荐注入封装后的GRPCClient实例而非原始Stub,这样能把gRPC调用的业务逻辑(序列化、请求构造等)封装在客户端类中,路由层只需调用封装好的方法,代码更清晰易维护。
2. 报错AttributeError: 'CalculationStub' object has no attribute 'get_result'的原因
你的get_stub生成器返回的是client.stub(即CalculationStub实例),但get_result方法是定义在GRPCClient类中的,并非CalculationStub的方法。路由中拿到的是原始gRPC Stub,自然没有这个自定义方法。
3. 修正方案
方案一:修改依赖注入返回GRPCClient实例(推荐)
调整依赖函数的名称和返回值:
def get_grpc_client(): client = GRPCClient() try: yield client finally: client.channel.close()
路由中使用封装后的客户端实例:
@router.post("/", status_code=status.HTTP_201_CREATED) def hello(client = Depends(get_grpc_client)): dic = dict(r=dict(a=1,b=3,c=5),l=dict(a=20,b=3,c=0), num=1) result = client.get_result(dic) return result
方案二:复用gRPC通道(性能优化)
gRPC通道本身是线程安全的,无需每次请求都创建新通道。通过FastAPI生命周期事件管理全局通道,减少连接开销:
# 全局通道变量 grpc_channel = None @app.on_event("startup") def startup_event(): global grpc_channel grpc_channel = grpc.insecure_channel( '111.11.1.11:1111', options=(('grpc.enable_http_proxy', 0),) ) @app.on_event("shutdown") def shutdown_event(): global grpc_channel if grpc_channel: grpc_channel.close() class GRPCClient: def __init__(self, channel): self.stub = CalculationStub(channel) def get_result(self, json_data): bytes_text = bytes(json.dumps(json_data), encoding="UTF-8") binary_iterator = generate_text_iterator(bytes_text) response = self.stub.GetResult(binary_iterator) return response def get_grpc_client(): # 复用全局通道创建客户端 return GRPCClient(grpc_channel)
路由使用方式与方案一一致。
内容的提问来源于stack exchange,提问作者giwony
相关产品推荐
相关产品推荐

