Example app & project structure for Golem Cloud

Overview

Synopsis

This project serves as an example/template for building an application using WebAssembly Component Model (and in this case, an app for Ziverge's Golem Cloud. It is my recommendation on how to structure such a project.

Problem statement

The cargo-component project by Bytecode Alliance greatly smooths out the development process in building WebAssembly Component Model applications (in Rust). You will define your app's public data structures (records and enums) and function interfaces in a wit (Wasm interface type) file, which is then used to generate the Rust bindings for your Wasm component. The generated code sits in a module somewhere inside the target directory. Running cargo component build will build a valid codebase successfully.

Sadly, as of this writing, the regular Rust tooling (e.g. rust-analyzer) lacks visibility to this module. As a result, red squiggly lines will likely appear in our IDE for any data types defined in the wit file. Additionally, cargo test will fail because it cannot resolve those references.

This is the motivation of creating a project structure that allows us to follow the development process we have accustomed to: write and run tests locally, as well as running them on CI.

Although discussing the merits (and the associated costs) of writing (and maintaining) tests is out of scope here, the ability to test our apps locally in this case can be quite desireable. Even though it's feasible to test and debug our apps directly in the cloud, the feedback loop of such practice is much slower, let alone the time wasted on rebuilding and redeploying apps. This project (template) makes it possible to run tests without having to change or disable regions of our Wasm component code merely for testing purposes. It's my current recommendation on building WASI apps until cargo-component improves (or better alternatives become available).

Before I start the walkthrough and explain the project structure, make sure you have set up Rust's toolchain and installed cargo-component. Please refer to Golem Cloud documentation for instructions.

Workspace structure

1. Core module

The core business logic of our application goes into the lib module, where our code can be organized into logical units and only a select set of functions (and structs) are exposed as public APIs. This is quite common in Rust applications.

Like most Rust apps, we can write unit tests in each sub-module as well as integration tests in a separate tests module.

To run tests at the project's root, simply do cargo nextest run -p lib. (I highly recommend using cargo-nextest as the test runner.) Note the -p parameter at the end of the command -- we are passing the name of this module as the value.

We can also check test coverage by running cargo tarpaulin -p lib. (Run cargo install cargo-tarpaulin to add the sub-command.)

2. Console app

This one is optional. However, I feel it's beneficial to build a console app, which not only provides us a way to system-test our APIs defined in the lib module but, rather importantly, it can guide us through the process of designing the APIs, especially in the early iterations. While calling the APIs in a console app might be slightly different than calling them from the Wasm component (because the execution flow may likely be different), we can still try to mimic, as much as possible, the cloud API flow (exposed by the Wasm component -- we're speaking in the context of running it on Golem Cloud here). By doing so, this console app shall give us a very close feel of how our APIs will work. This will provide a fast feedback loop and allow us to iterate quicker and with more confidence; at the same time it should help minimize the potential of a bad API design.

To run the console app at the project root, do cargo run -p app. Again, we will pass the -p parameter and specify the app module. If you want to produce a binary of the console app, running cargo build -p app will produce the executable as target/debug/app (or target/release/app if the --release flag is included in the build command).

3. Wasm app

Now that we have tests and the console app to guide the implementation, we should have a very good idea of how our APIs will look like. Thereby, we shall express our APIs in the wit file. Next, we will add some boilerplate code in the wasm module to glue the Rust bindings to our Wasm implementation. Please refer to the code in wasm\lib.rs as well as Golem's documentation. The implementation in the Wasm module should be fairly trivial and quite similar to that of the console app.

To build the Wasm assembly, run cargo component build --release -p wasm at the root of our project directory. This will produce the target/wasm32-wasi/release/fib.wasm file in this case.

Running the app on Golem Cloud

As a quick reference, here are the steps to run this app on Golem Cloud. For details of various commands, please refer to Golem CLI documentation as well as its built-in help.

Upload this app and run it on Golem Cloud:

  1. Download the latest version of Golem CLI by signing up for the Developer Preview.
  2. Unzip the bundle to a directory.
  3. Define a shell alias to the Golem CLI for convenience. For example:
alias golem='{path-to-directory}/golem-cli/bin/golem'
  1. Run golem account get to go through the authorization process if you haven't done so.
  2. cd back to our project directory.
  3. Run the following command to upload the binary.
golem component add --component-name fib target/wasm32-wasi/release/fib.wasm
  1. Next, run this command to create an instance of our app.
