Skip to content

Commit

Permalink
Replaces http wasm middleware with more flexible implementation (#2922)
Browse files Browse the repository at this point in the history
Currently, http wasm middleware uses a proof of concept simple rewrite
function. This replaces it with a faster executing and more complete
middleware, http-wasm, added https://github.com/http-wasm/components-contrib/pull/2

Signed-off-by: Adrian Cole <adrian@tetrate.io>
  • Loading branch information
codefromthecrypt committed Mar 20, 2023
1 parent ed26d86 commit 5707007
Showing 1 changed file with 64 additions and 16 deletions.
Expand Up @@ -11,10 +11,11 @@ WebAssembly is a way to safely run code compiled in other languages. Runtimes
execute WebAssembly Modules (Wasm), which are most often binaries with a `.wasm`
extension.

The Wasm [HTTP middleware]({{< ref middleware.md >}}) allows you to rewrite a
request URI with custom logic compiled to a Wasm binary. In other words, you
can extend Dapr using external files that are not pre-compiled into the `daprd`
binary. Dapr embeds [wazero](https://wazero.io) to accomplish this without CGO.
The Wasm [HTTP middleware]({{< ref middleware.md >}}) allows you to manipulate
an incoming request or serve a response with custom logic compiled to a Wasm
binary. In other words, you can extend Dapr using external files that are not
pre-compiled into the `daprd` binary. Dapr embeds [wazero](https://wazero.io)
to accomplish this without CGO.

Wasm modules are loaded from a filesystem path. On Kubernetes, see [mounting
volumes to the Dapr sidecar]({{< ref kubernetes-volume-mounts.md >}}) to configure
Expand All @@ -28,27 +29,21 @@ kind: Component
metadata:
name: wasm
spec:
type: middleware.http.wasm.basic
type: middleware.http.wasm
version: v1
metadata:
- name: path
value: "./hello.wasm"
- name: poolSize
value: 1
value: "./router.wasm"
```

## Spec metadata fields

Minimally, a user must specify a Wasm binary that contains the custom logic
used to rewrite requests. An instance of the Wasm binary is not safe to use
concurrently. The below configuration fields control both the binary to
instantiate and how large an instance pool to use. A larger pool allows higher
concurrency while consuming more memory.
Minimally, a user must specify a Wasm binary implements the [http-handler](https://http-wasm.io/http-handler/).
How to compile this is described later.

| Field | Details | Required | Example |
|----------|----------------------------------------------------------------|----------|----------------|
| path | A relative or absolute path to the Wasm binary to instantiate. | true | "./hello.wasm" |
| poolSize | Number of concurrent instances of the Wasm binary. Default: 10 | false | 1 |

## Dapr configuration

Expand All @@ -64,7 +59,60 @@ spec:
httpPipeline:
handlers:
- name: wasm
type: middleware.http.wasm.basic
type: middleware.http.wasm
```

*Note*: WebAssembly middleware uses more resources than native middleware. This
result in a resource constraint faster than the same logic in native code.
Production usage should [Control max concurrency]({{< ref control-concurrency.md >}}).

### Generating Wasm

This component lets you manipulate an incoming request or serve a response with
custom logic compiled using the [http-handler](https://http-wasm.io/http-handler/)
Application Binary Interface (ABI). The `handle_request` function receives an
incoming request and can manipulate it or serve a response as necessary.

To compile your Wasm, you must compile source using a http-handler compliant
guest SDK such as [TinyGo](https://github.com/http-wasm/http-wasm-guest-tinygo).

Here's an example in TinyGo:

```go
package main

import (
"strings"

"github.com/http-wasm/http-wasm-guest-tinygo/handler"
"github.com/http-wasm/http-wasm-guest-tinygo/handler/api"
)

func main() {
handler.HandleRequestFn = handleRequest
}

// handleRequest implements a simple HTTP router.
func handleRequest(req api.Request, resp api.Response) (next bool, reqCtx uint32) {
// If the URI starts with /host, trim it and dispatch to the next handler.
if uri := req.GetURI(); strings.HasPrefix(uri, "/host") {
req.SetURI(uri[5:])
next = true // proceed to the next handler on the host.
return
}

// Serve a static response
resp.Headers().Set("Content-Type", "text/plain")
resp.Body().WriteString("hello")
return // skip the next handler, as we wrote a response.
}
```

If using TinyGo, compile as shown below and set the spec metadata field named
"path" to the location of the output (ex "router.wasm"):

```bash
tinygo build -o router.wasm -scheduler=none --no-debug -target=wasi router.go`
```

### Generating Wasm
Expand Down Expand Up @@ -108,4 +156,4 @@ tinygo build -o example.wasm -scheduler=none --no-debug -target=wasi example.go
- [Middleware]({{< ref middleware.md >}})
- [Configuration concept]({{< ref configuration-concept.md >}})
- [Configuration overview]({{< ref configuration-overview.md >}})
- [waPC protocol](https://wapc.io/docs/spec/)
- [Control max concurrency]({{< ref control-concurrency.md >}})

0 comments on commit 5707007

Please sign in to comment.