deislabs / wagi

Write HTTP handlers in WebAssembly with a minimal amount of work
Apache License 2.0
889 stars 45 forks source link

Registering routes with Go and AssemblyScript #128

Closed benc-uk closed 3 years ago

benc-uk commented 3 years ago

I'm following the guide here, regarding route registration https://github.com/deislabs/wagi/blob/main/docs/writing_modules.md#advanced-declaring-sub-routes-in-the-module

However I'm trying to use either Go or AssemblyScript and not having much luck with the routing feature

My Go code is very simple

package main

import "fmt"

func main() {
    fmt.Println("Content-Type: text/plain")
    fmt.Println("")
    fmt.Println("this is route main")
}

//export test
func test() {
    fmt.Println("Content-Type: text/plain")
    fmt.Println("")
    fmt.Println("this is route test")
}

//export _routes
func _routes() {
    fmt.Println("/test test")
}

My modules config is simply

[[module]]
route = "/"
module = "server.wasm"

When I run this I can hit the root URL and get this is route main returned but hitting /test results in nothing. I don't think the exported _routes() function is even being called


So tried again, but this time using AssemblyScript

import "wasi";
import { Console, Environ, CommandLine } from "as-wasi";

Console.log("content-type: text/plain");
Console.log("");
Console.log("Hello!");

export function test(): void {
  Console.log("content-type: text/plain");
  Console.log("");
  Console.log("Test!");
}

export function _routes(): void {
  Console.log("/test test");
}

This time when I run WAGI (directed at the build/untouched.wasm file) I get

Error: Not all routes could be built: exit with invalid exit status outside of [0..126)
wasm backtrace:
    0:  0x600 - <unknown>!~lib/wasi/index/abort
    1:  0x679 - <unknown>!~lib/rt/itcms/visitRoots
    2:  0xf42 - <unknown>!~lib/rt/itcms/step
    3: 0x1081 - <unknown>!~lib/rt/itcms/interrupt
    4: 0x160f - <unknown>!~lib/rt/itcms/__new
    5: 0x1959 - <unknown>!~lib/string/String.UTF8.encode
    6: 0x1675 - <unknown>!~lib/string/String.UTF8.encode@varargs
    7: 0x16ac - <unknown>!~lib/as-wasi/as-wasi/Descriptor#writeStringLn
    8: 0x1727 - <unknown>!~lib/as-wasi/as-wasi/Descriptor#writeString
    9: 0x1794 - <unknown>!~lib/as-wasi/as-wasi/Console.write
   10: 0x179d - <unknown>!~lib/as-wasi/as-wasi/Console.log
   11: 0x1925 - <unknown>!assembly/index/_routes

I don't know what I'm doing wrong!

benc-uk commented 3 years ago

Ok I've got the Go version working

I either need to set the base route as an empty string route = "" in the modules.toml or remove the slash prefix at the start of the routes I register

If you have both it's actually matching on a route with two slashes e.g. http://localhost:3000//test

The AssemblyScript issue is likely completely unrelated.

I'll leave this open for now, in case the double slash behaviour is a bug (it kinda feels like it is)

itowlson commented 3 years ago

I think this is probably a bug. The expectation is that base routes wouldn't end with a / (e.g. /parent rather than /parent/) but that probably shouldn't be assumed, and it's a poor fit for the base route case. Thanks for flagging this.

For our info, was this using a released WAGI binary, or building yourself from main? Asking because we did a major refactor recently and it's quite possible I introduced a regression.

itowlson commented 3 years ago

Forgot to say, yes, the AssemblyScript issue looks like something deeper and nastier - I will look at that too.

itowlson commented 3 years ago

Fix in for the double slash issue, but I'm having trouble reproducing the AssemblyScript one I'm afraid. I'll keep you posted.

itowlson commented 3 years ago

I'm a bit stumped on the AssemblyScript one. Here is my index.ts:

import "wasi";

import { Console } from "as-wasi";

Console.log("Content-Type: text/plain\n");
Console.log("Hello, world!");

export function onFoo(): void {
    Console.log("Content-Type: text/plain\n");
    Console.log("YOU'VE BEEN ROUTED");
}

export function _routes(): void {
    Console.log("/foo onFoo");
}

I'm mounting it to WAGI as a bindle rather than as a modules.toml because I'm lazy, but I don't think that should make any difference. And what I see is:

$ curl 127.0.0.1:3000/
Hello, world!
$ curl 127.0.0.1:3000/foo
YOU'VE BEEN ROUTED

The trace you get from the AS one makes me wonder if there is something like a GC going on - I don't know what interrupt, step and visitRoots are but they sound a little like a mark and sweep GC. So I'm wondering if you and I have different versions of AssemblyScript, and yours has requirements that mine doesn't, and somehow those requirements mean we need to provide runtime support that we currently don't.

Here's what my AS test program's package.json contains:

  "scripts": {
    "build:untouched": "asc assembly/index.ts --target debug --use abort=wasi_abort",
    "build:optimized": "asc assembly/index.ts --target release --use abort=wasi_abort",
    "build": "npm run build:untouched && npm run build:optimized"
  },
  "devDependencies": {
    "assemblyscript": "^0.17.2"
  },
  "dependencies": {
    "as-wasi": "^0.4.3"
  }

What version are you on and is there any difference in your build script? Thanks!

(Note: I was testing with a WAGI version that contained the double-slash fix. But the double slash thing should cause 404s rather than Wasm runtime errors.) ETA: confirmed still no repro with WAGI main

itowlson commented 3 years ago

It almost looks like you might be building with the minimal runtime: "The minimal runtime is similar to the incremental runtime, except that it doesn't go to lengths to polyfill WebAssembly features that are not yet available." That shouldn't be the default though...

https://www.assemblyscript.org/garbage-collection.html#runtime-variants

itowlson commented 3 years ago

Nope, that trace definitely looks like you are on the incremental runtime: "Incremental Tri-Color Mark & Sweep (ITCMS)" as in lib/rt/itcms/....

itowlson commented 3 years ago

Aha! If I upgrade to AssemblyScript 0.19.17 and as-wasi 0.4.6 then everything turns to custard!

  10596: 0x23c7 - <unknown>!~lib/as-wasi/as-wasi/wasi_abort
  10597: 0x23b4 - <unknown>!~stack_check
  10598: 0x23c7 - <unknown>!~lib/as-wasi/as-wasi/wasi_abort
  10599: 0x23b4 - <unknown>!~stack_check
  10600: 0x23c7 - <unknown>!~lib/as-wasi/as-wasi/wasi_abort
  10601: 0x23b4 - <unknown>!~stack_check

It's a different flavour of custard but that may be because I'm building with --use abort=wasi_abort. I think we have our culprit. Now to see if there is anything we can do on our side or if we have to address this on the AS runtime side.

itowlson commented 3 years ago

Using the Wasmtime CLI:

So there is some deep incompatibility between this version of AS and this version of Wasmtime, even when WAGI is completely out of the picture.

But why? function _routes() is doing nothing different from what the implicit main is doing...

itowlson commented 3 years ago

Raised https://github.com/AssemblyScript/assemblyscript/issues/2099