golem instance add --instance-name fib-instance-1 --component-name fib
  1. Let's define another shell alias to invoke the instance. For example:
alias fib='golem instance invoke-and-await --instance-name fib-instance-1 --component-name fib --function $*'

Note: invoke-and-await is akin to Akka's ask pattern whereas the invoke command is fire-and-forget.

  1. At last let's run our app! 🎉
  • Run the next command to get the next Fibonacci number. Repeat it a few times to verify that it produces the correct Fibonacci sequence.
fib golem:fib/api/next --parameters '[]'
  • Run the reset command to start over from 0.
fib golem:fib/api/reset --parameters '[]'

Congratulations! We have written, deployed and executed our first Golem app!

Bonus

Now that we know our app is running as expected, we can test out the promise of Golem Cloud that apps are resilient and their states are preserved between interruptions.

We can interrupt our app by executing:

golem instance interrupt --instance-name fib-instance-1 --component-name fib

(or simulate a crash with golem instance simulated-crash --instance-name fib-instance-1 --component-name fib).

After that, run fib golem:fib/api/next --parameters '[]' again and verify that the Fibonacci number continues from that of the last invocation.

Homework

I can tell you there is a bug somewhere in this implementation. Can you identify it as an exercise? If so, give it a shot at fixing it. PRs are welcome! 🙂 I have something in mind for the fix (I actually have a reason why I don't want to fix it 😝 ) but I'm interested in other solutions.

Thanks for reading 🙏 and have fun writing Golem apps!

P.S.

This project is definitely very very simple! For (slightly) more complex apps, check out my other Golem's projects here and here.

You might also like...
Automatically build a Rust module tree from the project directory structure

Hypermod An even lazier version of automod and supermod. Searches the src/ directory recursively for .rs files, then builds a module tree using the di

A simple CLI tool to create python project file structure, written in Rust
A simple CLI tool to create python project file structure, written in Rust

Ezpie Create python projects blazingly fast What Ezpie can do? It can create a python project directory What kind of directory can Ezpie create? For c

example of a full stack web app (backend and frontend) wrtiten in Rust

rust-fullstack-example An example of creating a full stack web application (backend and frontend) using Rust. Backend Go to ./backend and start the se

An example app in Rust for CircleCI's Dynamic Config demo
An example app in Rust for CircleCI's Dynamic Config demo

circleci-dynamic-config-example An example app in Rust for CircleCI's dynamic config demo. Dynamic config allows you to dynamically generate CircleCI'

iOS app example - AI Selfies Generator like Lensa: Stable Diffusion In Action
iOS app example - AI Selfies Generator like Lensa: Stable Diffusion In Action

Magic Avatars In this repository, we look at several approaches to creating avatars, changing backgrounds, and deep image processing for more detailed

An example project showing usage of CMake with Rust

An example of using CMake with Rust. Try it! mkdir build cd build cmake .. -DCMAKE_INSTALL_PREFIX=/tmp make -j make test -j make doc -j make install

An example project demonstrating integration with Rust for the ESP32-S2 and ESP32-C3 microcontrollers.

Rust ESP32 Example An example project demonstrating integration with Rust for the ESP32-S2 and ESP32-C3 microcontrollers.

A basic rp2040-hal project with blinky and rtt logging example code.

A basic rp2040-hal project with blinky and rtt logging example code. With this you can quickly get started on a new rp2040 project

The point of this anchor project is to serve as a starter kit or example to compose with mango-v3 using anchor.

The point of this anchor project is to serve as a starter kit or example to compose with mango-v3 using anchor. It currently provides 2 examples and various inline todos on how to extend this.

Example NFT marketplace project using ink! smart contract.

NFT Marketplace project This contract is an example for the NFT marketplace implementation. License Apache 2.0 🏗️ How to use - Contracts 💫 Build Use

This is an example Nostr rust project to enable '402 Payment Required' responses for requests to paid content.

Nostr Paywall Example This is an example Nostr rust project to enable 402 Payment Required responses for requests to paid content. To prove payment, a

A collection of example project using Njord.
A collection of example project using Njord.

Example Projects A collection of example project using Njord. Contributors The following contributors have either helped to start this project, have c

An API and test-app that exposes zcash functionality for app consumption

Zingolib This repo provides both a library for zingoproxyclient and zingo-mobile, as well as an included cli application to interact with zcashd via l

A todo list app that indexes your app to find TODO:'s

forgot A todo list app that indexes your app to find TODO:'s Usage to list all your todos forgot list list all your todos ignoring search in ./target,

Create a Python project automatically with rust (like create-react-app but for python)

create-python-project Create a Python project automatically with rust (like create-react-app but for python) Installation cargo install create-python-

The Heros NFT Marketplace Boilerplate project is designed to let users fork, customize, and deploy their own nft marketplace app to a custom domain, ultra fast.

Heros NFT on Solana The Heros NFT Marketplace Boilerplate project is designed to let users fork, customize, and deploy their own nft marketplace app t

Mac App/CLI that automatically adds project logos to your locally cloned GitHub repos
Mac App/CLI that automatically adds project logos to your locally cloned GitHub repos

Download the app Automatically adds project logos to your locally cloned GitHub repos. Youtube Video This repository contains the source code for the

Create That Project. Project Creation That Rocks 🎸🧱.
Create That Project. Project Creation That Rocks 🎸🧱.

Create That Project Config Example Install $ cargo install ctp Basic Info In any file or even in the commands sections of your config file you can pla

Help project managers and project owners with easy-to-understand views of github issue dependencies.
Help project managers and project owners with easy-to-understand views of github issue dependencies.

Help project managers and project owners with easy-to-understand views of github issue dependencies.

Owner
Terry L
FP dev: zio, cats
Terry L
Wasm video filter booth app written in Rust

Video effect booth written in Rust and WebAssembly Play with it here: https://mtharrison.github.io/wasmbooth/ Aim I wrote this purely to teach myself

Matt Harrison 75 Nov 21, 2022
wasmy, easily customize my wasm app

wasmy wasmy, easily customize my wasm app! features Completely shield vm-wasm interaction details Simple and flexible ABI, supports freely adding vm a

henrylee2cn 21 Jul 22, 2022
Dister builds and bundles your wasm web app.

dister Dister builds and bundles your wasm web app. Installation cargo install dister Requirements wasm32-unknown-unknown target: rustup target add wa

Mohammed Alyousef 1 Apr 9, 2022
A template project to demonstrate how to run WebAssembly functions as sidecar microservices in dapr

Demo and tutorials Live Demo | Tutorial article | Tutorial video 1. Introduction DAPR is a portable, event-driven runtime that makes it easy for any d

Second State 184 Dec 29, 2022
A template for kick starting a Rust and WebAssembly project using wasm-pack.

A template for kick starting a Rust and WebAssembly project using wasm-pack.

Haoxi Tan 1 Feb 14, 2022
Easy c̵̰͠r̵̛̠ö̴̪s̶̩̒s̵̭̀-t̶̲͝h̶̯̚r̵̺͐e̷̖̽ḁ̴̍d̶̖̔ ȓ̵͙ė̶͎ḟ̴͙e̸̖͛r̶̖͗ë̶̱́ṉ̵̒ĉ̷̥e̷͚̍ s̷̹͌h̷̲̉a̵̭͋r̷̫̊ḭ̵̊n̷̬͂g̵̦̃ f̶̻̊ơ̵̜ṟ̸̈́ R̵̞̋ù̵̺s̷̖̅ţ̸͗!̸̼͋

Rust S̵̓i̸̓n̵̉ I̴n̴f̶e̸r̵n̷a̴l mutability! Howdy, friendly Rust developer! Ever had a value get m̵̯̅ð̶͊v̴̮̾ê̴̼͘d away right under your nose just when

null 294 Dec 23, 2022
SKYULL is a command-line interface (CLI) in development that creates REST API project structure templates with the aim of making it easy and fast to start a new project.

SKYULL is a command-line interface (CLI) in development that creates REST API project structure templates with the aim of making it easy and fast to start a new project. With just a few primary configurations, such as project name, you can get started quickly.

Gabriel Michaliszen 4 May 9, 2023
A Modern Real-Time Data Processing & Analytics DBMS with Cloud-Native Architecture, built to make the Data Cloud easy

A Modern Real-Time Data Processing & Analytics DBMS with Cloud-Native Architecture, built to make the Data Cloud easy

Datafuse Labs 5k Jan 9, 2023
A Modern Real-Time Data Processing & Analytics DBMS with Cloud-Native Architecture, built to make the Data Cloud easy

A Modern Real-Time Data Processing & Analytics DBMS with Cloud-Native Architecture, built to make the Data Cloud easy

Datafuse Labs 5k Jan 9, 2023
A command-line utility that creates project structure.

petridish A command-line utility that creates project structure. If you have heard of the cookiecutter project, petridish is a rust implementation of

null 11 Dec 29, 2022