# 前言 sanic 和 服务之间基于grpc 解绑,一个服务一个grpc 可以参考接口,grpc 最好留有健康校验 # grpc demo 为了增强 gRPC 通讯的可靠性,我们可以添加以下功能: 1. 服务器健康检查服务 2. 客户端连接前检查服务器状态 3. 通讯过程中的错误处理和重试机制 ## 1. 修改 protobuf 定义 (task.proto) 首先添加健康检查服务定义: ```protobuf syntax = "proto3"; package task; service TaskService { rpc ProcessTask (TaskRequest) returns (TaskResponse); } // 添加健康检查服务 service HealthCheck { rpc Check (HealthCheckRequest) returns (HealthCheckResponse); } message HealthCheckRequest { string service = 1; } message HealthCheckResponse { enum ServingStatus { UNKNOWN = 0; SERVING = 1; NOT_SERVING = 2; SERVICE_UNKNOWN = 3; } ServingStatus status = 1; } message TaskRequest { string task_id = 1; string sn = 2; ContentBody content_body = 3; } message ContentBody { string org_code = 1; repeated int32 func_id = 2; string source_url = 3; string push_url = 4; float confidence = 5; repeated ParaList para_list = 6; Invade invade = 7; } message ParaList { int32 func_id = 1; bool para_invade_enable = 2; } message Invade { string invade_file = 1; string camera_para_url = 2; } message TaskResponse { string task_id = 1; bool success = 2; string message = 3; } ``` ## 2. 重新生成 Python 代码 ```bash python -m grpc_tools.protoc -I. --python_out=. --grpc_python_out=. task.proto ``` ## 3. 增强服务端实现 (server.py) ```python from concurrent import futures import grpc import time import task_pb2 import task_pb2_grpc class TaskServiceServicer(task_pb2_grpc.TaskServiceServicer): def ProcessTask(self, request, context): print(f"Received task_id: {request.task_id}") # ... 原有处理逻辑 return task_pb2.TaskResponse( task_id=request.task_id, success=True, message="Task processed successfully" ) class HealthCheckServicer(task_pb2_grpc.HealthCheckServicer): def Check(self, request, context): # 简单实现:总是返回SERVING状态 # 实际应用中可以根据服务状态返回不同值 return task_pb2.HealthCheckResponse( status=task_pb2.HealthCheckResponse.ServingStatus.SERVING ) def serve(): server = grpc.server(futures.ThreadPoolExecutor(max_workers=10)) # 添加服务实现 task_pb2_grpc.add_TaskServiceServicer_to_server(TaskServiceServicer(), server) task_pb2_grpc.add_HealthCheckServicer_to_server(HealthCheckServicer(), server) server.add_insecure_port('[::]:50051') server.start() print("Server started, listening on port 50051...") try: while True: time.sleep(86400) # 保持运行 except KeyboardInterrupt: server.stop(0) if __name__ == '__main__': serve() ``` ## 4. 增强客户端实现 (client.py) ```python import grpc import time import task_pb2 import task_pb2_grpc def check_server_status(channel): try: health_stub = task_pb2_grpc.HealthCheckStub(channel) response = health_stub.Check(task_pb2.HealthCheckRequest(service="TaskService")) return response.status == task_pb2.HealthCheckResponse.ServingStatus.SERVING except grpc.RpcError as e: print(f"Health check failed: {e}") return False def run_with_retry(max_retries=3, delay=5): channel = None retries = 0 while retries < max_retries: try: # 创建通道 channel = grpc.insecure_channel('localhost:50051') # 检查服务器状态 if not check_server_status(channel): raise Exception("Server is not healthy") stub = task_pb2_grpc.TaskServiceStub(channel) # 创建请求消息 request = task_pb2.TaskRequest( task_id="d6118954-a170-4e1c-84bd-ddbd3114b354", sn="8UUXN6S00A0CK7", content_body=task_pb2.ContentBody( org_code="HMZHB", func_id=[101204], source_url="rtmp://222.212.85.86:1935/live/1581F8HGX253S00A05L8", push_url="", confidence=0.4, para_list=[ task_pb2.ParaList( func_id=101204, para_invade_enable=True ) ], invade=task_pb2.Invade( invade_file="meta_data/高压线-0826.geojson", camera_para_url="meta_data/camera_para/hami_camera_para .txt" ) ) ) # 调用远程方法 response = stub.ProcessTask(request) print(f"Response: task_id={response.task_id}, success={response.success}, message={response.message}") return True except grpc.RpcError as e: retries += 1 print(f"RPC error occurred (attempt {retries}/{max_retries}): {e}") if retries < max_retries: print(f"Retrying in {delay} seconds...") time.sleep(delay) except Exception as e: print(f"Error occurred: {e}") retries += 1 if retries < max_retries: print(f"Retrying in {delay} seconds...") time.sleep(delay) finally: if channel: channel.close() print("All retry attempts failed") return False if __name__ == '__main__': run_with_retry() ``` ## 5. 增强功能说明 1. 健康检查服务 - 添加了标准的 gRPC 健康检查服务 - 客户端可以在执行主要操作前检查服务状态 2. 错误处理和重试机制 : - 客户端现在会捕获 `grpc.RpcError` 和其他异常 - 实现了最大重试次数和重试间隔 - 每次重试前都会检查服务器状态 3. 资源管理 - 确保在所有情况下都正确关闭通道 - 使用上下文管理器处理通道生命周期 4. 状态反馈 : - 提供更详细的错误信息 - 记录重试尝试 ## 6. 运行说明 1. 安装依赖: ```bash pip install grpcio grpcio-tools ``` 2. 生成 protobuf 代码: ```bash python -m grpc_tools.protoc -I. --python_out=. --grpc_python_out=. task.proto ``` 3. 启动服务器: ```bash python server.py ``` 4. 运行客户端: ```bash python client.py ``` ## 7. 测试场景 1. 服务器未运行 - 客户端会检测到连接失败并重试 - 最终显示所有重试失败 2. 服务器运行但健康检查失败 - 可以修改 `HealthCheckServicer` 返回 `NOT_SERVING` 状态进行测试 - 客户端会拒绝执行主要操作 3. 网络中断 - 客户端会捕获异常并尝试重试 这个增强版本提供了更健壮的 gRPC 通讯机制,适合生产环境使用。