Flawless Logo, a beautiful woman with freckles head illustration. flawless.dev

Your First Workflow

First, you will need to start the Flawless server with:

$ flawless up

Setting up a cargo project

Let's now use cargo flw to create a new Flawless project:

$ cargo flw new hello-workflow
$ cd hello-workflow

Running cargo flw new will have a similar result to running (cargo new), but it adds a few Flawless specific configuration options to the project:

1. .cargo/config.toml

The default compilation target is set to wasm32-unknown-unknown.

target = "wasm32-unknown-unknown"

2. Cargo.toml

When compiling to WebAssembly, the crate-type needs to be set to cdylib. Also, the flawless and log crates are added as dependencies.

# ... truncated ...

crate-type = ["cdylib"]

flawless = "1.0.0-alpha.16"
log = "0.4"

3. src/lib.rs

Workflows in flawless are just regular Rust functions that are annotated with the #[workflow("<name>")] macro. You can have multiple of them inside one project.

Printing to standard output is not supported from a workflow, but you can use the log crate for logging. Flawless will set up a logging environment for each workflow automatically.

use flawless::workflow;
use log::info;

fn hello_workflow() {
    info!("👋 Hello from a workflow!");

Running the workflow

To run the workflow you can use the cargo flw run command:

$ cargo flw run hello_workflow

This will build the project, upload it to the flawless server and trigger the hello_workflow workflow. The workflow just prints out "👋 Hello from a workflow!" to the log. You can observe the output in the terminal window where you started flawless up.

The durability part of flawless

To demonstrate the durability part of Flawless, let's open the src/lib.rs file and replace the existing code with:

use flawless::{exe::sleep, log, workflow};
use std::time::Duration;

fn hello_workflow() {
    for i in 0..30 {
        log::info!("👋 Hello from a workflow! {i}");

You can again start the workflow with:

$ cargo flw run hello_workflow

This workflow runs for 1 minute and just prints a greeting message every 2 seconds.

To test the durability, you can abruptly stop the server with Ctrl+C or using the killall flawless command. And next time you bring up the server again with flawless up, the execution should pick up exactly where it stopped.

This is a very important property of Flawless. It implicitly "remembers" the exact point in code where the execution was interrupted, but it does so by only saving the minimal amount of information to reconstruct the state. Every other feature that Flawless has is a result of this guarantee.

Workflow performing HTTP requests

Let's look now at a bit more complicated workflow that performs HTTP requests, fetches 10 dad jokes and logs them.

First we need to add another dependency to flawless, an HTTP client:

flawless = "1.0.0-alpha.16"
flawless-http = "1.0.0-alpha.16"
log = "0.4"

Now let's update the src/lib.rs file with the implementation:

use std::time::Duration;

use flawless::{exe::sleep, workflow};
use flawless_http::get;

fn dad_joke_api() {
    for i in 1..11 {
        let request = get("https://icanhazdadjoke.com/")
                        .set_header("Accept", "application/json");
        let response = request.send().unwrap();
        let response_txt = String::from_utf8(response.body()).unwrap();
        log::info!("Dad Joke {i}: {}", response_txt.trim());

Notice that the name of the workflow also changed, now you can start it using:

$ cargo flw run dad_joke_api

You will see the fetched jokes being printed out in the server window.

Next steps

Flawless is still very early in development and new APIs are being added on a weekly basis. The best way to check what is available is by looking at the API reference.

Check also out workflow fundamentals, for examples on how to pass input values to workflows and how to get some output from them.