Résumer les conseils de gestion des erreurs lors de l'implémentation d'un client gRPC dans Ruby
tl;dr
GRPC :: BadStatus
, alors assurez-vous de la resuce lors d'un appel gRPC.
--Si vous voulez obtenir les informations détaillées de l'exception capturée, transtypez-les en type Google :: Rpc :: Status
avec la méthode to_rpc_status
.La réponse à l'appel gRPC est essentiellement l'un des codes suivants.
enum Code {
OK = 0;
CANCELLED = 1;
UNKNOWN = 2;
INVALID_ARGUMENT = 3;
DEADLINE_EXCEEDED = 4;
NOT_FOUND = 5;
ALREADY_EXISTS = 6;
PERMISSION_DENIED = 7;
UNAUTHENTICATED = 16;
RESOURCE_EXHAUSTED = 8;
FAILED_PRECONDITION = 9;
ABORTED = 10;
OUT_OF_RANGE = 11;
UNIMPLEMENTED = 12;
INTERNAL = 13;
UNAVAILABLE = 14;
DATA_LOSS = 15;
}
https://github.com/googleapis/googleapis/blob/master/google/rpc/code.proto En tant qu'implémentation du serveur gRPC, je pense que le système normal renvoie le code OK (0), et s'il y a une erreur, il renvoie un code (1 à 15) autre que OK.
Lorsqu'une erreur est renvoyée, il semble qu'une exception soit générée du côté du gem grpc sans permission, et le programme s'arrêtera là à moins que le sauvetage ne soit effectué. Par conséquent, il est nécessaire de récupérer l'exception avec sauvetage comme suit.
begin
stub = HogeProto::HogeService::Stub.new("localhost:50051", :this_channel_is_insecure)
res = stub.get_hoge
rescue GRPC::BadStatus => ex
res = "error"
rescue ex
res = "unexpected error"
end
En regardant la classe d'erreur définie par gem, toutes les classes sont BadStatus
Vous pouvez voir qu'il hérite de la classe.
En fait, si vous regardez l'arborescence d'héritage de l'exception qui s'est produite
p ex.class.ancestors
# =>[GRPC::InvalidArgument, GRPC::BadStatus, GRPC::Core::StatusCodes, StandardError, Exception...
En gros, vous pouvez attraper toutes les exceptions avec GRPC :: BadStatus
.
Si vous voulez traiter plus en détail, vous pouvez le récupérer dans des unités comme GRPC :: InvalidArgument
.
Extrayons les informations de l'exception capturée.
L'instance BadStatus
a quatre champs.
https://github.com/grpc/grpc/blob/d48d39c4324f06a6da24bb4f67e8ef21166ba65b/src/ruby/lib/grpc/errors.rb#L49-L52
Par exemple, créez une erreur à partir du serveur gRPC implémenté dans Go comme suit et renvoyez-la à ruby.
server.go
func (s *Server) set_name(name string) {
st := status.New(codes.InvalidArgument, "invalid username")
return nil, st.Err()
}
client.rb
begin
stub = HogeProto::HogeService::Stub.new("localhost:50051", :this_channel_is_insecure)
res = stub.set_name("hoge1")
rescue GRPC::BadStatus => ex
p ex.code # => 3
p ex.message # => "3:invalid username"
p ex.details # => "invalid username"
res = "error"
rescue ex
res = "unexpected error"
end
J'ai reçu les messages Code d'état «3» et «Nom d'utilisateur invalide» «
Jusqu'à ce qui précède, le code d'état et le message d'erreur ont été obtenus. Cependant, en le faisant, je pense que les détails de l'erreur sont souvent utilisés pour transmettre les détails de l'erreur. https://christina04.hatenablog.com/entry/grpc-error-details https://grpc.io/docs/guides/error/#richer-error-model
Si vous voulez des informations plus détaillées, y compris des détails d'erreur, vous pouvez obtenir des informations plus détaillées en utilisant la méthode to_rpc_status
.
La mise en œuvre de to_rpc_status
est la suivante, ce qui vous permet de convertir en type Google :: Rpc :: Status
et de récupérer des informations détaillées, y compris les métadonnées de la bande-annonce.
https://github.com/grpc/grpc/blob/d48d39c4324f06a6da24bb4f67e8ef21166ba65b/src/ruby/lib/grpc/errors.rb#L63-L75
J'ai ajouté des détails d'erreur à l'exemple d'implémentation précédent.
server.go
func (s *Server) set_name(name string) {
st := status.New(codes.InvalidArgument, "invalid username")
//Créer et définir des informations détaillées sur l'erreur
desc := "The username must only contain alphanumeric characters"
v := &errdetails.BadRequest_FieldViolation{
Field: "username",
Description: desc,
}
br := &errdetails.BadRequest{}
br.FieldViolations = append(br.FieldViolations, v)
st, _ = st.WithDetails(br)
return nil, st.Err()
}
client.rb
require 'google/rpc/error_details_pb'
begin
stub = HogeProto::HogeService::Stub.new("localhost:50051", :this_channel_is_insecure)
res = stub.set_name("hoge1")
rescue GRPC::BadStatus => ex
p ex.class # => GRPC::InvalidArgument
p ex.to_rpc_status.class # => Google::Rpc::Status
p ex.to_rpc_status # => <Google::Rpc::Status: code: 3, message: "invalid username", details: [<Google::Protobuf::Any: type_url: "type.googleapis.com/google.rpc.BadRequest", value: "\nC\n\tusername\x126The username must only contain alphanumeric characters">]>
ex.to_rpc_status.details.each do |detail|
p detail.type_url # => "type.googleapis.com/google.rpc.BadRequest"
p detail.unpack(Google::Rpc::BadRequest) # => <Google::Rpc::BadRequest: field_violations: [<Google::Rpc::BadRequest::FieldViolation: field: "username", description: "The username must only contain alphanumeric characters">]>
end
res = "error"
rescue ex
res = "unexpected error"
end
Détails notables details: [<Google :: Protobuf :: Any: type_url:" type.googleapis.com/google.rpc.BadRequest ", valeur:" \ nC \ n \ tusername2 \ x126Le nom d'utilisateur ne doit contenir que des caractères alphanumériques La partie caractères ">]
.
Il s'agit des données de détails d'erreur envoyées sous forme de bande-annonce, et il y a des données de type Google :: Protobuf :: Any
et des données de valeur.
Vous pouvez définir plusieurs détails d'erreur et ils seront renvoyés sous forme de tableau, vous devez donc les activer pour les récupérer.
type_url
est l'emplacement de la définition de type pour les détails de l'erreur, et si vous utilisez le type fourni par Google par défaut, ce sera" type.googleapis.com/google.rpc.BadRequest "
. .. Bien sûr, vous pouvez également définir votre propre type défini comme détails d'erreur, auquel cas l'emplacement que vous avez défini dans le fichier proto sera stocké.
De plus, l'instance renvoyée est de type Google :: Protobuf :: Any
, et si elle est laissée telle quelle, les données ne peuvent pas être récupérées correctement dans un état sérialisé. Par conséquent, la méthode ʻunpackest utilisée. En déterminant le type avec
type_url et en le convertissant au type que vous voulez renvoyer avec ʻunpack
, nous avons finalement pu récupérer les détails de l'erreur.
À propos, notez que vous devez importer google / rpc / error_details_pb
pour voir la définition de type de Google :: Rpc :: BadRequest
.
La récupération des détails de l'erreur a pris beaucoup de temps. L'exemple de code sur https://grpc.io/docs/languages/ruby/quickstart/ ne couvre pas cela en détail, il est donc un peu pénible de devoir parcourir le contenu du gem un par un.
Recommended Posts