Module nano_service

Module nano_service 

Source
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 – allocate size bytes 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 bytes

The 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§

DeserializedRequest
The deserialized parts of a nano-service wire-format request.
NanoService
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 by NanoServiceHandler::load so a missing/broken module is reported at handler construction, not at config publish time (validation already checks the file exists).
NanoServiceHandler
The nano-service handler: holds a process-wide wasmtime engine and the linker wired with the dwara host imports. Cheap to clone (Arc internals). One instance per crate::dataplane::DataPlane (or per route set); NanoServiceHandler::handle is called per request.
NanoServiceResponse
The response a nano-service module produced.

Enums§

NanoServiceError
A nano-service error. Maps to HTTP responses:

Functions§

deserialize_request
Deserialize a nano-service wire-format request back into its parts. Returns None on 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 Engine per 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.