zl程序教程

您现在的位置是:首页 >  后端

当前栏目

【Python分布式服务框架】gRPC服务异常状态响应

2023-09-11 14:19:33 时间


gRPC服务异常状态响应

gRPC服务中已经为我们申明了状态码,需要在项目中引入grpc.StatusCode文件,我们也只能使用这些状态码进行异常响应,使用未定义的状态码会响应UNKNOWN错误,如果项目中有特殊需求可以考虑定义数据结构来实现。

1. gRPC状态码说明

状态码描述
OK不是错误;是成功的响应。
CANCELLED操作已取消,通常由调用方取消。
UNKNOWN未知错误。
INVALID_ARGUMENT客户端指定了无效参数。
DEADLINE_EXCEEDED操作完成前的截止日期已过期。
NOT_FOUND未找到某些请求的实体,如:文件或目录。
ALREADY_EXISTS我们试图创建的某些实体,例如:文件或目录已经存在。
PERMISSION_DENIED调用方无权执行指定的活动。
UNAUTHENTICATED请求没有有效的身份验证凭据活动。
RESOURCE_EXHAUSTED某些资源已耗尽,可能是每个用户的配额或者可能整个文件系统的空间不足。
FAILED_PRECONDITION操作被拒绝,因为系统未处于状态操作执行所需的。
ABORTED操作中止,通常是由于并发问题,如sequencer检查失败、事务中止等。
UNIMPLEMENTED此服务中未实现或不支持的操作。
INTERNAL表示底层用户期望的一些不变量系统被破坏了。
UNAVAILABLE该服务当前不可用。
DATA_LOSS无法恢复的数据丢失或损坏。

2. 服务中直接使用context响应异常

定义服务

# coding=gbk
from grpc import StatusCode
import greeter_pb2, greeter_pb2_grpc

# 黑名单
DenyUser = ["admin", "administrator"]


class Greeter(greeter_pb2_grpc.GreeterServicer):

    async def SayHello(self, request, context):
        if request.name in DenyUser:
            context.set_code(StatusCode.PERMISSION_DENIED)
            context.set_details("失败,用户权限不足")
            return context
        return greeter_pb2.HelloReply(message=f"Hello {request.name}")

在这里插入图片描述

3. 定义中间件响应异常

使用中间件来获取异常时可能需要自定义一组异常类配合使用,才能使返回更加友好。

定义中间件

# coding=gbk
from grpc import StatusCode
from types import FunctionType
from functools import wraps


def wrapper(method):
    @wraps(method)
    async def wrapped(clf, request, context):
        try:
            return await method(clf, request, context)
        except Exception as e:
            context.set_code(StatusCode.UNKNOWN)
            context.set_details(f'Grpc ERROR [{e}]')
            return context
    return wrapped


class ServiceMiddlewareClass(type):
    def __new__(meta, classname, bases, class_dict):
        new_class_dict = {}

        for attribute_name, attribute in class_dict.items():
            if isinstance(attribute, FunctionType):
                # replace it with a wrapped version
                attribute = wrapper(attribute)

            new_class_dict[attribute_name] = attribute

        return type.__new__(meta, classname, bases, new_class_dict)

定义服务

# coding=gbk
from grpc import StatusCode
import greeter_pb2, greeter_pb2_grpc
from middleware import ServiceMiddlewareClass

# 黑名单
DenyUser = ["admin", "administrator"]


class Greeter(greeter_pb2_grpc.GreeterServicer, metaclass=ServiceMiddlewareClass):

    async def SayHello(self, request, context):
        if request.name in DenyUser:
            raise Exception("失败,用户权限不足")
        return greeter_pb2.HelloReply(message=f"Hello {request.name}")

在这里插入图片描述

4. 成功状态(StatusCode.OK)

需要注意的是,在python实现的gRPC中是不能直接响应OK状态的,如果context被设置为OK状态客户端实际收到的状态是UNKNOWN状态,也需要考虑定义数据结构来实现。