mcpField
R
rust-backend

rust-backend

github.com/windmill-labs開発18.3k1.1k 回インストール今日更新
リポジトリ

rust-backend について

Windmill の `backend/` で Rust を書くためのパターンガイドです。エラー処理、SQLx、JSON、非同期処理、コード構成に加え、プロジェクト固有のテレメトリー規則を扱います。

主な機能

  1. 01Result によるエラー処理と panic 回避
  2. 02SQLx のクエリとトランザクションのパターン
  3. 03JSON と Serde の処理指針
  4. 04非同期処理と Mutex の選択
  5. 05モジュール構成と rust-analyzer によるナビゲーション
  6. 06機能テレメトリーと Axum ハンドラーの規則

活用シーン

  1. 01Windmill の backend API の実装
  2. 02互換性を考慮した SQLx クエリの作成
  3. 03非同期・並行処理コードの確認
  4. 04機能利用テレメトリーイベントの追加

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/windmill-labs/windmill --skill rust-backend

インストール後、Claude Code で/rust-backendを入力して読み込まれたか確認します。

詳細

Windmill の Rust パターン

backend/ で Rust コードを書く際は、Windmill 固有のパターンを適用してください。

エラー処理

windmill_common::error の Error を使用してください。Result<T, Error> または JsonResult<T> を返します。

use windmill_common::error::{Error, Result};

pub async fn get_job(db: &DB, id: Uuid) -> Result<Job> {
    sqlx::query_as!(Job, "SELECT id, workspace_id FROM v2_job WHERE id = $1", id)
        .fetch_optional(db)
        .await?
        .ok_or_else(|| Error::NotFound("job not found".to_string()))?;
}

ライブラリコードでパニックを発生させないでください。.unwrap() はコンパイル時に保証される場合にのみ使用してください。

SQLx のパターン

SELECT * は使用しないでください。常に列を明示的に指定してください。ワーカーが API バージョンに追いついていない場合の後方互換性に不可欠です。

// Correct
sqlx::query_as!(Job, "SELECT id, workspace_id, path FROM v2_job WHERE id = $1", id)

// Wrong — breaks when columns are added
sqlx::query_as!(Job, "SELECT * FROM v2_job WHERE id = $1", id)

N+1 を避けるため、バッチ操作を使用してください。

// Preferred — single query with IN clause
sqlx::query!("SELECT ... WHERE id = ANY($1)", &ids[..]).fetch_all(db).await?

複数ステップの操作にはトランザクションを使用してください。すべてのクエリをパラメーター化してください。

JSON の処理

確認せずに JSON を保存または受け渡す場合は、serde_json::Value よりも Box<serde_json::value::RawValue> を優先してください。

pub struct Job {
    pub args: Option<Box<serde_json::value::RawValue>>,
}

JSON の確認または変更が必要な場合にのみ、serde_json::Value を使用してください。

Serde の最適化

#[derive(Serialize, Deserialize)]
pub struct Job {
    #[serde(skip_serializing_if = "Option::is_none")]
    pub parent_job: Option<Uuid>,
    #[serde(skip_serializing_if = "Vec::is_empty")]
    pub tags: Vec<String>,
    #[serde(default)]
    pub priority: i32,
}

非同期処理と並行処理

非同期ランタイムをブロックしないでください。CPU 負荷の高い処理には spawn_blocking を使用してください。

let result = tokio::task::spawn_blocking(move || expensive_computation(&data)).await?;

Mutex の選択:データ保護には std::sync::Mutex(または parking_lot::Mutex)を優先してください。ロックを .await ポイントをまたいで保持する場合にのみ、tokio::sync::Mutex を使用してください。

チャネルには tokio::sync::mpsc(有界)を使用してください。非同期コンテキストでは std::thread::sleep を避けてください。

モジュール構成と可視性

  • 可能な場合は pub ではなく pub(crate) を使用してください
  • 機能に応じて適切なクレートに新しいコードを配置してください
  • API エンドポイントは、ドメインごとに整理して windmill-api/src/ に配置してください
  • 共有機能は windmill-common/src/ に配置してください

コードのナビゲーション

定義への移動、参照の検索、型情報の確認には、必ず rust-analyzer LSP を使用してください。モジュールパスを推測しないでください。

機能テレメトリー

windmill-api-workspaces/src/workspaces.rs の FEATURE_USAGE_KINDS は許可リストです。ここにない (feature, kind) の組み合わせは、valid_feature_usage_event によって何もエラーを返さずに continue で破棄され、ルートは 204 を返します。フロントエンドにカウンターを追加しても、 ここに登録しなければ何も記録されません。docs/feature-telemetry.md を参照してください。

Axum ハンドラー

関数シグネチャ内でエクストラクターを直接分解してください。

async fn process_job(
    Extension(db): Extension<DB>,
    Path((workspace, job_id)): Path<(String, Uuid)>,
    Query(pagination): Query<Pagination>,
) -> Result<Json<Job>> { ... }

コメント