What primarily brings you to using backend WASM rather than deploying Go natively?
Then don't worry [...] high performance programming" is ill defined. For the term to have any real meaning one has to be more specific about what one tries to achieve.
My main "high performance" experience is of writing WebVR applications. VR can't tolerate framerate drops because it makes users physically sick.
I don't know what the GC story is like for Go in WASM but it would make me very wary.
To be clear: I'm not using WASM in any backends right now, but I would like to.
The two main use-cases for me would be data transformation and message routing or decision logic that is maintained by the user. That is, the user develops the code to parse custom data formats and emit them in various other data formats, tests and compiles it locally and then uploads it into the backend to be instantiated and run. Ditto for routing/decision logic. (So typical "reactor" usage).
Having third parties produce Go binaries to do this would be resource intensive and awkward.
One of our projects is an IoT platform where we get lots and lots of messages from devices. Some of these devices are very constrained and use, or want to use, space efficient custom data formats. However, they'd like to make the data available in more practical formats for consumers. Hence the need to be able to transform them to one or more other formats in real-time. I'd like to let the customers to be able to write these codecs.
There are a few other uses as well that we are looking at, but common for all of them is that none of them need a generic system interface. Typically you want to project some API(s) into the runtime that the code can call.
(I'm also on the lookout for ways to embed compilers in the backend so customers can edit code in a web interface and compile it in the backend, but embedding compilers has proven to be ... not incredibly fun)
How do you enforce a contract on these WASI artefacts? How do you stop the user doing bad things (like infinite loops or crashing the surrounding program)?
The short answer is: I don't know and those are valid concerns.
The first issue you bring up is really one about resource limiting. You would want a mechanism to set resource limits (CPU, memory, execution time etc) and then be able to pause/unpause, throttle, terminate, restart or perform some other action when you hit a resource limit. It is safe to assume people will make mistakes. :-)
It has been a while since I looked at runtimes, but I don't think resource limits would necessarily be that hard to implement.
It seems to me that preventing crashing the surrounding program isn't something you can necessarily address in a runtime. Any library or component you use in your Go code can potentially crash the program. And if you project APIs into the sandbox that can be called in ways that crash the surrounding program, that's mostly on you, the programmer, and not really something I think the runtime could reasonably prevent.
You can do this with wasmtime using either a deadline trap or a concept called "fuel" which is basically a measure of "consumed CPU time" roughly speaking. I have used wasm for a very similar thing (user writing code for robots in a multiplayer video game) and it works very well. I am confident they can't mess with the server and I can prevent them from running long running processes.
For wazero (mentioned in the article) WASI capabilities can be granted piecemeal: (e.g.) the host can grant/deny access to the clock or implement a virtual one. Obviously, you can do the same with the file system, etc.
Guest crashes become panics the host can recover from.
Finally, you can use a Context to abort execution of the guest, although this option introduces a performance penalty: every backjump must read a counter to periodically poll this context.
That said there are issues when running adversarial code.
The default WASI filesystem implementation is not really meant for sandboxing. When you mount a host folder in the guest, it's possible for the guest to escape the root. You can improve the situation by using virtual files, but that's more work if you want anything sophisticated. WASI is simultaneously too sophisticated to make it hard/slow to emulate+sandbox (symlinks and Unix path resolution), and lacking important features.
There are little to no protections against speculative execution (i.e spectre) attacks. With memory bounds checks implemented in software, you're bound to leak information that way.
So please: don't mix multiple customers custom code in one Go host process. It's not really meant for that.
Allowing your single customer (per host/VM) to customize your product with some plugins, giving some tought about filesystem access (to prevent privilege escalation), is more realistic.
Well, now you have defined what you mean (realtime'ish execution low/no latency variance). The next step would be to formulate a test and see if it is actually a problem and then make technology choices. Just assuming isn't really professional.
You can always find use-cases where GC'ed languages might be challenging to use. With emphasis on "might", because you kind of have to try it out before you can determine if it is a problem.
There are a lot of high performance applications where they're just fine. For instance if you care more about throughput than latency variance. This is why "high performance" isn't a useful term. You have to be specific about how you measure "performance".
Most of the code for most developers isn't terribly performance critical. Correctness is usually far more important. Most performance tends to be lost due to lack of design talent rather than the language.
I don't know what the GC story is like for Go in WASM but it would make me very wary.