ai_project_v1/md/grpc.md
2026-01-05 16:29:39 +08:00

7.0 KiB
Raw Blame History

前言

sanic 和 服务之间基于grpc 解绑一个服务一个grpc

可以参考接口grpc 最好留有健康校验

grpc demo

为了增强 gRPC 通讯的可靠性,我们可以添加以下功能:

  1. 服务器健康检查服务
  2. 客户端连接前检查服务器状态
  3. 通讯过程中的错误处理和重试机制

1. 修改 protobuf 定义 (task.proto)

首先添加健康检查服务定义:

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 代码

python -m grpc_tools.protoc -I. --python_out=. --grpc_python_out=. task.proto

3. 增强服务端实现 (server.py)

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)

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. 安装依赖:

    pip install grpcio grpcio-tools
    
  2. 生成 protobuf 代码:

    python -m grpc_tools.protoc -I. --python_out=. --grpc_python_out=. task.proto
    
  3. 启动服务器:

    python server.py
    
  4. 运行客户端:

    python client.py
    

7. 测试场景

  1. 服务器未运行
    • 客户端会检测到连接失败并重试
    • 最终显示所有重试失败
  2. 服务器运行但健康检查失败
    • 可以修改 HealthCheckServicer 返回 NOT_SERVING 状态进行测试
    • 客户端会拒绝执行主要操作
  3. 网络中断
    • 客户端会捕获异常并尝试重试

这个增强版本提供了更健壮的 gRPC 通讯机制,适合生产环境使用。