Fassen Sie Tipps zur Fehlerbehandlung bei der Implementierung eines gRPC-Clients in Ruby zusammen
tl;dr
Die Antwort des gRPC-Aufrufs ist im Grunde einer der folgenden Codes.
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 Als Implementierung des gRPC-Servers denke ich, dass das normale System den Code OK (0) zurückgibt, und wenn ein Fehler auftritt, gibt es einen anderen Code (1 bis 15) als OK zurück.
Wenn ein Fehler zurückgegeben wird, scheint die grpc-Gem-Seite ohne Erlaubnis eine Ausnahme zu generieren, und wenn Sie nicht retten, wird das Programm dort gestoppt. Daher ist es notwendig, die Ausnahme mit Rettung wie folgt aufzunehmen.
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
In der von gem definierten Fehlerklasse sind alle Klassen "BadStatus" Sie können sehen, dass es Klasse erbt.
In der Tat, wenn Sie sich den Vererbungsbaum der aufgetretenen Ausnahme ansehen
p ex.class.ancestors
# =>[GRPC::InvalidArgument, GRPC::BadStatus, GRPC::Core::StatusCodes, StandardError, Exception...
Grundsätzlich können Sie alle Ausnahmen mit GRPC :: BadStatus
abfangen.
Wenn Sie detaillierter verarbeiten möchten, können Sie es in Einheiten wie "GRPC :: InvalidArgument" abholen.
Lassen Sie uns die Informationen aus der erfassten Ausnahme extrahieren.
Die BadStatus
-Instanz hat vier Felder.
https://github.com/grpc/grpc/blob/d48d39c4324f06a6da24bb4f67e8ef21166ba65b/src/ruby/lib/grpc/errors.rb#L49-L52
Erstellen Sie beispielsweise einen Fehler vom in Go implementierten gRPC-Server wie folgt und geben Sie ihn an ruby zurück.
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
Ich habe die Meldungen Statuscode "3" und "ungültiger Benutzername" erhalten
Bis zu dem oben genannten wurden der Statuscode und die Fehlermeldung erhalten. Ich denke jedoch, dass Fehlerdetails häufig verwendet werden, um die Details des Fehlers zu übergeben. https://christina04.hatenablog.com/entry/grpc-error-details https://grpc.io/docs/guides/error/#richer-error-model
Wenn Sie detailliertere Informationen einschließlich Fehlerdetails wünschen, können Sie mithilfe der Methode to_rpc_status
detailliertere Informationen erhalten.
Die Implementierung von "to_rpc_status" ist wie folgt: Sie können in den Typ "Google :: Rpc :: Status" umwandeln und detaillierte Informationen, einschließlich Trailer-Metadaten, abrufen.
https://github.com/grpc/grpc/blob/d48d39c4324f06a6da24bb4f67e8ef21166ba65b/src/ruby/lib/grpc/errors.rb#L63-L75
Ich habe dem vorherigen Implementierungsbeispiel Fehlerdetails hinzugefügt.
server.go
func (s *Server) set_name(name string) {
st := status.New(codes.InvalidArgument, "invalid username")
//Erstellen und Festlegen von Informationen zu Fehlerdetails
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
Bemerkenswerte Details Details: [<Google :: Protobuf :: Any: type_url:" type.googleapis.com/google.rpc.BadRequest ", Wert:" \ nC \ n \ tusername2 \ x126Der Benutzername darf nur alphanumerisch sein Die Zeichen ">]
Teil.
Dies sind die Fehlerdetails, die als Trailer gesendet wurden, und es gibt einige Daten vom Typ "Google :: Protobuf :: Any" und Wertdaten.
Sie können mehrere Fehlerdetails festlegen, die als Array zurückgegeben werden. Sie müssen also alle drehen, um sie abzurufen.
"type_url" ist der Speicherort für die Typdefinition für Fehlerdetails. Wenn Sie standardmäßig den von Google bereitgestellten Typ verwenden, lautet dieser "type.googleapis.com/google.rpc.BadRequest". .. Natürlich können Sie auch Ihren eigenen definierten Typ als Fehlerdetails festlegen. In diesem Fall wird der in der Protodatei definierte Speicherort gespeichert.
Außerdem ist die zurückgegebene Instanz vom Typ "Google :: Protobuf :: Any". Wenn sie unverändert bleibt, können die Daten in einem serialisierten Zustand nicht ordnungsgemäß abgerufen werden. Daher wird die Entpackungsmethode verwendet.
Durch Bestimmen des Typs mit type_url
und Umwandeln in den Typ, den Sie mit unpack
zurückgeben möchten, konnte ich endlich Fehlerdetails abrufen.
Beachten Sie übrigens, dass Sie "google / rpc / error_details_pb" importieren müssen, um die Typdefinition von "Google :: Rpc :: BadRequest" anzuzeigen.
Das Abrufen der Fehlerdetails hat viel Zeit in Anspruch genommen. Der Beispielcode unter https://grpc.io/docs/languages/ruby/quickstart/ behandelt dies nicht im Detail, daher ist es etwas schmerzhaft, den Inhalt des Edelsteins einzeln durchgehen zu müssen.
Recommended Posts