Front Line (Web) Assembly
Background
The approach I took was to create a "helper function" which provides a bare minimum interface between Fn and the function.
This is all well and good, but it is not a full FDK. Some of the capabilities of the supported FDKs are absent. For example, the helper is not aware of values that have been configured for the function or application via the context.
So in this post, I want to explore a different approach, which will
- enable the capabilities of the provided FDKs
- support functions in a language for which there is no FDK
WebAssembly
WebAssembly ("wasm") is an open standard W3C that defines a portable binary format. By compiling code to WebAssembly we are able to run it in a browser. This means that developers can
- write code in a language other than JavaScript
- compile it to WebAssembly
- run it in the browser
WebAssembly is supported in the current versions of all major browsers.
Interestingly it is also possible to run WebAssembly in
Node.js.
Polyglot Functions: Node and WebAssembly
So if we write our functions in a language that can be compiled to WebAssembly, then we should be able to run those functions in Node.js. Since there is an FDK for Node.js, this means we can leverage the capabilities of the FDK to run our WebAssembly function.
Rust
Rust is a comparatively new language that has generated
a lot of interest in the developer community since its launch. It is statically typed, compiled and fast. It has generated particular interest from teams who are concerned about
memory safety, due to its innovative approach to memory management.
Once you have compiled your Rust code to create a WebAssembly package, you can publish this with npm, and use it like a regular JavaScript package.
So we should be able to
- Write our function code in Rust
- Create a WebAssembly package
- Publish the package to npmjs
- Create a Node.js function in the usual way
- Reference the WebAssembly package in package.json
- Call the methods in the package from our JavaScript code in the usual way
To build WebAssembly packages from Rust, we're going to use a tool called
wasm-pack.
Building the Function
Setup
To build
this example, we need to do the following (if not already installed):
Install RustOnce Rust is installed, install wasm-pack:
cargo install wasm-pack
Install Node.js
Install the Fn CLI to build functions and deploy them to the Oracle Functions service (preferred) or in a local test environment. If you're using OCI Cloud Shell the Fn CLI is already installed
You'll need to configure your context for the Fn CLI. Follow the appropriate instructions for:
Then create an app to deploy your functions to.
All the code in this sample is available on
GitHub.
Create a WebAssembly package with wasm-pack
Run the following command:
$ wasm-pack new rust-fn
Add serialisation support
If we want to be able to serialise and deserialise objects between Rust and JS then we need to modify the Cargo.toml file so that the [dependencies] section matches the example:
Expose Rust Functions
Edit the /src/lib.rs file so that it matches the example:
The key here is the annotations
The main one to consider is:
#[wasm_bindgen]
Functions with this annotation will be able to be called from JavaScript.
The other important annotations are:
#[derive(Serialize)]
#[derive(Deserialize)]
These declare the associated type to be serialisable or deserialisable.
There are two styles of function in this example. The simplest use strings to pass data to and from JavaScript, and the others (with the suffix _json) use JSON and serialization
Compile the Package
Run
wasm-pack build --target nodejs --scope <your-node-js-user-id>
This will create a package that can be used from node, and published to npm.
From the pkg directory, run the following to publish your package:
npm publish --access=public
Creating functions
You can now run fn init in the usual way to create a function:
fn init --runtime node <function-name>
Edit the package.json to include your package (mine is @crush-157/rust-fn)
Then you can reference the package in JavaScript and call it's functions in the usual way.
Sample Functions
There are two sample functions in this example:
lazy-rust
The JSON payload is parsed in JavaScript
busy-rust
The JSON payload is parsed by the Rust function
It's up to you whether you'd rather parse JSON in JS and pass it to the function (possibly easier but not terribly elegant), or pass the JSON to Rust and parse it there (maybe a bit more work but cleaner).
So now we can use the Node FDK to run functions written in any language that compiles to WebAssembly.
Comments
Post a Comment