[gRPC] .NET Core 에서 gRPC 오류 처리하는 방법

참고 사이트


gRPC 인터셉터에 의한 서버 예외 처리

  • Interecptor 클래스에는 gRPC 요청을 가로채기 위한 많은 메서드가 있습니다.
  • 여기서는 서버 측 수신 호출에 대한 최상의 방법은 UnaryServerHandler 메서드를 사용하는 것입니다.
  • 다음은 서버 측 인터셉터 코드 예제 입니다.
public class ExceptionInterceptor: Interceptor
{
    private readonly ILogger<ExceptionInterceptor> _logger;

    public ExceptionInterceptor(ILogger<ExceptionInterceptor> logger)
    {
        _logger = logger;
    }

    public override async Task<TResponse> UnaryServerHandler<TRequest, TResponse>(
        TRequest request,
        ServerCallContext context,
        UnaryServerMethod<TRequest, TResponse> continuation)
    {
        try
        {
            return await continuation(request, context);
        }
        catch (Exception exception)
        {
            //... Handle of error logic 
        }
    }
}
  • 다음 단계는 유용한 인터셉터를 IoC 컨테이너에 등록하는 것입니다.
public void ConfigureServices(IServiceCollection services)
{
    // Classic sample..
    services.AddGrpc(
        options =>
        {
            options.Interceptors.Add<ExceptionInterceptor>();
        });

    // CodeFirst sample..
    services.AddCodeFirstGrpc(
        options =>
        {
            options.Interceptors.Add<ExceptionInterceptor>();
        });
}

{% include adsense.html %}

gRPC 클라이언트의 예외 처리

  • 앞서, 서버 측 인터셉터 코드를 작성하였습니다.
  • 하지만 만약 서버가 gRPC 클라이언트 측에 사용자 지정 예외를 throw 하면 어떻게 될까요?
  • 생각과는 다르게 Client 에서는 Server 가 throw 한 사용자 정의 예외를 수신하지 않고, 아래 코드가 예상한 것과는 다르게 동작하지 않게 됩니다.
try
{
    await grpc.SendWeatherForecastGeneratedEvent(new SendWeatherForecastEventCommand());
}
catch(CustomWeatherException exception)
{

}
  • 실제로 Client 에서 받게되는 예외는 사용자 정의 예외가 아닌 RpcException 예외를 받게 됩니다.
  • 서버 측에서 이 예외의 내용을 Status 객체로 지정할 수 있습니다.
  • 상태에는 호출 코드(gRPC 호출 코드) 및 세부 정보에 대한 정보가 포함됩니다.
  • 앞에서 작성했던 서버 측 인터 셉터 코드를 다음과 같이 수정 하였습니다.
public class ExceptionInterceptor:  Interceptor
{
    private readonly ILogger<ExceptionInterceptor> _logger;

    public ExceptionInterceptor(ILogger<ExceptionInterceptor> logger)
    {
        _logger = logger;
    }

    public override async Task<TResponse> UnaryServerHandler<TRequest, TResponse>(
        TRequest request,
        ServerCallContext context,
        UnaryServerMethod<TRequest, TResponse> continuation)
    {
        try
        {
            return await continuation(request, context);
        }
        catch (CustomWeatherException weatherException)
        {
            throw new RpcException(new Status(StatusCode.InvalidArgument, "weather is terrible"));
        }
        catch (Exception exception)
        {
            throw new RpcException(new Status(StatusCode.Internal, exception.ToString()));
        }
    }
}
  • 위 코드를 작성하고, 예외가 발생하게 되면 Client 는 Server 에서 어떤 에러가 발생했는지 정확히 알 수 있습니다.

gRPC 요청 상태 코드 관리

  • gRPC 요청 상태를 코드로 관리할 수 있습니다.
public class ExceptionInterceptor:  Interceptor
{
    private readonly ILogger<ExceptionInterceptor> _logger;

    public ExceptionInterceptor(ILogger<ExceptionInterceptor> logger)
    {
        _logger = logger;
    }

    public override async Task<TResponse> UnaryServerHandler<TRequest, TResponse>(
        TRequest request,
        ServerCallContext context,
        UnaryServerMethod<TRequest, TResponse> continuation)
    {
        try
        {
            return await continuation(request, context);
        }
        catch (CustomWeatherException weatherException)
        {
            var httpContext = context.GetHttpContext();
            httpContext.Response.StatusCode = StatusCodes.Status400BadRequest;

            throw new RpcException(new Status(StatusCode.InvalidArgument, "weather is terrible"));
        }
        catch (Exception exception)
        {
            var httpContext = context.GetHttpContext();
            httpContext.Response.StatusCode = StatusCodes.Status500InternalServerError;

            throw new RpcException(new Status(StatusCode.Internal, exception.ToString()));
        }
    }
}
  • ServerCallContext 인수에서 httpContext 에 대한 정보를 얻을 수 있고 200 상태 코드를 재정의할 수 있습니다.
728x90

이 글을 공유하기

댓글

Designed by JB FACTORY