7.0 KiB
7.0 KiB
前言
sanic 和 服务之间基于grpc 解绑,一个服务一个grpc
可以参考接口,grpc 最好留有健康校验
grpc demo
为了增强 gRPC 通讯的可靠性,我们可以添加以下功能:
- 服务器健康检查服务
- 客户端连接前检查服务器状态
- 通讯过程中的错误处理和重试机制
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. 增强功能说明
-
健康检查服务
- 添加了标准的 gRPC 健康检查服务
- 客户端可以在执行主要操作前检查服务状态
-
错误处理和重试机制
:
- 客户端现在会捕获
grpc.RpcError和其他异常 - 实现了最大重试次数和重试间隔
- 每次重试前都会检查服务器状态
- 客户端现在会捕获
-
资源管理
- 确保在所有情况下都正确关闭通道
- 使用上下文管理器处理通道生命周期
-
状态反馈
:
- 提供更详细的错误信息
- 记录重试尝试
6. 运行说明
-
安装依赖:
pip install grpcio grpcio-tools -
生成 protobuf 代码:
python -m grpc_tools.protoc -I. --python_out=. --grpc_python_out=. task.proto -
启动服务器:
python server.py -
运行客户端:
python client.py
7. 测试场景
- 服务器未运行
- 客户端会检测到连接失败并重试
- 最终显示所有重试失败
- 服务器运行但健康检查失败
- 可以修改
HealthCheckServicer返回NOT_SERVING状态进行测试 - 客户端会拒绝执行主要操作
- 可以修改
- 网络中断
- 客户端会捕获异常并尝试重试
这个增强版本提供了更健壮的 gRPC 通讯机制,适合生产环境使用。