wakuwaku(ワクワク)

Rust のための証明駆動マイクロサービスフレームワーク

wakuwaku はサービスを組み立てるフレームワークです。gRPC サーバー、イベントハンドラー、cron ジョブといったすべてのコンポーネントを共有依存の型レベルレジストリから構築します。実際の処理を担うクレートは feature フラグの裏で再エクスポートされるので、サービスが依存するのは wakuwaku ひとつだけです。

依存はひとつだけ

wakuwaku を追加し、必要な連携機能を feature で有効にします。API に現れるサードパーティのクレートは wakuwaku::deps から再エクスポートされます。

  • grpc· デフォルト
  • proof· デフォルト
  • iggy
  • entity
  • sqlx-pg
  • sqlx-mysql
  • redis
  • meilisearch
Cargo.toml
[dependencies]
wakuwaku = { version = "1.0.0-rc2", features = ["iggy", "sqlx-pg", "redis"] }
tokio = { version = "1", features = ["macros", "rt-multi-thread", "signal"] }

証明駆動プログラミング

正しさを 2 つに分け、それぞれに適した方法で証明します。

マクロな正しさ

コンポーネント同士の組み合わせ方はトレイトで証明し、コンパイラーが検査します。登録されていない依存を使うコンポーネント、読み取り専用ハンドルで実行する書き込みクエリ、間隔がゼロの cron ジョブは、どれもビルドが通りません。

ミクロな正しさ

個々のコンポーネントの振る舞いはユニットテストで証明します。どのコンポーネントも Processor ベースのトレイトを実装したただの値なので、サービスを起動せずにテストから直接呼び出せます。

証明駆動の設計を読む

主な機能

フレームワーク本体がコンポーネントを組み立て、各連携機能はそれぞれのクレートとして feature フラグの裏で再エクスポートされます。

型レベルの依存レジストリ

ServiceBuilder

共有依存は型でインデックスされたレジストリに置かれます。コンポーネントは ServiceCreation を通じてそのひとつから、または compose_* のクロージャで複数の依存から構築されます。参照はトレイトソルバーが解決するため、Any もダウンキャストも実行時のマップもありません。

詳しく見る

gRPC サーバーの登録

feature = "grpc"

レジストリから tonic のサーバーを構築し、登録順にひとつのルーターへまとめて追加します。Box 化も動的ディスパッチもありません。

詳しく見る

cron ジョブ

CronJob

ジョブは定数 CronJobInterval を持つ CronTick のプロセッサーです。実行後に間隔を空ける、開始の間隔を最低限空ける、実行が重なりうる固定のグリッド、のいずれかを選べます。エラーやパニックはログに記録され、スケジュールは保たれます。

詳しく見る

Apache Iggy 上の型付きイベント

wakuwaku::iggy

順序はパーティション単位ではなくキー単位で保証されます。順序フェンスが追い越しの可否を決め、代数マーカーによってポーリングしたバッチを畳み込み、ハンドラー呼び出しを減らせます。

詳しく見る

ケイパビリティで型付けされたデータアクセス

wakuwaku::entity

クエリは読み書きするエンティティを宣言し、Db ハンドルはそれを満たすケイパビリティを持たなければなりません。sqlx(PostgreSQL・MySQL)、Redis、Meilisearch のデータソースを提供します。

詳しく見る

証明付きバリデーション

wakuwaku::proof

prove は値と、述語が成り立った証拠を組にした Proven<T, P> を返します。シグネチャで Proven を受け取れば、「検証し忘れ」は型エラーになります。

詳しく見る

ひとつのファイルでサービスを

共有の SessionStore から構築され、1 分ごとに実行される cron ジョブです。gRPC サーバーや Iggy のイベントハンドラーも同じ ServiceBuilder から登録します。

クイックスタートに進む
src/main.rs
use std::time::Duration;
use wakuwaku::deps::kanau::processor::Processor;
use wakuwaku::{CronJob, CronJobInterval, CronTick, ServiceBuilder, ServiceCreation};

#[derive(Clone)]
struct SessionStore;

struct ExpireSessions { store: SessionStore }

impl ServiceCreation for ExpireSessions {
    type Dep = SessionStore;
    fn create_service(store: SessionStore) -> Self { Self { store } }
}

impl Processor<CronTick> for ExpireSessions {
    type Output = ();
    type Error = std::convert::Infallible;
    async fn process(&self, _tick: CronTick) -> Result<(), Self::Error> {
        // Scan for expired sessions and delete them.
        Ok(())
    }
}

impl CronJob for ExpireSessions {
    const INTERVAL: CronJobInterval = CronJobInterval::AtLeast(Duration::from_secs(60));
}

#[tokio::main]
async fn main() {
    let (services, cron) = ServiceBuilder::new(SessionStore)
        .cron_job::<ExpireSessions, _>()
        .start();

    // Build gRPC servers and Iggy handlers from `services` the same way:
    // `services.grpc_service::<XxxServer<_>, Impl, _>(XxxServer::new)`,
    // `services.iggy_consumer::<Handler, _, _>()`, or from several
    // services at once with `.compose_grpc_service(|s| ...)`.
    let _ = services;

    tokio::signal::ctrl_c().await.ok();
    cron.shutdown().await;
}

ロードマップ

目指すのは、Java における Spring のように強力で堅牢なフレームワークです。

  1. 1.0.0-rc1出発点

    最初のリリース候補版です。

  2. 1.0.0-rc3現在

    このドキュメントが対象とするリリース候補版です。

  3. 1.0.0安定版

    実際のプロジェクトでの E2E テストを経てリリースします。

  4. 2.0.0Spring と同等

    意味のある Spring モジュールすべてに wakuwaku の対応物がそろった段階です。

さっそく作ってみましょう

プロジェクトを用意して、数分で最初のサービスを動かせます。