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

283 lines
7.0 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 前言
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 通讯机制,适合生产环境使用。