Skip to content

Commit e363ba6

Browse files
authored
Init inlining & panic=unwind reinitialization (#964)
1 parent bd2dfa5 commit e363ba6

File tree

21 files changed

+413
-258
lines changed

21 files changed

+413
-258
lines changed

.github/workflows/pullrequest.yml

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ jobs:
7676
continue
7777
fi
7878
echo "Generating $template_name"
79-
cargo generate --path $template --name "$template_name" --destination ./generated --force
79+
cargo generate --path $template --name "$template_name" --destination ./generated --force --define panic_unwind=false
8080
cd "generated/$template_name"
8181
echo "Building $template_name"
8282
../../target/debug/worker-build
@@ -108,6 +108,9 @@ jobs:
108108
- name: Make worker-build executable
109109
run: chmod +x ./target/debug/worker-build
110110

111+
- name: Build wasm-bindgen
112+
run: cd wasm-bindgen && cargo build -p wasm-bindgen-cli --bin wasm-bindgen
113+
111114
- name: Build all examples
112115
run: |
113116
sed -i 's/, "examples\/axum"//g' Cargo.toml
@@ -119,7 +122,7 @@ jobs:
119122
fi
120123
echo "Building $example_name"
121124
cd "$example"
122-
../../target/debug/worker-build
125+
WASM_BINDGEN_BIN='../../wasm-bindgen/target/debug/wasm-bindgen' ../../target/debug/worker-build
123126
cd ../..
124127
done
125128

README.md

Lines changed: 64 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -48,8 +48,10 @@ Use [cargo generate](https://github.com/cargo-generate/cargo-generate) to start
4848
cargo generate cloudflare/workers-rs
4949
```
5050

51-
There are several templates to chose from. You should see a new project layout with a `src/lib.rs`.
52-
Start there! Use any local or remote crates and modules (as long as they compile to the `wasm32-unknown-unknown` target).
51+
There are several templates to choose from. During generation you will be prompted to enable
52+
`panic=unwind` and abort recovery (see [Panic Recovery](#panic-recovery-with---panic-unwind)
53+
below). You should see a new project layout with a `src/lib.rs`. Start there! Use any local or
54+
remote crates and modules (as long as they compile to the `wasm32-unknown-unknown` target).
5355

5456
Once you're ready to run your project, run your worker locally:
5557

@@ -439,6 +441,66 @@ allows you to describe your RPC interface using WIT and generate JavaScript bind
439441
[rpc-client example](./examples/rpc-client/wit/calculator.wit). The easiest way to use this code generator is using a [build script](./examples/rpc-client/build.rs) as shown in the example.
440442
This code generator is pre-alpha, with no support guarantee, and implemented only for primitive types at this time.
441443

444+
## Panic Recovery with `--panic-unwind`
445+
446+
By default, Rust panics in Workers compile with `panic=abort`, which terminates the WebAssembly
447+
instance. The `--panic-unwind` flag for `worker-build` changes this behavior so that panics are
448+
caught and converted to JavaScript exceptions, allowing the Worker to continue serving requests
449+
after a panic.
450+
451+
```bash
452+
npx worker-build --panic-unwind
453+
```
454+
455+
Or in your `wrangler.toml` build command:
456+
457+
```toml
458+
[build]
459+
command = "cargo install worker-build && worker-build --release --panic-unwind"
460+
```
461+
462+
This flag:
463+
464+
- Uses the **nightly** Rust toolchain (requires `rustup toolchain install nightly`)
465+
- Rebuilds `std` with `-Zbuild-std=std,panic_unwind` and `-Cpanic=unwind`
466+
- Enables wasm-bindgen's [panic catching](https://wasm-bindgen.github.io/wasm-bindgen/reference/catch-unwind.html)
467+
support, which catches panics at FFI boundaries and converts them to JavaScript `PanicError`
468+
exceptions
469+
- Registers `schedule_reinit()` via wasm-bindgen's [abort handling](https://wasm-bindgen.github.io/wasm-bindgen/reference/handling-aborts.html)
470+
hooks to automatically recover from critical errors (e.g. `unreachable`, stack overflow, or
471+
out-of-memory). After a hard abort the WebAssembly instance is transparently reinitialized on
472+
the next request, with an internal instance ID bump so that Durable Object instances are
473+
recreated.
474+
475+
Without this flag, any panic will terminate the isolate. With it, individual requests that
476+
trigger a panic will fail with an error response while subsequent requests continue to work
477+
normally.
478+
479+
### Unwind Safety
480+
481+
When building with `panic=unwind`, exported function arguments and closure captures must satisfy
482+
Rust's `UnwindSafe` trait. The `worker` crate macros wrap handler callbacks with
483+
`AssertUnwindSafe` automatically, but if you pass closures to JavaScript via `Closure::new` or
484+
similar APIs you may need to wrap non-unwind-safe captures (e.g. `&mut T`, `Cell<T>`,
485+
`RefCell<T>`) in `std::panic::AssertUnwindSafe`:
486+
487+
```rust
488+
use std::cell::Cell;
489+
use std::panic::AssertUnwindSafe;
490+
use wasm_bindgen::prelude::*;
491+
492+
let counter = Cell::new(0u32);
493+
let counter_ref = AssertUnwindSafe(&counter);
494+
let closure = Closure::new(move || {
495+
counter_ref.set(counter_ref.get() + 1);
496+
});
497+
```
498+
499+
Alternatively, `Closure::own_aborting` and other `*_aborting` variants skip the `UnwindSafe`
500+
requirement but will abort on panic instead of catching it. See the
501+
[wasm-bindgen closures documentation](https://wasm-bindgen.github.io/wasm-bindgen/reference/passing-rust-closures-to-js.html)
502+
for the full set of closure APIs and their unwind behavior.
503+
442504
## Testing with Miniflare
443505

444506
In order to test your Rust worker locally, the best approach is to use

0 commit comments

Comments
 (0)