Expand description
WASM route handlers (nano-services) – DW-106.
A nano-service is a route action that runs a WebAssembly module to
generate the response directly, instead of proxying to an upstream.
The module implements a simple request->response handler ABI over
the existing wasmtime runtime (the wasm cargo feature, brought in
by nano_services). This is the “function-as-a-route” path: a
self-contained WASM module owns the whole response for a route –
status, headers, and body – with no backend contact.
§Handler ABI
The module exports:
memory– the linear memory the host and module share.alloc(size: i32) -> i32– allocatesizebytes in linear memory and return a pointer (a simple bump allocator is fine; the host uses it to place the serialized request).handle(req_ptr: i32, req_len: i32) -> i32– handle the request whose serialized form lives at[req_ptr, req_ptr+req_len)in linear memory. Returns 0 on success (the response is communicated back via the host imports below) and non-zero on error (the route answers 502).
The host provides these imports under the module name dwara:
response_status(status: i32)– set the HTTP response status.response_header(k_ptr, k_len, v_ptr, v_len)– add a response header.response_body(ptr, len)– set the response body.log(ptr, len)– emit a log line (tracing::debug).
The request is serialized into linear memory in a length-prefixed binary format (all lengths u32 big-endian):
u32 method_len, method bytes
u32 path_len, path bytes
u32 headers_count, [u32 key_len, key, u32 val_len, val]...
u32 body_len, body bytesThe module parses this to read the request, then calls the host
imports to build the response and returns 0 from handle.
§Resource limits
memory_limit caps the linear memory the module may allocate
(enforced via wasmtime’s ResourceLimiter). execution_timeout_ms
caps the wall-clock time the handle call may run: the call runs on
a blocking pool thread wrapped in a tokio::time::timeout, so a
module that exceeds it is interrupted and the route answers 504. A
fuel budget caps CPU work (a module that exhausts it traps and the
route answers 502).
§Feature gate
The module compiles only when the nano_services cargo feature is
enabled (which pulls in wasm / wasmtime). The config schema is
always present, so configs round-trip without the feature; when the
feature is off the action is accepted but inert (validation warns,
the route returns 502).
Structs§
- Deserialized
Request - The deserialized parts of a nano-service wire-format request.
- Nano
Service - A compiled nano-service: the module path and the resource limits,
resolved from the route’s
NanoServiceAction. The WASM bytes are read and compiled lazily byNanoServiceHandler::loadso a missing/broken module is reported at handler construction, not at config publish time (validation already checks the file exists). - Nano
Service Handler - The nano-service handler: holds a process-wide wasmtime engine and
the linker wired with the
dwarahost imports. Cheap to clone (Arc internals). One instance percrate::dataplane::DataPlane(or per route set);NanoServiceHandler::handleis called per request. - Nano
Service Response - The response a nano-service module produced.
Enums§
- Nano
Service Error - A nano-service error. Maps to HTTP responses:
Functions§
- deserialize_
request - Deserialize a nano-service wire-format request back into its parts.
Returns
Noneon a truncated/corrupt buffer. - serialize_
request - Serialize a request into the nano-service wire format (all lengths u32 big-endian):
- shared_
handler - A process-wide shared nano-service handler. wasmtime recommends a
single
Engineper process (compiled modules are cached and shared across threads), so the dataplane reuses one handler for every nano-service route. The handler is stateless beyond the immutable engine + linker (both Arc-held), so sharing it across requests and tests is safe. Lazily initialized on first use; a construction failure (wasmtime misconfiguration) is reported once and cached as an error so every subsequent request answers 502 without retrying.