[RAILS] Conseils pour la gestion des erreurs de gRPC dans Ruby

Résumer les conseils de gestion des erreurs lors de l'implémentation d'un client gRPC dans Ruby

supposition

tl;dr

Commencez par détecter l'erreur

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.

Extraire les informations de l'exception capturée

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» «

Si vous souhaitez obtenir les détails de l'erreur, utilisez la méthode to_rpc_status

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 avectype_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.

Impressions

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

Conseils pour la gestion des erreurs de gRPC dans Ruby
Conseils pour la gestion des énumérations avec thymeleaf
Conseils pour gérer les pseudo-éléments dans Selenium
Gestion des erreurs avec Graphql-ruby
[Ruby] Gestion des exceptions dans les fonctions
Implémenter le client gRPC dans Ruby
Points clés pour l'introduction de gRPC en Java
[Ruby / Rails] Mécanisme de nouvelle tentative d'erreur de thread
gestion des exceptions ruby
astuces pour java.nio.file.Path
[WIP] Astuces Ruby
Gestion des exceptions Ruby
Lourd en rubis! ??
Comment implémenter la pagination dans GraphQL (pour ruby)
Conseils pour générer des fichiers pour les projets d'éclipse avec Gradle
Solution de contournement pour l'erreur Bundler.require lors de l'exécution de ruby avec crontab
Conseils pour définir le délai initial pour Poller dans XML
Conseils pour bien utiliser Canvas avec Xcode
ActiveModel :: UnknownAttributeError: attribut inconnu'foreign_type 'pour la gestion des erreurs PaperTrail :: VersionAssociation
[Pour les débutants] ○○. △△ en Ruby (méthode ActiveRecord, méthode d'instance, acquisition de données)
Comment résoudre l'erreur SSL_connect dans le SDK PayPal Ruby
Traitement de la date et de l'heure en Ruby. Utilisez correctement la date et l'heure.
À propos des messages d'erreur Ruby
À propos de la gestion des exceptions Ruby
abréviation de la méthode ruby
Triangle de sortie en Ruby
Types de variables dans ruby
Popcount rapide en Ruby
Integer # pow est recommandé pour résoudre à plusieurs reprises la méthode du carré dans Ruby
J'ai recherché un framework web avec Gem en Ruby
Conseils d'utilisation de Salesforce SOAP et de l'API Bulk en Java
Micro-benchmark pour les nombres à virgule flottante à la puissance des entiers dans Ruby
Gestion du début et de la fin de ligne dans les expressions régulières dans Ruby