Crate worker

source ·
Expand description

§Features

§d1

Allows the use of D1 bindings and query! macro.

§queue

Enables queue event type in [event] macro.

// Consume messages from a queue
#[event(queue)]
pub async fn main(message_batch: MessageBatch<MyType>, env: Env, _ctx: Context) -> Result<()> {
    Ok(())
}

§http

worker 0.0.21 introduced an http feature flag which starts to replace custom types with widely used types from the http crate.

This makes it much easier to use crates which use these standard types such as axum.

This currently does a few things:

  1. Introduce Body, which implements http_body::Body and is a simple wrapper around web_sys::ReadableStream.
  2. The req argument when using the [event(fetch)] macro becomes http::Request<worker::Body>.
  3. The expected return type for the fetch handler is http::Response<B> where B can be any http_body::Body<Data=Bytes>.
  4. The argument for Fetcher::fetch_request is http::Request<worker::Body>.
  5. The return type of Fetcher::fetch_request is http::Response<worker::Body>.

The end result is being able to use frameworks like axum directly (see example):

pub async fn root() -> &'static str {
    "Hello Axum!"
}

fn router() -> Router {
    Router::new().route("/", get(root))
}

#[event(fetch)]
async fn fetch(
    req: HttpRequest,
    _env: Env,
    _ctx: Context,
) -> Result<http::Response<axum::body::Body>> {
    Ok(router().call(req).await?)
}

We also implement try_from between worker::Request and http::Request<worker::Body>, and between worker::Response and http::Response<worker::Body>. This allows you to convert your code incrementally if it is tightly coupled to the original types.

§Send Helpers

A number of frameworks (including axum) require that objects that they are given (including route handlers) can be sent between threads (i.e are marked as Send). Unfortuntately, objects which interact with JavaScript are frequently not marked as Send. In the Workers environment, this is not an issue, because Workers are single threaded. There are still some ergonomic difficulties which we address with some wrapper types:

  1. send::SendFuture - wraps any Future and marks it as Send:
// `fut` is `Send`
let fut = send::SendFuture::new(async move {
    // `JsFuture` is not `Send`
    JsFuture::from(promise).await
});
  1. send::SendWrapper - Marks an arbitrary object as Send and implements Deref and DerefMut, as well as Clone, Debug, and Display if the inner type does. This is useful for attaching types as state to an axum Router:
// `KvStore` is not `Send`
let store = env.kv("FOO")?;
// `state` is `Send`
let state = send::SendWrapper::new(store);
let router = axum::Router::new()
    .layer(Extension(state));
  1. [worker::send] - Macro to make any async function Send. This can be a little tricky to identify as the problem, but axum’s [debug_handler] macro can help, and looking for warnings that a function or object cannot safely be sent between threads.
// 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))

§RPC Support

workers-rs has experimental support for Workers RPC. For now, this relies on JavaScript bindings and may require some manual usage of wasm-bindgen.

Not all features of RPC are supported yet (or have not been tested), including:

  • Function arguments and return values
  • Class instances
  • Stub forwarding

§RPC Server

Writing an RPC server with workers-rs is relatively simple. Simply export methods using wasm-bindgen. These will be automatically detected by worker-build and made available to other Workers. See example.

§RPC Client

Creating types and bindings for invoking another Worker’s RPC methods is a bit more involved. You will need to write more complex wasm-bindgen bindings and some boilerplate to make interacting with the RPC methods more idiomatic. See example.

With manually written bindings, it should be possible to support non-primitive argument and return types, using serde-wasm-bindgen.

§Generating Client Bindings

There are many routes that can be taken to describe RPC interfaces. Under the hood, Workers RPC uses Cap’N Proto. A possible future direction is for Wasm guests to include Cap’N Proto serde support and speak directly to the RPC protocol, bypassing JavaScript. This would likely involve defining the RPC interface in Cap’N Proto schema and generating Rust code from that.

Another popular interface schema in the WebAssembly community is WIT. This is a lightweight format designed for the WebAssembly Component model. workers-rs includes an experimental code generator which allows you to describe your RPC interface using WIT and generate JavaScript bindings as shown in the rpc-client example. The easiest way to use this code generator is using a build script as shown in the example. This code generator is pre-alpha, with no support guarantee, and implemented only for primitive types at this time.

Re-exports§

Modules§

  • Requires d1 feature.
  • Durable Objects provide low-latency coordination and consistent storage for the Workers platform. A given namespace can support essentially unlimited Durable Objects, with each Object having access to a transactional, key-value storage API.
  • Implements TlsConnect for Socket to enable tokio_postgres connections to databases using TLS.
  • This module provides utilities for working with JavaScript types which do not implement Send, in contexts where Send is required. Workers is guaranteed to be single-threaded, so it is safe to wrap any type with Send and Sync traits.

Macros§

  • When debugging your Worker via wrangler dev, wrangler tail, or from the Workers Dashboard, anything passed to this macro will be printed to the terminal or written to the console.
  • When debugging your Worker via wrangler dev, wrangler tail, or from the Workers Dashboard, anything passed to this macro will be printed to the terminal or written to the console.
  • When debugging your Worker via wrangler dev, wrangler tail, or from the Workers Dashboard, anything passed to this macro will be printed to the terminal or written to the console.
  • When debugging your Worker via wrangler dev, wrangler tail, or from the Workers Dashboard, anything passed to this macro will be printed to the terminal or written to the console.
  • Requires d1 feature. Prepare a D1 query from the provided D1Database, query string, and optional query parameters.

Structs§

Enums§

Traits§

  • A trait used to represent any viable Request type that can be used in the Worker. The only requirement is that it be convertible from a web_sys::Request.
  • A trait used to represent any viable Response type that can be used in the Worker. The only requirement is that it be convertible to a web_sys::Response.

Functions§

Type Aliases§

  • Requires http feature. Type alias for http::Request<worker::Body>.
  • Requires http feature. Type alias for http::Response<worker::Body>.
  • A string value representing a binding to an environment variable in a Worker.

Attribute Macros§

  • The event macro is used to denote a Worker handler, essentially binding from the JS runtime to a Rust function.
  • Convert an async function which is !Send to be Send.