Ren-C is Now on the Clouds ☁️ with WASI

Note: WASI => WebAssembly System Interface

We've been running in a browser for a while. And over time, as that host environment has gotten better...we've been getting better, too. (It can sometimes pay to be an early adopter and co-evolve with a platform.)

After several long days of nuanced work, I've been able to take another step...running in a WasmEdge VM!

Unlike the web version, this has the command-line processing built into it. So you can pass wasmedge the %r3.wasm file, and say something like --do of the code you want to run:

$ wasmedge r3.wasm --do \
      "print ['** uparse {Hello, Cloud} [thru space across to <end>] '**]"

Then you get your result:

** Cloud **

See for yourself, on the GitHub Workflow that builds it!!!!

"So... er... so what?" (someone might ask)

... WH-

... WH- WHAT YOU DO MEAN, "SO WHAT?" ... YOU, you... IGNORAMUS!

:angry:
...

Oh, all right, well. Fine. Let me try and break down what this is... and what it might mean for Ren-C's future in the cloud space (and elsewhere).


First Let's Talk About "The Dream That Isn't" (yet)

...and that dream is "SERVERLESS"-ness.

  • Picture if you will, the idea that we take %httpd.reb and shoot it into the sun... :rocket: :sun_with_face: ...vowing to never try and write another web server in a Redbol again.

  • INSTEAD we dial the clock back to how people responded to web requests in the 90's: we think of it that each request starts a whole new copy of %r3.exe, which does its work, and exits.

    • ...this really is how systems used to work, back when there were 5 people on the Internet. (Modems were so slow that you couldn't get more than one request a week, anyway.)

    • But in the name of speed, webmastering became a mystical black art of figuring out how to force your PHP or Python or whatever to stay resident inside the Apache server and not exit.

    • The seeping complexity started to require watchdog processes to check to make sure your long-running process wasn't accruing memory across requests, or restarting it if it crashed.

    • Security was also being compromised, because bugs in your code could allow session data to seep between different requests...since the process was long-lived and kept memory open.

  • THE UTOPIA WE ARE BEING SOLD is that IF we package our code as a blob-o-WebAssembly...

    • We will get all the benefits of running fresh every request...

    • ...but with a performance characteristic like if we'd rigged up a way to stay running the whole time.

  • THERE WILL STILL BE A WEBSERVER RUNNING (of course)

    • However: it will be The One True Debugged WebServer (compiled in something fully formal like Rust or Haskell, right?)...so it won't have the same security problems that your dirty Wasm blob would have if it tried to implement a long-running web server itself.

    • It will have lightning fast abilities to spin up and down the Wasm blobs, much faster than an OS shutdown and launch would ever be.

I've Now Made Us One Of Those Wasm Blobs!

Hence we can focus our efforts on the high level logic of how to answer a web request without worrying about the details of writing, running, or administrating a web server.

If you've ever looked at some Platform as a Service (PaaS) like Heroku or AWS and seen a short list of languages supported, that's going to be a thing of the past. Anyone who builds to WebAssembly can be hosted and just pay the price of their storage/CPU/network use.

  • Yesterday we were a black sheep of languages...with a shoddy, slow, and insecure webserver.

  • Tomorrow... we'll still be a black sheep of languages. But one that's on an even playing field for providing higher level logic for processing and serving data on the web.

"Ah! Now I See the What of the So What!"

:smiling_face_with_three_hearts:

It's a quite compelling vision statement, and a lot of people are evangelical (you can tell by how many times people say the term "serverless" at conferences these days).

I'm definitely the sort of person this is an easy sell to. You should choose your battles when it comes to optimization, this is one of my favorite quotes:

"90% of a program's execution time is spent in only 10% of its code. The standard inference from this rule is that programmers should find that 10% of the code and optimize it ... But a second inference is just as important: programmers can deoptimize the other 90% of the code (in order to make it easier to use, maintain, etc.) -- Richard Pattis

So focusing performance research on the spin-up and tear-down sounds 100% right. Over the long run, the factors I mention probably mitigate any "catastrophic slowdown". Your higher level program logic is starting from a clean slate every time. There's no memory fragmentation or leaks, and all those security benefits I mentioned.

Not Just the Cloud, but One Binary For All Desktops

As WebAssembly has proven its mettle on the Web, people have asked why it couldn't be run from a terminal prompt. All you'd need would be a runtime host--simpler than a browser--that provided basic file, I/O, and network services.

If you could do that, you'd be able to have one %r3.wasm file that you could download and use for Linux, Mac, Windows, on the cloud, and in your browser...

...in theory. And that theory is almost practice. (I've remarked on another thread about it so take discussions of the non-cloud applications there.)

Of Course, It's Not All-There-Yet

What about those Wasm blob server providers?

They don't exist yet.

So if you're going to use the serverless methodology in the here and now, you're going to still be in the webmastering game. Only now you're learning how to set up Docker instances and configure bleeding-edge Wasm runtimes.

What about that "One True Webserver?"

Y'know, the webserver you're going to throw out yours for. The one that's bulletproof and supersonic and Utopian--the kind Jesus would have written--the one that's going save us all?

It's NodeJS. :man_facepalming:
at least for WasmEdge on AWS Lambda, for now

So I hope you like setting up NodeJS in Docker.

What about the "Language Agnosticism" in hosting?

The company behind WasmEdge talks a big game, and they have a platform for Functions as a Service (FaaS). But for various reasons this only works with Rust.

Kind of annoyingly, if you read the docs for develop a WasmEdge app you will see it say:

For compiled languages (e.g., C and Rust), WasmEdge WebAssembly provides a safe, secure, isolated, and containerized runtime as opposed to Native Client (NaCl).

Then you will see it list examples for Rust, JavaScript, Go, Swift, AssemblyScript, Kotlin, Grain, Python

Noticeably missing is C. And that's the one we need.

Without C support for things like sockets, our Ren-C Wasm blob cannot make network requests. We can do filesystem operations, but networking is just not there yet.

(The missing C bits relative to the other languages isn't technically WasmEdge's fault...it's just that the libc implementation for Wasi doesn't have some things that the Rust standard library does. I just wish they'd explained the details of how they got the other languages to work built upon Rust...rather than leaving it as an exercise for the reader to delve into it all to figure out.)

But Stay Tuned...

This is a pretty major development, and things are moving fast. I want @gchiu to keep the eyes on the prize here, and we see what we can do to make sure we've got some demos rolled out in this space. As we find ways to bring more features online, I'll let you know.

4 Likes

4 posts were split to a new topic: Networking Calls from Ren-C WASI Build?

Rebol has for many years been at the forefront of personal computing so it's good to see it head back that way even it is personal cloud computing.

Could you please provide a Ren-C WASI stack update?

If I got everything right, the runtime can get permissions to access a local directory (using runtime command line parameters).

I hadn't really messed with it in the past year, but since you asked I went and bumped the WASI SDK version we build against from v16 to v20. There was a little debugging I had to do to get it to work, but it's working.

Yes (e.g. WasmEdge lets you map --dir guestdir:hostdir and through %guestdir/* you can access files in %hostdir/* (read-write or read-only).

But we now use libuv for filesystem and networking abstractions in the desktop build... and there's no WASI target for libuv. (...and WASI's subset of Posix is insufficient to be able to use the libuv Posix target.)

Yet since they do offer some translation between simple C filesystem calls and the WASI layer, I did a little proof of concept by adding BASIC-READ and BASIC-WRITE functions, with this little test:

wasmedge --dir x:. r3.wasm --do \
    "print {Begin}, basic-write %x/test.txt {Test}, print {End}"

wasmedge --dir x:. r3.wasm  --do \
    "either {Test} = as text! basic-read %x/test.txt [print {Yay}] [fail]"

r3 --do \
      "if {Test} = as text! read %test.txt [print {Verified}] else [fail]"

And it works.

WASI is generally meant to be run by a native Wasm runtime. But the WASI-built blobs can be loaded into browsers if one wants to, there are various experiments.

Here is one such experiment: https://runno.dev/wasi

And here is a WASI blob I made that you can upload in there and it sort of works, when you turn echo on in the settings:

http://hostilefork.com/media/shared/wasi/r3.wasm

But bear in mind that blob was built for WasmEdge, which supports neither Wasm exceptions nor setjmp()/longjmp() emulation. So any error or typo will crash it.

(This should change soon, as Wasm exceptions have just been pushed on a branch this week in WasmEdge.)

If you write a file with BASIC-WRITE there, it will let you download it from the browser. In terms of leveraging the browser's ability to grant access to files on your local system, that's something I haven't kept up with but my understanding is that people have pushed to make it possible. That particular demo doesn't do that particular thing.

In any case, it's still a pretty diverse set of scenarios with pros and cons for every choice. I think serverless routines is the near-term sweet spot for WASI (as opposed to overtaking the need for .EXEs on desktops). And the richness and interoperability with the browser of the ReplPad is a lot more interesting than running a WASI blob in a dumb terminal emulated in a webpage. But it's good to have options.

2 Likes

In terms of how far away WASI blobs are from being a replacement for .EXEs on your desktop, I'll point out this thread about the lack of "termios" (things letting you move the cursor around the screen and draw, as well as accept and react to a keypress instantly without needing to wait until a line of input is entered with RETURN):

missing termios.h functionality · Issue #161 · WebAssembly/WASI · GitHub

They mention that some of the holdup is because of security concerns... they don't want to blindly parrot old APIs that were designed without an eye toward security. Security and near-native speed are the two big focus points for what WASI workloads are worried about.

The danger here is that if they don't standardize something, WASI runtimes like WasmTime or WasmEdge or any of the others might go their own way, and implement something ad-hoc. Then you'd end up in a situation where depending on what runtime you were using you'd have to write different code for REPLs... which would just mirror the situation where Windows and UNIX don't have compatible interfaces, and that would motivate a higher-level package like ncurses.

Long story short: I don't imagine you'll want to use WASI blobs interactively for consoles until this sorts out, which won't be any sooner than several years from now. That's going to be the domain of ReplPad and the platform-specific .EXEs for some time to come.

But you could use a %r3.wasm plus %some-script.reb (or encap them together for r3-some-script.wasm) and passing it arguments to do data processing tasks that are able to run anywhere... cloud, browser, various desktops.

Looking into it further, this has already happened with a fork of the WASI spec called "WASIX", that is only supported in the Wasmer runtime.

https://wasix.org/

I went through some hassles to get Ren-C built against it with the Posix terminal code enabled, and verified you can indeed react to single key presses and cursor around in the console. But Wasmer does not implement Wasm exceptions yet, and their support for the setjmp()/longjmp() alternative is a step back to the pre-Stackless methods of Emscripten... and it appears to be buggy. So you still wind up crashing any time there's an error raised.

Further, I discovered its support for Posix seems pretty far from being thorough enough to run libuv's Posix implementation on. The effort seems skeletal enough that it won't be able to do that any time soon.

Also...sentiment on HackerNews seems to be that Wasmer is a black sheep in the community, as pushing for something that makes WASI blobs only execute in one runtime is against the mission.

Hence I was likely correct about WASI .wasm blobs being unlikely to be the delivery vehicle for desktop Ren-C consoles anytime soon.

2 posts were split to a new topic: Building C++ GUI Code that Calls Ren-C Wasm and Runs in Browser