gRPCサーバーを実装する
単項RPCメソッドを提供します。
「gRPCサーバーを実装する」はCoddyKit上の無料Learn Rust Codingレッスンです。 これはレッスン3/4です。 下記で完全なレッスンを無料で読むことができます。その後、ブラウザ内の組み込みコードエディタと24時間対応のAIチューターでハンズオン演習できます。 これはLearn Rust Coding学習パスの一部であり、ウェブとCoddyKitアプリ全体で進捗が同期されます。 Learn Rust Codingコースには全4レッスンが含まれています。
生成されたサーバートレイト
Greeterという名前のサービスに対して、tonicはgreeter_server内にトレイトを生成します。独自の構造体にこれを実装して、動作を提供します。
このトレイトは#[tonic::async_trait]によってasyncになっているため、各メソッドはResultを返すasync fnになります。
use greeter::v1::greeter_server::{Greeter, GreeterServer};
use greeter::v1::{HelloRequest, HelloReply};リクエストとレスポンスのラッパー
メソッドはtonic::Request<T>を受け取り、tonic::Response<T>を返します。これらのラッパーには、メタデータ、拡張情報、内部のメッセージが含まれます。
.into_inner()を呼び出すとデコード済みのメッセージを取得でき、Response::new(..)で応答を作成できます。
let req: HelloRequest = request.into_inner();
let reply = HelloReply { message: format!("Hi {}", req.name) };
Ok(Response::new(reply))サーバー構造体
データベースプールなど、共有する状態を保持する構造体を定義します。状態を持たない場合は、Defaultをderiveすることがよくあります。
生成されたトレイトをこの構造体に実装します。
#[derive(Default)]
pub struct MyGreeter {}Unaryメソッドを実装する
#[tonic::async_trait]でimplブロックに注釈を付け、生成されたシグネチャに一致するasync fnとして各rpcを実装します。
成功時はOk(Response::new(reply))を返します。
#[tonic::async_trait]
impl Greeter for MyGreeter {
async fn say_hello(&self, request: Request<HelloRequest>)
-> Result<Response<HelloReply>, Status> {
let name = request.into_inner().name;
Ok(Response::new(HelloReply { message: format!("Hello {name}") }))
}
}Statusでエラーを返す
エラーはtonic::Statusとして返します。これはgRPCのステータスコードに対応します。Status::invalid_argumentやStatus::not_foundなどのコンストラクターを使ってください。
メッセージ文字列はコードとともにクライアントへ送信されます。
if name.is_empty() {
return Err(Status::invalid_argument("name must not be empty"));
}ビルドとサービスの提供
非同期のmainでtonic::transport::Serverを使います。生成された...Server型でラップしたサービスを追加し、ソケットアドレスを指定してserveを呼び出します。
#[tokio::main]マクロがランタイムを提供します。
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let addr = "[::1]:50051".parse()?;
Server::builder()
.add_service(GreeterServer::new(MyGreeter::default()))
.serve(addr)
.await?;
Ok(())
}サーバーストリーミングのレスポンス
サーバーストリーミングのメソッドはストリーム型を返します。tonicでは関連型とボックス化されたストリームを使います。メッセージを流し込む方法としては、mpscチャネルが一般的です。
ReceiverStreamをResponseでラップして返します。
use tokio_stream::wrappers::ReceiverStream;
let (tx, rx) = tokio::sync::mpsc::channel(8);
tokio::spawn(async move { tx.send(Ok(reply)).await.ok(); });
Ok(Response::new(ReceiverStream::new(rx)))メタデータを読み取る
リクエストのメタデータには、認証トークンなどのヘッダーが含まれます。ボディを消費する前にrequest.metadata()でアクセスしてください。
キーはASCIIで大文字と小文字を区別せず、値はMetadataValueとして返されます。
if let Some(token) = request.metadata().get("authorization") {
// validate token
} else {
return Err(Status::unauthenticated("missing token"));
}インターセプター
インターセプターは各リクエストの前に実行されるため、認証やログ出力に適しています。Requestを受け取り、それを返すか、Statusエラーを返します。
サービスを追加するときにwith_interceptorで取り付けます。
fn auth(req: Request<()>) -> Result<Request<()>, Status> {
match req.metadata().get("authorization") {
Some(_) => Ok(req),
None => Err(Status::unauthenticated("no token")),
}
}
// .add_service(GreeterServer::with_interceptor(svc, auth))グレースフルシャットダウン
serve_with_shutdownを使うと、Ctrl-Cシグナルなどのfutureが解決したときに、新しい接続の受け付けを停止できます。
実行中のリクエストが完了してからサーバーが終了するため、突然切断されることを防げます。
Server::builder()
.add_service(GreeterServer::new(MyGreeter::default()))
.serve_with_shutdown(addr, async {
tokio::signal::ctrl_c().await.ok();
})
.await?;共有状態
リクエスト間で可変状態を共有するには、サーバー構造体内でArcとtokio::sync::Mutexなどの同期プリミティブを組み合わせて状態を保持します。
tonicは接続ごとにサービスをcloneするため、安価にcloneできる共有ハンドルを使うのが適切なパターンです。
use std::sync::Arc;
use tokio::sync::Mutex;
#[derive(Default)]
pub struct MyGreeter {
hits: Arc<Mutex<u64>>,
}クイックチェック
tonicでは、gRPCメソッドの失敗をどのように通知しますか?
まとめ
生成されたサーバートレイトを実装し、リクエストのアンラップ、レスポンスとStatusエラーの返却、tokioによるサービス提供、レスポンスのストリーミング、メタデータの読み取り、インターセプターの追加、グレースフルシャットダウン、Arcによる状態共有を行いました。
次は、このサーバーを呼び出すクライアントを構築します。
よくある質問
「gRPCサーバーを実装する」レッスンは無料ですか?
はい。「gRPCサーバーを実装する」の完全なテキストはこのウェブで無料で読めます。インタラクティブに演習し(組み込みコードエディタと24時間対応のAIチューター)、Learn Rust Codingコースの残りをアンロックするには、CoddyKit PROにアップグレードしてください。 Learn Rust Codingコースには全4レッスンが含まれています。
「gRPCサーバーを実装する」で何を学びますか?
単項RPCメソッドを提供します。 ブラウザで直接実行するハンズオンコードでLearn Rust Codingを演習し、24時間対応のAIチューターがレッスンを進める中での質問に答えます。
Learn Rust Codingを始めるのに経験は必要ですか?
事前経験は必要ありません。CoddyKitのLearn Rust Codingは初級者から上級者向けに構成されているため、ここから始めるか最初から始めて、自分のペースで進むことができます。 これはレッスン3/4です。
「gRPCサーバーを実装する」レッスンにはどのくらい時間がかかりますか?
ほとんどのCoddyKitレッスンは約5~10分かかります。各レッスンはコンパクトでインタラクティブなので、着実に進歩し、ウェブとアプリ全体で正確に前回の場所から再開できます。
このLearn Rust Codingレッスンでコードを書いて実行できますか?
はい。すべてのLearn Rust Codingレッスンに組み込みコードエディタが含まれているため、ブラウザでリアルコードを書いて実行し、即座のAIフィードバックを取得できます。ローカル設定は不要です。
このコースのすべてのレッスン
- Protobufとサービス定義
- tonic-buildでコードを生成する
- gRPCサーバーを実装する
- gRPCクライアントから呼び出す