基于两个不同proto文件的gRPC双向流转发服务实现问题求助
问题原因分析
- 属性取值错误:遍历得到的
request是第一份proto定义的RequestToFirstServer实例,仅包含x、y两个字段,不存在processedX、processedY属性,代码中直接取request.processedX属于非法取值。 - oneof字段判断逻辑错误:直接用
if request.x判断的话,如果x的取值为合法的0,会被if判断为False,导致逻辑错误,应该用protobuf原生的WhichOneof方法判断当前激活的oneof字段。 - gRPC流式调用逻辑错误:第二服务的
StreamingCall是客户端流式接口,需要传入请求迭代器作为参数,不能直接传入单个请求对象,且不应该在遍历上游请求的循环里重复调用下游流式接口,整个上游流应该对应同一个下游流。 - 响应转换逻辑缺失:下游返回的
ResponseFromSecondServer实例不能直接返回给上游,需要转成第一份proto定义的ResponseForFirstServer实例。
修复后的实现代码
仅需修改FirstProtoService类的StreamingCall方法即可:
class FirstProtoService(fasr_srv.FirstProtoServiceServicer): def StreamingCall(self, request_iterator: fasr.RequestToFirstServer, context): # 构造下游服务的请求迭代器 def second_request_iter(): for request in request_iterator: # 用WhichOneof判断当前激活的oneof字段 active_field = request.WhichOneof("firstStreamingRequest") if active_field == "x": yield sasr.RequestToSecondServer(processedX=request.x) elif active_field == "y": yield sasr.RequestToSecondServer(processedY=request.y) try: # 调用下游流式接口,传入请求迭代器 second_responses = client.StreamingCall(second_request_iter()) # 遍历下游响应,转成上游需要的格式返回 for resp in second_responses: yield fasr.ResponseForFirstServer(someprocessedinformation=resp.computedInformation) except Exception as e: logging.error(f'Exception occurred: {e}.', exc_info=True) # 可选:把异常透传给上游gRPC上下文 context.abort(grpc.StatusCode.INTERNAL, f"Forward error: {str(e)}")
补充优化建议
- 建议把下游gRPC channel的创建逻辑放到合适的位置,避免全局单例channel出现异常后无法自动恢复的问题,可配合gRPC的channel状态监听逻辑实现重连。
- 如果需要透传gRPC的header、trailer、超时取消等上下文信息,可在调用下游接口时把上游的context元信息、超时时间也传递过去。
内容的提问来源于stack exchange,提问作者Bagzhan Zhumash
相关产品推荐
相关产品推荐

