ステータスコードとエラーハンドリング
gRPCのステータスコードを効果的に使用し、サービスに適切なエラー伝播とエラーハンドリングを実装する方法を学習します。
「ステータスコードとエラーハンドリング」はCoddyKit上の無料gRPC & High Performance APIsレッスンです。 これはレッスン1/4です。 下記で完全なレッスンを無料で読むことができます。その後、ブラウザ内の組み込みコードエディタと24時間対応のAIチューターでハンズオン演習できます。 これはgRPC & High Performance APIs学習パスの一部であり、ウェブとCoddyKitアプリ全体で進捗が同期されます。 gRPC & High Performance APIsコースには全4レッスンが含まれています。
このレッスンの一部はまだ翻訳されておらず、英語で表示されています。
Why Handle gRPC Errors?
In any robust application, errors are inevitable. How we handle them can make or break a system's reliability and user experience.
For distributed systems using gRPC, consistent error handling is crucial. It ensures that services can communicate problems clearly and clients can react appropriately.
Meet gRPC Status Codes
gRPC uses a standardized set of Status Codes to indicate the outcome of an RPC (Remote Procedure Call). These codes provide a universal way to understand why a call succeeded or failed.
Think of them like HTTP status codes, but specifically for gRPC. Some common ones include:
OK: The RPC completed successfully.NOT_FOUND: Resource not found (e.g., a user ID doesn't exist).INTERNAL: An unexpected error occurred on the server.UNAUTHENTICATED: The request lacks valid authentication credentials.
Protobuf Service Definition
Before we look at error handling, let's define a simple service in a .proto file. This defines the structure of our messages and the RPC methods.
We'll create a UserService with a GetUser method that takes a UserRequest and returns a User.
syntax = "proto3";
option java_multiple_files = true;
option java_package = "com.coddykit.grpc.error";
option java_outer_classname = "ErrorProto";
package errorhandling;
message UserRequest {
int32 id = 1;
}
message User {
int32 id = 1;
string name = 2;
string email = 3;
}
service UserService {
rpc GetUser (UserRequest) returns (User);
}Server-Side Error Signaling
On the server, when an operation fails, you don't throw a regular exception. Instead, you create a gRPC Status object with an appropriate code and description, then convert it to a StatusRuntimeException.
This exception is then sent back to the client via the responseObserver.onError() method, ensuring the client receives the standardized gRPC error.
Server Error Implementation
Try running this example. The server will respond with a NOT_FOUND error if you request any user ID other than 1.
import io.grpc.Server;
import io.grpc.ServerBuilder;
import io.grpc.Status;
import io.grpc.stub.StreamObserver;
import com.coddykit.grpc.error.ErrorProto.User;
import com.coddykit.grpc.error.ErrorProto.UserRequest;
import com.coddykit.grpc.error.UserServiceGrpc;
public class ErrorServer {
private static final int PORT = 50051;
public static void main(String[] args) throws Exception {
Server server = ServerBuilder.forPort(PORT)
.addService(new UserServiceImpl())
.build();
server.start();
System.out.println("Server started on port " + PORT);
server.awaitTermination();
}
static class UserServiceImpl extends UserServiceGrpc.UserServiceImplBase {
@Override
public void getUser(UserRequest request, StreamObserver<User> responseObserver) {
System.out.println("Received GetUser request for ID: " + request.getId());
if (request.getId() == 1) {
User user = User.newBuilder()
.setId(1)
.setName("Alice")
.setEmail("alice@example.com")
.build();
responseObserver.onNext(user);
responseObserver.onCompleted();
} else {
Status status = Status.NOT_FOUND.withDescription("User with ID " + request.getId() + " not found.");
responseObserver.onError(status.asRuntimeException());
}
}
}
}Client-Side Error Handling
On the client side, gRPC errors are typically received as StatusRuntimeException. You should wrap your gRPC calls in try-catch blocks to gracefully handle these exceptions.
Inside the catch block, you can inspect the Status object from the exception to determine the error code and description, allowing your client to respond intelligently.
Client Error Handling Demo
Run this client code after starting the server from the previous scene. Observe how it handles both a successful user lookup and a 'not found' error.
import io.grpc.ManagedChannel;
import io.grpc.ManagedChannelBuilder;
import io.grpc.StatusRuntimeException;
import com.coddykit.grpc.error.ErrorProto.User;
import com.coddykit.grpc.error.ErrorProto.UserRequest;
import com.coddykit.grpc.error.UserServiceGrpc;
public class ErrorClient {
private static final int PORT = 50051;
private static final String HOST = "localhost";
public static void main(String[] args) {
ManagedChannel channel = ManagedChannelBuilder.forAddress(HOST, PORT)
.usePlaintext() // For local testing without TLS
.build();
UserServiceGrpc.UserServiceBlockingStub blockingStub = UserServiceGrpc.newBlockingStub(channel);
// Scenario 1: User found
try {
UserRequest foundRequest = UserRequest.newBuilder().setId(1).build();
User user = blockingStub.getUser(foundRequest);
System.out.println("User found: " + user.getName());
} catch (StatusRuntimeException e) {
System.err.println("Error calling GetUser (found scenario): " + e.getStatus().getCode() + " - " + e.getStatus().getDescription());
}
System.out.println("\n--- Trying to get a non-existent user ---");
// Scenario 2: User not found (expected error)
try {
UserRequest notFoundRequest = UserRequest.newBuilder().setId(99).build();
User user = blockingStub.getUser(notFoundRequest);
System.out.println("User found (unexpected): " + user.getName()); // This line should not be reached
} catch (StatusRuntimeException e) {
System.err.println("Error calling GetUser (not found scenario):");
System.err.println(" Status Code: " + e.getStatus().getCode());
System.err.println(" Description: " + e.getStatus().getDescription());
} finally {
channel.shutdown();
}
}
}Effective Error Propagation
Proper error propagation is vital. When a gRPC service calls another internal service and encounters an error, it's often best to:
- Log the error with sufficient detail for debugging.
- Translate the error into an appropriate gRPC
Statuscode for the calling client. Don't expose internal system errors directly. - Avoid swallowing errors. Always handle them or re-throw them so they don't disappear silently.
Test Your Knowledge
You are building a gRPC service that performs a complex calculation. If the input data is invalid (e.g., negative numbers where only positive are allowed), which gRPC Status code is most appropriate to return?
Key Takeaways
You've learned the basics of gRPC error handling!
- gRPC uses standardized Status Codes to communicate RPC outcomes.
- Servers signal errors by creating a
Statusobject and callingresponseObserver.onError(). - Clients handle errors by catching
StatusRuntimeExceptionand inspecting itsStatusobject. - Always propagate errors clearly and translate them appropriately for clients.
This structured approach ensures reliable communication in your distributed systems.
よくある質問
「ステータスコードとエラーハンドリング」レッスンは無料ですか?
はい。「ステータスコードとエラーハンドリング」の完全なテキストはこのウェブで無料で読めます。インタラクティブに演習し(組み込みコードエディタと24時間対応のAIチューター)、gRPC & High Performance APIsコースの残りをアンロックするには、CoddyKit PROにアップグレードしてください。 gRPC & High Performance APIsコースには全4レッスンが含まれています。
「ステータスコードとエラーハンドリング」で何を学びますか?
gRPCのステータスコードを効果的に使用し、サービスに適切なエラー伝播とエラーハンドリングを実装する方法を学習します。 ブラウザで直接実行するハンズオンコードでgRPC & High Performance APIsを演習し、24時間対応のAIチューターがレッスンを進める中での質問に答えます。
gRPC & High Performance APIsを始めるのに経験は必要ですか?
事前経験は必要ありません。CoddyKitのgRPC & High Performance APIsは初級者から上級者向けに構成されているため、ここから始めるか最初から始めて、自分のペースで進むことができます。 これはレッスン1/4です。
「ステータスコードとエラーハンドリング」レッスンにはどのくらい時間がかかりますか?
ほとんどのCoddyKitレッスンは約5~10分かかります。各レッスンはコンパクトでインタラクティブなので、着実に進歩し、ウェブとアプリ全体で正確に前回の場所から再開できます。
このgRPC & High Performance APIsレッスンでコードを書いて実行できますか?
はい。すべてのgRPC & High Performance APIsレッスンに組み込みコードエディタが含まれているため、ブラウザでリアルコードを書いて実行し、即座のAIフィードバックを取得できます。ローカル設定は不要です。
このコースのすべてのレッスン
- ステータスコードとエラーハンドリング
- カスタムメタデータの送受信
- コンテキストとデッドライン
- google.rpc.Statusによる詳細なエラーモデル