🦀

Axum+Cloudflare Workersでつまったところn選

2024/09/02に公開

1. wranglerでインストールされるworkerが古い

cargo generate cloudflare/workers-rsでAxumのテンプレートを生成したらまずCargo.tomlのdependencies(依存クレート)を確認してほしい。
現時点(2024年9月2日)で記述されるworker,worker-macrosのバージョンが0.2.0になっている場合必ずビルドに失敗する。

ログ(長いので折りたたみ)
   Compiling worker v0.2.0
error[E0599]: no method named `unwrap` found for struct `js_sys::Iterator` in the current scope
  --> /Users/megaconfidence/.cargo/registry/src/index.crates.io-6f17d22bba15001f/worker-0.2.0/src/headers.rs:83:14
   |
80 | /         self.0
81 | |             .keys()
82 | |             // Header.keys() doesn't error: https://developer.mozilla.org/en-US/docs/Web/API/Headers/keys
83 | |             .unwrap()
   | |             -^^^^^^ method not found in `Iterator`
   | |_____________|
   | 

error[E0599]: no method named `unwrap` found for struct `js_sys::Iterator` in the current scope
  --> /Users/megaconfidence/.cargo/registry/src/index.crates.io-6f17d22bba15001f/worker-0.2.0/src/headers.rs:95:14
   |
92 | /         self.0
93 | |             .values()
94 | |             // Header.values() doesn't error: https://developer.mozilla.org/en-US/docs/Web/API/Headers/values
95 | |             .unwrap()
   | |             -^^^^^^ method not found in `Iterator`
   | |_____________|
   | 

error[E0599]: no method named `unwrap` found for struct `js_sys::Iterator` in the current scope
  --> /Users/megaconfidence/.cargo/registry/src/index.crates.io-6f17d22bba15001f/worker-0.2.0/src/headers.rs:69:14
   |
66 | /         self.0
67 | |             .entries()
68 | |             // Header.entries() doesn't error: https://developer.mozilla.org/en-US/docs/Web/API/Headers/entries
69 | |             .unwrap()
   | |             -^^^^^^ method not found in `Iterator`
   | |_____________|
   | 

error[E0277]: the `?` operator can only be applied to values that implement `Try`
  --> /Users/megaconfidence/.cargo/registry/src/index.crates.io-6f17d22bba15001f/worker-0.2.0/src/http/header.rs:11:16
   |
11 |     for res in from_headers.entries()?.into_iter() {
   |                ^^^^^^^^^^^^^^^^^^^^^^^ the `?` operator cannot be applied to type `js_sys::Iterator`
   |
   = help: the trait `Try` is not implemented for `js_sys::Iterator`

Some errors have detailed explanations: E0277, E0599.
For more information about an error, try `rustc --explain E0277`.
error: could not compile `worker` (lib) due to 4 previous errors
Error: Compiling your crate to WebAssembly failed
Caused by: Compiling your crate to WebAssembly failed
Caused by: failed to execute `cargo build`: exited with exit status: 101
  full command: cd "/Users/megaconfidence/Sandbox/temp/workers-rs" && "cargo" "build" "--lib" "--release" "--target" "wasm32-unknown-unknown"
Error: wasm-pack exited with status exit status: 1

js_sysの破壊的変更が原因っぽい
該当するissue:

この問題はすでに最新の0.3.4では解決しているのでTOMLを編集すれば解決する。

2. ハンドラの型定義が合わなくなる

もしかするとまだ筆者がAxumに不慣れなことも原因かもしれないが、Axumにわたすhandlerは何も考えずに書くと結構エラーが起きる。
1年前に書いた記事でもまとめているが、ハンドラを渡す際にはその関数がいくつか満たさなければならない条件がある。

Workerでデータベースを使いたい、というのはよくあることだが、この場合非同期処理が呼び出されることは珍しくない(KVのgetなど)。
これはworkerのDocでも述べられており、.awaitをはさむと基本的にハンドラ全体が!Sendになる。これはaxumのハンドラの制約

Returns a future that is Send. The most common way to accidentally make a future !Send is to hold a !Send type across an await.

に該当する。
解決法の一つとして以下のように#[worker::send]をつけることでSendに変換できるようになる、というのがもっともシンプル。ただ動作しないかもしれないので同じ章で書かれているラッパークラスの実装などになる場合もある。

// This macro makes the whole function (i.e. the `Future` it returns) `Send`.
#[worker::send]
async fn handler(Extension(env): Extension<Env>) -> Response<String> {
    let kv = env.kv("FOO").unwrap()?;
    // Holding `kv`, which is not `Send` across `await` boundary would mark this function as `!Send`
    let value = kv.get("foo").text().await?;
    Ok(format!("Got value: {:?}", value));
}

let router = axum::Router::new()
    .route("/", get(handler))

3. Axumとworkerの定義で衝突が起きる

別にworkerはAxumがなくても動くように、自前のRequest/Responseなどが提供されているので衝突が起きてエラーが頻発した。
ただ自分はAxumの書き方に慣れていたので、できるだけAxumに沿った書き方をしたい。
というわけで目をつけたのがaxum-cloudflare-adapterである。

https://github.com/logankeenan/axum-cloudflare-adapter

ただこのRepoは今年4月が最終リリース(現時点(2024年9月2日))でdependenciesのworker関連が^0.2.0なのでローカルに落として/adapterのTOMLを編集する必要がある(バージョン変えるだけでビルドは通る)
ただPRを見る限り0.3.2に上げようとしていたところで型関連でビルドに失敗しているっぽい。続報に期待?

(2024年10月1日追記)
こちらのリリースでバージョンが0.4.0に対応したので早速反映していい感じにしました(rust 1.81.0以上が必須)
ありがてぇ......

https://github.com/logankeenan/axum-cloudflare-adapter/releases/tag/0.13.0

Discussion