0Pricing
Learn Rust Coding · レッスン

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フィードバックを取得できます。ローカル設定は不要です。

このコースのすべてのレッスン

  1. Protobufとサービス定義
  2. tonic-buildでコードを生成する
  3. gRPCサーバーを実装する
  4. gRPCクライアントから呼び出す
← Learn Rust Codingに戻る