Shuttleはいいぞ~、ナナオです。
今回で三回目になります、Shuttleのチュートリアル記事です。
複数のサービスを動かす
shuttle_runtime::Service
を実装してあげることで、Webサービスとスケジューラを同時に動かすようなユースケースが実装可能になります。
Welcome to Shuttle's Docs - Start Building Backends Fast - Shuttle
こちらのチュートリアルではdiscordのBOTを動かしていますね。
以前までの実装にスケジューラを追加して、継続的にログにhello worldを出力させてみましょう。
ただactix-webでの実装がわからなかったので、axumの実装に直しました。
また、スケジューラにはtokio-cron-scheduler
を使用しました。
依存関係は以下のとおりです。
[dependencies]
axum = "0.6.20"
shuttle-runtime = "0.31.0"
tokio = "1.26.0"
tokio-cron-scheduler = "0.9.4"
では、以下が完成したコードです。
use axum::{routing::get, Router, response::IntoResponse};
use tokio_cron_scheduler::{Job, JobScheduler};
async fn hello_world() -> impl IntoResponse {
"Hello World!"
}
pub struct MultipleService {
router: Router,
scheduler: JobScheduler,
}
impl MultipleService {
pub async fn new() -> Result<MultipleService, shuttle_runtime::Error> {
let router = Router::new()
.route("/", get(hello_world));
let mut scheduler = JobScheduler::new().await.unwrap();
scheduler.add(
Job::new("1/10 * * * * *", |_uuid, _l| {
println!("I run every 10 seconds");
}).unwrap()
).await.unwrap();
Ok(Self {
router,
scheduler,
})
}
}
#[shuttle_runtime::async_trait]
impl shuttle_runtime::Service for MultipleService {
async fn bind(mut self, addr: std::net::SocketAddr) -> Result<(), shuttle_runtime::Error> {
let server = axum::Server::bind(&addr);
let (_runner_hdl, _axum_hdl) =
tokio::join!(self.scheduler.start(), server.serve(self.router.into_make_service()));
Ok(())
}
}
#[shuttle_runtime::main]
async fn main() -> Result<MultipleService, shuttle_runtime::Error> {
MultipleService::new().await
}
順番に説明します。
まず、複数のサービスを動かすベースとなるMultipleService
を定義してあげます。
フィールドにはWebサービスのためのrouter
と、スケジューラサービスのscheduler
を定義しました。
pub struct MultipleService {
router: Router,
scheduler: JobScheduler,
}
このベースとなるサービスをエントリーポイントから初期化して呼び出すためのnew
関数を実装します。
ここではスケジューラの初期化及びジョブの追加とルータの初期化処理を行い、構造体にセットする処理を実装しました。
impl MultipleService {
pub async fn new() -> Result<MultipleService, shuttle_runtime::Error> {
let router = Router::new()
.route("/", get(hello_world));
let mut scheduler = JobScheduler::new().await.unwrap();
scheduler.add(
Job::new("1/10 * * * * *", |_uuid, _l| {
println!("I run every 10 seconds");
}).unwrap()
).await.unwrap();
scheduler.set_shutdown_handler(Box::new(|| {
Box::pin(async move {
println!("Shut down done");
})
}));
Ok(Self {
router,
scheduler,
})
}
}
そして、この独自に作ったサービスをShuttleで動かすために、shuttle_runtime::Service
をMultipleService
に実装してあげます。
bind
関数は引数としてアドレスを持っているので、このアドレスをWebサーバーに渡してあげた後、tokio::join
を使用してWebサーバーとスケジューラを非同期に動かしています。
#[shuttle_runtime::async_trait]
impl shuttle_runtime::Service for MultipleService {
async fn bind(mut self, addr: std::net::SocketAddr) -> Result<(), shuttle_runtime::Error> {
let server = axum::Server::bind(&addr);
let (_runner_hdl, _axum_hdl) =
tokio::join!(self.scheduler.start(), server.serve(self.router.into_make_service()));
Ok(())
}
}
あとはShuttleでMultipleServiceのインスタンスを渡してあげれば、スケジューラとWebサーバーがどちらも動くようになります。
#[shuttle_runtime::main]
async fn main() -> Result<MultipleService, shuttle_runtime::Error> {
MultipleService::new().await
}
実際に動かしてみます。
> cargo shuttle run
...中略...
2023-11-04T11:18:38.540+09:00 [Runtime] shuttle-runtime executable started (version 0.31.0)
2023-11-04T11:18:38.540+09:00 [Runtime] ===============================================================
2023-11-04T11:18:38.540+09:00 [Runtime] Shuttle's default tracing subscriber is initialized!
2023-11-04T11:18:38.541+09:00 [Runtime] To disable the subscriber and use your own,
2023-11-04T11:18:38.541+09:00 [Runtime] turn off the default features for shuttle-runtime:
2023-11-04T11:18:38.541+09:00 [Runtime]
2023-11-04T11:18:38.541+09:00 [Runtime] shuttle-runtime = { version = "...", default-features = false }
2023-11-04T11:18:38.541+09:00 [Runtime] ===============================================================
2023-11-04T11:18:38.542+09:00 [Runtime] loading alpha service at C:\Users\Nanao\Project\study\shuttle-playground\target\debug\backend.exe
2023-11-04T11:18:38.915+09:00 [Runtime] INFO tokio_cron_scheduler::job_scheduler: Uninited
2023-11-04T11:18:38.915+09:00 [Runtime] INFO tokio_cron_scheduler::job_scheduler: Job creator created
No resources are linked to this service
Starting backend on http://127.0.0.1:8000
2023-11-04T11:18:38.917+09:00 [Runtime] Starting on 127.0.0.1:8000
2023-11-04T11:18:41.446+09:00 [Runtime] I run every 10 seconds
スケジューラのログが出力されていることがわかります。
Webサーバーのほうもちゃんと動いています!
ではこれをデプロイしてみましょう。
無事デプロイまでできました!
まとめ
今回は複数のサービスをShuttleで動かす方法について学びました。
Shuttle面白いですね。これでいろいろサービス作りたいな…と思ったんですが、無料プランだと3プロジェクトまでしか動かせないので注意が必要ですね。
それではまた。