Activities

Activities are the fundamental building blocks of work within an Obelisk workflow . They represent individual, idempotent operations that perform a specific task, typically a network activity. Think of them as the "verbs" of your workflow – the actions that get things done. Activities are designed to be resilient, with built-in mechanisms for handling errors and ensuring reliable execution.

Key Characteristics of Activities

Creating an Activity

  1. Definition: You define a workflow as code. Each function must have its signature specified using WIT (WebAssembly Interface Type) IDL. Any language that is supported by wit-bindgen including Rust and Go can be used.

  2. Compilation to WASM: Your activity code is compiled into a WebAssembly Component.

  3. Deployment: Create a new [[wasm_activity]] table with the compiled WASM file location in the Obelisk configuration file.

  4. Execution: The activity can be triggered directly using CLI, WebUI or gRPC, but most commonly it is executed as a step in a workflow . Obelisk persists the execution submission and execution result. If the activity times out, panics(traps) or returns an error, it will be retried after a timeout.

Example - calculating Fibonacci

In this contrived example we will create an activity that does not communicate with an external system. Its purpose is to show the interactions between activities and workflows . First we need to define an interface with a single function using WIT IDL. We will then export the interface.

package template-fibo:activity;

interface fibo-activity-ifc {
    fibo: func(n: u8) -> u64;
}
world any {
    export fibo-activity-ifc;
}

The corresponding bindings are generated automatically using wit-bindgen if we place the WIT file in the wit folder. Then we implement the Guest trait in Rust.

impl Guest for Component {
    fn fibo(n: u8) -> u64 {
        if n == 0 {
            0
        } else if n == 1 {
            1
        } else {
            Self::fibo(n - 1) + Self::fibo(n - 2)
        }
    }
}

In order to simplify creating the Cargo project, you can use cargo-generate:

cargo generate obeli-sk/obelisk-templates fibo/activity --name myactivity
cd myactivity
cargo build --release
obelisk server run

Follow the template's README to execute the activity.

HTTP Client

Activities can make HTTP requests using the WASI 0.2 HTTP client. This allows them to interact with external services and APIs. Importantly, this HTTP client is controlled, with built-in tracing to enhance security and predictability. Disk I/O is not permitted.

Example - WAKI based HTTP client

Instead of using the generated bindings directly we can use the waki HTTP client.

impl Guest for Component {
    fn get(url: String) -> Result<String, String> {
        let resp = waki::Client::new()
            .get(&url)
            .connect_timeout(Duration::from_secs(1))
            .send()
            .map_err(|err| format!("{err:?}"))?;
        let body = resp.body().map_err(|err| format!("{err:?}"))?;
        Ok(String::from_utf8_lossy(&body).into_owned())
    }
}

#[cfg(test)]
mod tests {

    #[test]
    fn integration_test() {
        let url = std::env::var("TEST_URL").expect("TEST_URL must be set");
        let body = Component::get(url).unwrap();
        println!("body: {body}");
    }
}

This project can be generated using the http-simple template

cargo generate obeli-sk/obelisk-templates http-simple/activity

If you need to use GraphQL, check out the cynic crate and the following template:

cargo generate obeli-sk/obelisk-templates graphql-github/activity

Note: If you need an async HTTP client, use wstd crate instead of waki.

Logging, debugging, testing

To understand the internal state of an activity, you can use the following:

Unit testing is possible with Cargo's test harness.

Run the testing WASM artifact as usual:

cargo test

Make sure to add the following in your .cargo/config.toml, so that the test binary is run with wasmtime or other WASI 0.2 compatible runtime:

[build]
target = "wasm32-wasip2"

[target.wasm32-wasip2]
runner = "wasmtime run -Scli -Shttp  --env TEST_URL"

The stargazers demo repository contains unit and integration tests for activities.