Rustのshuttleを使ってみる【2】

にあえん

November 2, 2023

タダでもうれしいのはOSSだけ、ナナオです。

前回に引き続き、Shuttleを使ってみようと思います。

ワークスペースでプロジェクトをデプロイする

shuttleはワークスペースをサポートしています。

これにより、複雑なコードをカプセル化しつつ、可読性高く開発することができます。

(私の最初のイメージでは、ワークスペースのメンバーそれぞれがプロジェクトとして独立した形でデプロイされるのかと思ってたんですが、ルートパッケージが一つのプロジェクトとして扱われるようになる感じでした…)

Project structure - Shuttle

ただし、既存のパッケージをプロジェクトとして独立させるみたいなことをするのは少し厄介です。

というのも、どうやらそもそもローカルにあるCargoディレクトリの移動ということが想定されていないためか、既にデプロイしているディレクトリを移動するとデプロイができなくなってしまいます。

また、内部的にgitのコミットを追っているというのもあり、gitの管理をいったん外すといったことができなくなります。

つまり、新たに作成したワークスペースのメンバーに既存のCargoパッケージを追加する場合、本来はルートパッケージ側でgitを管理したいのにそれができなくなってしまうということが考えられます。

(まぁこの辺は単に私のドキュメントの読み込み不足という可能性もあるので、その辺は指摘あればコメントください)

ということで、前回の記事で作成したプロジェクトは一旦リモートのプロジェクトからは削除して、新たにワークスペース単位でリソース管理ができるようにしてみましょう。

まずはベースになるルートパッケージを作成します。

cargo new shuttle-playground

次に、前回作成したプロジェクトを削除します。

# 前回作成したshuttle-playground-nanaoを削除します
# 削除前にサーバーを止めておく必要がある
cargo shuttle stop
# 停止後に削除ができるようになる
cargo shuttle project delete

これできれいになりました!

次にルートプロジェクト内に前回のshuttle-playground-nanaoを移動します。

ローカルでの名前は変えておきましょうか。

mv shuttle-playground-nanao shuttle-playground/backend

backendをワークスペースのメンバーに追加してあげます。

[workspace]
members = [
    "backend",
]

このままのパッケージ名だとありふれているため競合してしまいますが、ルートパッケージ配下にShuttle.tomlを作成することで解決できます。

ここでは以前と同じ名前にしておきましょう。

name = "shuttle-playground-nanao"

この状態で、ルートパッケージのファーストコミットを行っておきます。

git add --all
git commit -m "first commit"

ではデプロイしていきます。

# Shuttleプロジェクトを開始
cargo shuttle project start
# プロジェクトにデプロイ
cargo shuttle deploy

デプロイ後、アクセスした様子が以下になります。

これでワークスペースを使用したパッケージからのデプロイができました!

エントリーポイントが二つあったらどうなるの?

ちなみに少し話が逸れますが、今backendのみにエントリーポイントがある感じなんですが(#[shuttle_runtime::main]のこと)、これが二つになったらどうなるんでしょうか?

backendパッケージをコピーして少し実装修正してワークスペースのメンバーに追加し、もう一度デプロイしてみましょう。

cp backend frontend

同一のパッケージ名が二つ存在してしまうことになるので、frontend/Cargo.tomlを変更しておきます。

[package]
name = "frontend"

backendのコードと区別するため、frontend/src/main.rsを少し修正します。

use actix_web::{get, web::ServiceConfig};
use shuttle_actix_web::ShuttleActixWeb;

#[get("/")]
async fn hello_world() -> &'static str {
    "Hello Frontend!" // 返却される文字列を修正
}

#[shuttle_runtime::main]
async fn main() -> ShuttleActixWeb<impl FnOnce(&mut ServiceConfig) + Send + Clone + 'static> {
    let config = move |cfg: &mut ServiceConfig| {
        cfg.service(hello_world);
    };

    Ok(config.into())
}

これでコミットしてデプロイしましょう。

git add --all
git commit -m "fix: エントリーポイントが二つある場合どうなるか実験"
cargo shuttle deploy

なんと、不思議なことにデプロイできてしまいました。

ただ返却されるのは永遠にbackendからのレスポンスでした。

エラーになるかロードバランシング的な感じになるのを期待していたのですが、うーん、謎挙動。。

このあと、frontend側のURLパスを変更してみてどうなるかも試しましたが(#[get("/")]#[get("/frontend")]にしたり)、frontend側の一切リクエストが届きませんでした。

興味深いのは、この後ワークスペースのメンバーをfrontendだけにしてデプロイしたら、それはそれでちゃんとfrontendのリクエストが届くようになったんですよね。

[workspace]
members = [
    # "backend", # コメントアウト
    "frontend",
]

興味本位でやってみましたが、挙動としてはややこしくなるだけなので、エントリーポイントはパッケージ内に一つだけとなるようにしましょう。

まとめ

ワークスペースでShuttleを使ってみました。

次回はここにスケジューラを足してみたいと思います。

ではまた。