Açıklaması şöyle
Sunucu tarafından fırlatılan exception gRPC tarafından StatusRuntimeException'a çevrilir.By default, gRPC relies heavily on status code for error handling.
Örnek
Şöyle yaparız. Burada ServiceException kendi sınıfımız
Ancak bir problem var. O da hata mesajının kaybolması. Çıktı olarak şunu alırızimport io.grpc.StatusRuntimeException;//Client callpublic Product getProduct(String productId) {Product product = null;try {var request = GetProductRequest.newBuilder().setProductId(productId).build();var productApiServiceBlockingStub = ProductServiceGrpc.newBlockingStub(managedChannel);var response = productApiServiceBlockingStub.getProduct(request);// Map to domain objectproduct = ProductMapper.MAPPER.map(response);} catch (StatusRuntimeException error) {log.error("Error while calling product service, cause {}", error.getMessage());throw new ServiceException(error.getCause());}return product;}
Açıklaması şöyleio.grpc.StatusRuntimeException: UNKNOWN
gRPC wraps our custom exception in StatusRuntimeException and swallows the error message and assigns a default status code UNKNOWN.Bunu düzeltmek için sunucu tarafında şöyle yaparız. Bu sefer onError() metodunu çağırıyoruz.
//Server Product Service APIpublic void getProduct(GetProductRequest request, StreamObserver<GetProductResponse> responseObserver) {try {...responseObserver.onNext(response);responseObserver.onCompleted();} catch (ResourceNotFoundException error) {var status = Status.NOT_FOUND.withDescription(error.getMessage()).withCause(error);responseObserver.onError(status.asException());}}
İstemci tarafında çıktı olarak şunu alırız.
Error while calling product service, cause NOT_FOUND: Product ID not foundHata mesajı düzgün ancak hala exception içindeki getCause() null döner. Sebebinin açıklaması şöyle. Yani io.grpc.Status.withCause() çağrısı orijinal exception'ı göndermiyor.
Create a derived instance of Status with the given cause. However, the cause is not transmitted from server to client.Şöyle yaparız. Bu sefer io.grpc.Metadata kullanılıyor
public void getProduct(GetProductRequest request, StreamObserver<GetProductResponse> responseObserver) {try {...responseObserver.onNext(response);responseObserver.onCompleted();} catch (ResourceNotFoundException error) {Map<String, String> errorMetaData = error.getErrorMetaData();var metadata = new Metadata();errorMetaData.entrySet().stream().forEach(entry ->metadata.put(Metadata.Key.of(entry.getKey(), Metadata.ASCII_STRING_MARSHALLER),entry.getValue()));var statusRuntimeException =Status.NOT_FOUND.withDescription(error.getMessage()).asRuntimeException(metadata);responseObserver.onError(statusRuntimeException);}}
İstemci tarafında şöyle yaparız
} catch (StatusRuntimeException error) {Metadata trailers = error.getTrailers();Set<String> keys = trailers.keys();for (String key : keys) {Metadata.Key<String> k = Metadata.Key.of(key, Metadata.ASCII_STRING_MARSHALLER);log.info("Received key {}, with value {}", k, trailers.get(k));}}
İstemci tarafında çıktı olarak şunu alırız.
Received key Key{name='resource_id'}, with value 32c29935-da42-4801-825a-ac410584c281Received key Key{name='content-type'}, with value application/grpcReceived key Key{name='message'}, with value Product ID not found
- Bütün bunlarlar uğraşmak yerine Google Richer Error Model kullanılabilir.
- Ayrıca sunucu tarafında bir sürü exceptıon yakalayıp io.grpc.Status dönmek yerine io.grpc.ServerInterceptor arayüzünden kalıtıp ortak bir kod yazılabilir.
- Eğer Spring kullanıyorsak aynı şeyi şöyle yaparız
@GrpcAdvicepublic class ExceptionHandler {@GrpcExceptionHandler(ResourceNotFoundException.class)public StatusRuntimeException handleResourceNotFoundException(ResourceNotFoundException
cause) {var errorMetaData = cause.getErrorMetaData();var errorInfo =ErrorInfo.newBuilder().setReason("Resource not found").setDomain("Product").putAllMetadata(errorMetaData).build();var status =com.google.rpc.Status.newBuilder().setCode(Code.NOT_FOUND.getNumber()).setMessage("Resource not found").addDetails(Any.pack(errorInfo)).build();return StatusProto.toStatusRuntimeException(status);}}
Hiç yorum yok:
Yorum Gönder