From f6e6c35fd80a3f2a54cdfdeb84b83ca33e62b043 Mon Sep 17 00:00:00 2001 From: Greg Travis Date: Tue, 15 Sep 2026 14:58:04 -0400 Subject: [PATCH 1/6] rust SAA docs --- docs/develop/rust/activities/index.mdx | 2 ++ docs/develop/rust/index.mdx | 1 + docs/encyclopedia/activities/standalone-activity.mdx | 2 ++ docs/quickstarts.mdx | 1 + sidebars.js | 9 +++++++++ 5 files changed, 15 insertions(+) diff --git a/docs/develop/rust/activities/index.mdx b/docs/develop/rust/activities/index.mdx index 21a9f6a37d..eaa7745550 100644 --- a/docs/develop/rust/activities/index.mdx +++ b/docs/develop/rust/activities/index.mdx @@ -22,4 +22,6 @@ import * as Components from '@site/src/components'; - [Activity basics](/develop/rust/activities/basics) - [Activity execution](/develop/rust/activities/execution) +- [Standalone Activities Quickstart](/develop/rust/activities/standalone-activities-quickstart) +- [Standalone Activities Feature Guide](/develop/rust/activities/standalone-activities) - [Timeouts](/develop/rust/activities/timeouts) diff --git a/docs/develop/rust/index.mdx b/docs/develop/rust/index.mdx index 61c03ba94b..dddd4345e8 100644 --- a/docs/develop/rust/index.mdx +++ b/docs/develop/rust/index.mdx @@ -43,6 +43,7 @@ Once your local Temporal Service is set up, continue building with the following - [Activity basics](/develop/rust/activities/basics) - [Activity execution](/develop/rust/activities/execution) +- [Standalone Activities](/develop/rust/activities/standalone-activities-quickstart) - [Timeouts](/develop/rust/activities/timeouts) ## [Workers](/develop/rust/workers) diff --git a/docs/encyclopedia/activities/standalone-activity.mdx b/docs/encyclopedia/activities/standalone-activity.mdx index 79e0d72ee1..332dd42ce3 100644 --- a/docs/encyclopedia/activities/standalone-activity.mdx +++ b/docs/encyclopedia/activities/standalone-activity.mdx @@ -50,6 +50,7 @@ Pick your SDK and follow the quickstart: | [TypeScript](/develop/typescript/activities/standalone-activities-quickstart) | [.NET](/develop/dotnet/activities/standalone-activities-quickstart) | [Ruby](/develop/ruby/activities/standalone-activities-quickstart) +| [Rust](/develop/rust/activities/standalone-activities-quickstart) ::: @@ -229,6 +230,7 @@ Get results, get handles, and list Standalone Activities: | [TypeScript](/develop/typescript/activities/standalone-activities) | [.NET](/develop/dotnet/activities/standalone-activities) | [Ruby](/develop/ruby/activities/standalone-activities) +| [Rust](/develop/rust/activities/standalone-activities) ::: diff --git a/docs/quickstarts.mdx b/docs/quickstarts.mdx index 6275cf92d3..dcadb31da4 100644 --- a/docs/quickstarts.mdx +++ b/docs/quickstarts.mdx @@ -41,6 +41,7 @@ Run an Activity from a Temporal Client without writing a Workflow. { href: "/develop/dotnet/activities/standalone-activities-quickstart", title: ".NET", description: "Execute a Standalone Activity with the .NET SDK." }, { href: "/develop/python/activities/standalone-activities-quickstart", title: "Python", description: "Execute a Standalone Activity with the Python SDK." }, { href: "/develop/ruby/activities/standalone-activities-quickstart", title: "Ruby", description: "Execute a Standalone Activity with the Ruby SDK." }, + { href: "/develop/rust/activities/standalone-activities-quickstart", title: "Rust", description: "Execute a Standalone Activity with the Rust SDK." }, { href: "/develop/typescript/activities/standalone-activities-quickstart", title: "TypeScript", description: "Execute a Standalone Activity with the TypeScript SDK." }, ]} /> diff --git a/sidebars.js b/sidebars.js index 21328419e5..094752f5b5 100644 --- a/sidebars.js +++ b/sidebars.js @@ -918,6 +918,15 @@ const developRustCategory = { items: [ 'develop/rust/activities/basics', 'develop/rust/activities/execution', + { + type: 'category', + label: 'Standalone Activities', + collapsed: true, + items: [ + 'develop/rust/activities/standalone-activities-quickstart', + 'develop/rust/activities/standalone-activities', + ], + }, 'develop/rust/activities/timeouts', ], }, From 4a225ae2c22a5fe166e2f3ef5d22e10f631305f9 Mon Sep 17 00:00:00 2001 From: Greg Travis Date: Tue, 15 Sep 2026 15:07:13 -0400 Subject: [PATCH 2/6] rust SAA docs --- .../standalone-activities-quickstart.mdx | 294 +++++++++++++++ .../rust/activities/standalone-activities.mdx | 350 ++++++++++++++++++ 2 files changed, 644 insertions(+) create mode 100644 docs/develop/rust/activities/standalone-activities-quickstart.mdx create mode 100644 docs/develop/rust/activities/standalone-activities.mdx diff --git a/docs/develop/rust/activities/standalone-activities-quickstart.mdx b/docs/develop/rust/activities/standalone-activities-quickstart.mdx new file mode 100644 index 0000000000..2b14d92075 --- /dev/null +++ b/docs/develop/rust/activities/standalone-activities-quickstart.mdx @@ -0,0 +1,294 @@ +--- +id: standalone-activities-quickstart +title: Standalone Activities Rust Quickstart +sidebar_label: Quickstart +description: Execute a Standalone Activity with the Temporal Rust SDK without writing a Workflow. +tags: + - Activities + - Temporal Client + - Rust SDK + - setup + - getting started +hide_table_of_contents: true +--- + +import { SetupSteps, SetupStep, CodeSnippet } from '@site/src/components'; + +# Quickstart + +Standalone Activities are Activities that run independently, without being orchestrated by a +Workflow. Instead of executing an Activity from within a Workflow Definition using +`ctx.execute_activity()`, you execute a Standalone Activity directly from a +[`Client`](https://docs.rs/temporalio-client/latest/temporalio_client/struct.Client.html). + +The way you write the Activity and register it with a Worker is identical to [Workflow +Activities](/develop/rust/activities/basics). The only difference is that you execute a Standalone +Activity directly from your Temporal Client. + +:::note + +This documentation uses source code from the +[standalone_activity](https://github.com/temporalio/sdk-rust/tree/main/crates/sdk/examples/standalone_activities) +sample. + +::: + + + + + +{`brew install temporal`} + + +{`temporal --version`} + + +{`temporal server start-dev`} + + +}> + +## Get started with Standalone Activities {/* #get-started */} + +Prerequisites: + +- **Rust** 1.92.0+ + +- **Temporal Rust SDK** (v1.0.0 or higher). See the [Rust Quickstart](/develop/rust/quickstart) for install instructions. + +- **Temporal CLI** v1.9.1 or higher. Install with Homebrew, or see the [Temporal CLI install guide](/cli/setup-cli) for other platforms. Verify the installation with `temporal --version`. + +Start the Temporal development server with `temporal server start-dev`. + +This command automatically starts the Temporal development server with the Web UI, and creates the `default` Namespace. +It uses an in-memory database, so do not use it for real use cases. + +The Temporal Server will now be available for client connections on `localhost:7233`, and the +Temporal Web UI will now be accessible at [http://localhost:8233](http://localhost:8233). + + + + + +{`[dependencies] +futures = "0.3" +temporalio-client = "1.0.0" +temporalio-macros = "1.0.0" +temporalio-sdk = "1.0.0" +tokio = { version = "1", features = ["full"] } +`} + + +}> + +## Clone the sample + +Clone the [sdk-rust](https://github.com/temporalio/sdk-rust) repository to follow along: + +```bash +git clone https://github.com/temporalio/sdk-rust.git +cd sdk-rust/crates/sdk +``` + +The sample consists of separate programs in the `crates/sdk/examples/standalone_activities` directory: + +``` +standalone_activities/ +├── activities.rs # Activity definition, shared by the programs below +├── worker.rs # Worker that processes Activity Tasks +├── execute_activity.rs # Executes an Activity and waits for the result +├── start_activity.rs # Starts an Activity without blocking +├── get_activity_handle.rs # Gets a handle to an existing Activity +├── list_activities.rs # Lists Activity Executions +└── count_activities.rs # Counts Activity Executions +``` + +To write the same code in your own project, add the dependencies shown here to your `Cargo.toml`. +Standalone Activities need `temporalio-client` for the Client, `temporalio-sdk` and +`temporalio-macros` for the Activity and Worker, and `tokio` as the async runtime. `futures` is +needed to consume the stream returned by `list_activities`. + + + + + +{`use temporalio_macros::activities; +use temporalio_sdk::activities::{ActivityContext, ActivityError}; + +pub struct GreetingActivities; + +#[activities] +impl GreetingActivities { + #[activity] + pub async fn compose_greeting( + _ctx: ActivityContext, + input: (String, String), + ) -> Result { + let (greeting, name) = input; + Ok(format!("{greeting}, {name}!")) + } +}`} + + +}> + +## Define your Activity {/* #define-activity */} + +An Activity in the Temporal Rust SDK is an `async` method on an `impl` block marked with the +`#[activities]` macro, annotated with `#[activity]`. The way you define a Standalone Activity is +identical to how you define an Activity orchestrated by a Workflow. In fact, the same Activity can +be executed both as a Standalone Activity and as a Workflow Activity. + +Each Activity method takes an +[`ActivityContext`](https://docs.rs/temporalio-sdk/latest/temporalio_sdk/activities/struct.ActivityContext.html) +as its first parameter and returns `Result`. Use `_ctx` if you don't need the +context. To pass more than one value to an Activity, take them as a tuple, as +`compose_greeting` does here. + +By default, the macro names each Activity `::`, so this one registers as +`GreetingActivities::compose_greeting`. That's the name to use from the Temporal CLI and in [List +Filter](/list-filter) queries. + +[activities.rs](https://github.com/temporalio/sdk-rust/blob/main/crates/sdk/examples/standalone_activities/activities.rs) + + + + + +{`use temporalio_client::{ + Client, ClientOptions, Connection, envconfig::LoadClientConfigProfileOptions, +}; +use temporalio_sdk::{Runtime, Worker, WorkerOptions}; + +#[tokio::main] +async fn main() -> Result<(), Box> { + let runtime = Runtime::from_current_tokio(Default::default())?; + + let (connection_options, client_options) = + ClientOptions::load_from_config(LoadClientConfigProfileOptions::default())?; + let connection = Connection::connect(connection_options).await?; + let client = Client::new(connection, client_options)?; + + let worker_options = WorkerOptions::new("standalone-activities") + .register_activities(GreetingActivities) + .build(); + + let mut worker = Worker::new(&runtime, client, worker_options)?; + println!("Starting worker (ctrl+c to exit)"); + worker.run().await?; + + Ok(()) +}`} + + +{`cargo run --features examples --example standalone-activities-worker`} + + +}> + +## Run a Worker with the Activity registered {/* #run-worker */} + +Running a Worker for Standalone Activities is the same as running a Worker for Workflow Activities — +you build [`WorkerOptions`](https://docs.rs/temporalio-sdk/latest/temporalio_sdk/struct.WorkerOptions.html) +for a Task Queue, register the Activities with `register_activities`, and call `worker.run()`. The +Worker doesn't need to know whether the Activity will be invoked from a Workflow or as a Standalone +Activity, and a Worker that runs Standalone Activities needs no registered Workflows at all. See +[How to run a Worker](/develop/rust/workers/worker-process) for more details on Worker setup and +configuration options. + +[worker.rs](https://github.com/temporalio/sdk-rust/blob/main/crates/sdk/examples/standalone_activities/worker.rs) + +Open a new terminal, navigate to the `crates/sdk` directory, and run the Worker. +Leave this terminal running — the Worker needs to stay up to process activities. + + + + + +{`let options = ActivityStartOptions::with_start_to_close_timeout( + "standalone-activities", + "standalone-activity-id", + Duration::from_secs(10), +) +.build(); + +let handle = client + .start_activity( + GreetingActivities::compose_greeting, + ("Hello".to_string(), "Temporal".to_string()), + options, + ) + .await?; + +let result = handle.result().await?; +println!("Activity result: {result}");`} + + +{`cargo run --features examples --example standalone-activities-execute`} + + +{`temporal activity execute \\ + --type 'GreetingActivities::compose_greeting' \\ + --activity-id standalone-activity-id \\ + --task-queue standalone-activities \\ + --start-to-close-timeout 10s \\ + --input '["Hello","Temporal"]'`} + + +}> + +## Execute a Standalone Activity {/* #execute-activity */} + +Use [`Client::start_activity`](https://docs.rs/temporalio-client/latest/temporalio_client/struct.Client.html#method.start_activity) +to start a Standalone Activity, then +[`ActivityHandle::result`](https://docs.rs/temporalio-client/latest/temporalio_client/struct.ActivityHandle.html#method.result) +to block until it completes. Call these from your application code, not from inside a Workflow +Definition. `start_activity` durably enqueues your Standalone Activity in the Temporal Server, and +`result` waits for it to be executed on your Worker and returns the result. + +[execute_activity.rs](https://github.com/temporalio/sdk-rust/blob/main/crates/sdk/examples/standalone_activities/execute_activity.rs) + +The first argument to `start_activity` is the Activity to run. Passing the Activity method itself, +`GreetingActivities::compose_greeting`, gives you a typed +[`ActivityHandle`](https://docs.rs/temporalio-client/latest/temporalio_client/struct.ActivityHandle.html), +so the input and output types are checked at compile time and `result` returns the Activity's own +return type. The second argument is the Activity's input. + +[`ActivityStartOptions`](https://docs.rs/temporalio-client/latest/temporalio_client/struct.ActivityStartOptions.html) +requires a Task Queue, an Activity ID, and a close timeout. The `with_start_to_close_timeout` and +`with_schedule_to_close_timeout` constructors return a builder with that timeout already set; call +`.build()` to finish. + +To run it: + +1. Make sure the Temporal Server is running (from the [Get Started](#get-started) step above). +2. Make sure the Worker is running (from the [Run a Worker](#run-worker) step above). +3. Open a new terminal, navigate to the `crates/sdk` directory, and run the execute command. + +Or use the Temporal CLI. Because `compose_greeting` takes its two values as a tuple, the CLI input +is a single two-element JSON array. + + + + + +## Run with Temporal Cloud + +All code samples on this page use +[`ClientOptions::load_from_config`](https://docs.rs/temporalio-client/latest/temporalio_client/struct.ClientOptions.html#method.load_from_config) +to configure the Temporal Client connection. It responds to [environment +variables](/references/client-environment-configuration) and [TOML configuration +files](/references/client-environment-configuration), so the same code works against a local dev +server and Temporal Cloud without changes. See [Run Standalone Activities with Temporal +Cloud](/develop/rust/activities/standalone-activities#run-standalone-activities-temporal-cloud) in the Feature Guide +for mTLS and API key setup. + +## Next steps + +- **[Standalone Activities Feature Guide](/develop/rust/activities/standalone-activities)**: Start without waiting, get handles, list and count Activities, and connect to Temporal Cloud. +- **[Activity basics](/develop/rust/activities/basics)**: How to write and register Activities with the Rust SDK. diff --git a/docs/develop/rust/activities/standalone-activities.mdx b/docs/develop/rust/activities/standalone-activities.mdx new file mode 100644 index 0000000000..9351c4e99b --- /dev/null +++ b/docs/develop/rust/activities/standalone-activities.mdx @@ -0,0 +1,350 @@ +--- +id: standalone-activities +title: Standalone Activities Feature Guide +sidebar_label: Feature Guide +toc_max_heading_level: 4 +tags: + - Activities + - Temporal Client + - Rust SDK + - Temporal SDKs +description: Execute Activities independently without a Workflow using the Temporal Rust SDK. +--- + +[Standalone Activities](/standalone-activity) are Activities that run independently, without being +orchestrated by a Workflow. Instead of executing an Activity from within a Workflow Definition using +`ctx.execute_activity()`, you execute a Standalone Activity directly from a +[`Client`](https://docs.rs/temporalio-client/latest/temporalio_client/struct.Client.html). + +The way you write the Activity and register it with a Worker is identical to [Workflow +Activities](/develop/rust/activities/basics). The only difference is that you execute a Standalone +Activity directly from your Temporal Client. + +:::tip + +New to Standalone Activities? Start with the [Standalone Activities Quickstart](/develop/rust/activities/standalone-activities-quickstart). + +::: + +This page covers the following: + +- [Prerequisites](#prerequisites) +- [Start a Standalone Activity without waiting for the result](#start-activity) +- [Get a handle to an existing Standalone Activity](#get-activity-handle) +- [Wait for the result of a Standalone Activity](#get-activity-result) +- [List Standalone Activities](#list-activities) +- [Count Standalone Activities](#count-activities) +- [Run Standalone Activities with Temporal Cloud](#run-standalone-activities-temporal-cloud) + +:::note + +This documentation uses source code from the +[standalone_activity](https://github.com/temporalio/sdk-rust/tree/main/crates/sdk/examples/standalone_activities) +sample. + +::: + +## Prerequisites {/* #prerequisites */} + +Standalone Activities require: + +- **Rust** 1.92.0+ +- **Temporal Rust SDK** v1.0.0 or higher +- **[Temporal CLI](/cli/setup-cli)** v1.9.1 or higher + +The [Standalone Activities Quickstart](/develop/rust/activities/standalone-activities-quickstart) +walks through installing these. + +## Start a Standalone Activity without waiting for the result {/* #start-activity */} + +Starting a Standalone Activity means sending a request to the Temporal Server to durably enqueue +your Activity job, without waiting for it to be executed by your Worker. + +Use [`Client::start_activity`](https://docs.rs/temporalio-client/latest/temporalio_client/struct.Client.html#method.start_activity) +to start a Standalone Activity and get a handle without waiting for the result: + +[start_activity.rs](https://github.com/temporalio/sdk-rust/blob/main/crates/sdk/examples/standalone_activities/start_activity.rs) + +```rust +let options = ActivityStartOptions::with_start_to_close_timeout( + "standalone-activities", + "standalone-activity-id", + Duration::from_secs(10), +) +.build(); + +let handle = client + .start_activity( + GreetingActivities::compose_greeting, + ("Hello".to_string(), "Temporal".to_string()), + options, + ) + .await?; + +println!("Started Activity with id={} run_id={:?}", handle.activity_id(), handle.run_id()); + +// Wait for the result later +println!("Activity result: {}", handle.result().await?); +``` + +The first argument identifies the Activity to run. Passing the Activity method itself, such as +`GreetingActivities::compose_greeting`, gives you a typed +[`ActivityHandle`](https://docs.rs/temporalio-client/latest/temporalio_client/struct.ActivityHandle.html), +so the input and output types are checked at compile time. The second argument is the Activity's +input; if your Activity takes several values, pass them as a tuple. + +[`ActivityStartOptions`](https://docs.rs/temporalio-client/latest/temporalio_client/struct.ActivityStartOptions.html) +requires a Task Queue, an Activity ID, and a close timeout. The +`with_start_to_close_timeout` and `with_schedule_to_close_timeout` constructors return a builder +with that timeout already set; call `.build()` to finish, or set additional fields such as +`retry_policy`, `heartbeat_timeout`, `id_reuse_policy`, or `priority` first. + +With the Temporal Server and Worker running, open a new terminal in the `crates/sdk` directory and +run: + +```bash +cargo run --features examples --example standalone-activities-start +``` + +Or use the Temporal CLI: + +```bash +temporal activity start \ + --type 'GreetingActivities::compose_greeting' \ + --activity-id standalone-activity-id \ + --task-queue standalone-activities \ + --start-to-close-timeout 10s \ + --input '["Hello","Temporal"]' +``` + +By default, the `#[activities]` macro names each Activity `::`, so the +`compose_greeting` method on `GreetingActivities` registers as `GreetingActivities::compose_greeting`. Use that +name when referring to the Activity from the CLI or from a [List Filter](/list-filter) query. + +## Get a handle to an existing Standalone Activity {/* #get-activity-handle */} + +Use [`Client::get_activity_handle`](https://docs.rs/temporalio-client/latest/temporalio_client/struct.Client.html#method.get_activity_handle) +to create an +[`ActivityHandle`](https://docs.rs/temporalio-client/latest/temporalio_client/struct.ActivityHandle.html) +for a previously started Standalone Activity: + +[get_activity_handle.rs](https://github.com/temporalio/sdk-rust/blob/main/crates/sdk/examples/standalone_activities/get_activity_handle.rs) + +```rust +let handle = client.get_activity_handle( + GreetingActivities::compose_greeting, + "standalone-activity-id", + None, +); +``` + +Pass `None` for the run ID to target the latest run of the given Activity ID, or pass +`Some(run_id)` to target a specific run. + +If you don't have the Activity definition on hand, for example in a tool that operates on +Activities it didn't start, use +[`Client::get_untyped_activity_handle`](https://docs.rs/temporalio-client/latest/temporalio_client/struct.Client.html#method.get_untyped_activity_handle) +instead. You can still describe, cancel, and terminate through an untyped handle. + +You can then use the handle to wait for the result, describe, cancel, or terminate the Activity: + +```rust +handle.result().await?; // block until the activity completes +handle.describe(Default::default()).await?; // status, timestamps, attempt, last failure, ... +handle.cancel(Default::default()).await?; // request cancellation +handle.terminate(Default::default()).await?; // force-close the activity +``` + +[`describe`](https://docs.rs/temporalio-client/latest/temporalio_client/struct.ActivityHandle.html#method.describe) +takes an +[`ActivityDescribeOptions`](https://docs.rs/temporalio-client/latest/temporalio_client/struct.ActivityDescribeOptions.html). +Its `include_input`, `include_outcome`, and `include_heartbeat_details` fields are off by default, +because those fields carry Payloads that can be arbitrarily large. Turn them on only when you need +them: + +```rust +let description = handle + .describe(ActivityDescribeOptions::builder().include_outcome(true).build()) + .await?; + +println!("Status: {:?}", description.status()); +println!("Attempt: {}", description.attempt()); +``` + +The accessors on the description (`status()`, `activity_type()`, `schedule_time()`, and so on) +come from the +[`ActivityExecutionInfoLike`](https://docs.rs/temporalio-client/latest/temporalio_client/trait.ActivityExecutionInfoLike.html) +trait, so bring it into scope to use them. + +Run it, after executing an Activity with one of the samples above: + +```bash +cargo run --features examples --example standalone-activities-get-handle +``` + +Or use the Temporal CLI to describe an Activity by ID: + +```bash +temporal activity describe --activity-id standalone-activity-id +``` + +## Wait for the result of a Standalone Activity {/* #get-activity-result */} + +The Rust SDK has no single call that does both. To execute a Standalone Activity and wait for its +result, call `start_activity` to durably enqueue the Activity, then +[`ActivityHandle::result`](https://docs.rs/temporalio-client/latest/temporalio_client/struct.ActivityHandle.html#method.result) +to block until it completes and return the result: + +[execute_activity.rs](https://github.com/temporalio/sdk-rust/blob/main/crates/sdk/examples/standalone_activities/execute_activity.rs) + +```rust +let handle = client + .start_activity( + GreetingActivities::compose_greeting, + ("Hello".to_string(), "Temporal".to_string()), + options, + ) + .await?; + +let result = handle.result().await?; +println!("Activity result: {result}"); +``` + +Because the handle is typed, `result` returns the Activity's own output type, `String` in this +case, with no downcasting. It fails with an +[`ActivityResultError`](https://docs.rs/temporalio-client/latest/temporalio_client/errors/enum.ActivityResultError.html) +if the Activity failed, was cancelled, or was terminated. + +Splitting start from result also means you don't have to wait in the same process, or even the same +program, that started the Activity: [get a handle](#get-activity-handle) later and call `result` on +it. + +Or use the Temporal CLI to wait for a result by Activity ID: + +```bash +temporal activity result --activity-id standalone-activity-id +``` + +## List Standalone Activities {/* #list-activities */} + +Use [`Client::list_activities`](https://docs.rs/temporalio-client/latest/temporalio_client/struct.Client.html#method.list_activities) +to list Standalone Activity Executions that match a [List Filter](/list-filter) query. The result is +a [`ListActivitiesStream`](https://docs.rs/temporalio-client/latest/temporalio_client/struct.ListActivitiesStream.html), +a `Stream` of +[`ActivityExecutionInfo`](https://docs.rs/temporalio-client/latest/temporalio_client/struct.ActivityExecutionInfo.html) +values that fetches pages from the server on demand as the stream is consumed. + +These APIs return only Standalone Activity Executions. Activities running inside Workflows are not +included. + +[list_activities.rs](https://github.com/temporalio/sdk-rust/blob/main/crates/sdk/examples/standalone_activities/list_activities.rs) + +```rust +use futures::StreamExt; +use temporalio_client::ActivityExecutionInfoLike; + +let mut activities = + client.list_activities("TaskQueue = 'standalone-activities'", Default::default()); + +while let Some(activity) = activities.next().await { + let activity = activity?; + println!( + "{} {} {:?}", + activity.activity_id(), + activity.activity_type(), + activity.status() + ); +} +``` + +`list_activities` is not `async`. It returns the stream immediately, and the requests happen as you +poll it. Each item is a `Result`, because a page fetch can fail partway through the +stream. + +Run it: + +```bash +cargo run --features examples --example standalone-activities-list +``` + +Or use the Temporal CLI: + +```bash +temporal activity list +``` + +The query parameter accepts the same [List Filter](/list-filter) syntax used for [Workflow +Visibility](/visibility). For example, +`ActivityType = 'GreetingActivities::compose_greeting' AND ExecutionStatus = 'Running'`. + +## Count Standalone Activities {/* #count-activities */} + +Use [`Client::count_activities`](https://docs.rs/temporalio-client/latest/temporalio_client/struct.Client.html#method.count_activities) +to count Standalone Activity Executions that match a [List Filter](/list-filter) query. This returns +the total count of executions (running, completed, failed, etc.) — not the number of queued tasks. +It works the same way as counting Workflow Executions. + +[count_activities.rs](https://github.com/temporalio/sdk-rust/blob/main/crates/sdk/examples/standalone_activities/count_activities.rs) + +```rust +let result = client + .count_activities("TaskQueue = 'standalone-activities'", Default::default()) + .await?; + +println!("Total: {}", result.count()); +for group in result.groups() { + println!(" {:?} => {}", group.get::(0), group.count()); +} +``` + +If the query has a `GROUP BY` clause, +[`groups()`](https://docs.rs/temporalio-client/latest/temporalio_client/struct.ActivityExecutionCount.html#method.groups) +holds the per-group counts and `count()` is their sum; otherwise `groups()` is empty. Group values +are typed: read them with `get::(index)`, or with `try_get` if you want to handle a +deserialization failure rather than get `None`. + +Run it: + +```bash +cargo run --features examples --example standalone-activities-count +``` + +Or use the Temporal CLI: + +```bash +temporal activity count +``` + +## Run Standalone Activities with Temporal Cloud {/* #run-standalone-activities-temporal-cloud */} + +The Worker and Client code in the [Standalone Activities Quickstart](/develop/rust/activities/standalone-activities-quickstart) +use [`ClientOptions::load_from_config`](https://docs.rs/temporalio-client/latest/temporalio_client/struct.ClientOptions.html#method.load_from_config), +so the same code works against Temporal Cloud — configure the connection via environment variables +or a TOML profile. No code changes are needed. + +For a step-by-step guide on connecting to Temporal Cloud, including Namespace creation, certificate +generation, and authentication setup in the Cloud UI, see +[Connect to Temporal Cloud](/develop/rust/client/temporal-client#connect-to-temporal-cloud). + +### Connect with mTLS + +Set these environment variables with values from your Temporal Cloud Namespace settings: + +``` +export TEMPORAL_ADDRESS=..tmprl.cloud:7233 +export TEMPORAL_NAMESPACE=. +export TEMPORAL_TLS_CLIENT_CERT_PATH='path/to/your/client.pem' +export TEMPORAL_TLS_CLIENT_KEY_PATH='path/to/your/client.key' +``` + +### Connect with an API key + +Set these environment variables with values from your Temporal Cloud API key settings: + +``` +export TEMPORAL_ADDRESS=..tmprl.cloud:7233 +export TEMPORAL_NAMESPACE=. +export TEMPORAL_API_KEY= +``` + +Then run the Worker and starter code as shown in the [Standalone Activities Quickstart](/develop/rust/activities/standalone-activities-quickstart). From 62d70592a0dc05c562efab0455566c08bdc68446 Mon Sep 17 00:00:00 2001 From: Greg Travis Date: Tue, 15 Sep 2026 15:24:01 -0400 Subject: [PATCH 3/6] Make docs code match samples code. --- .../standalone-activities-quickstart.mdx | 18 ++++----- .../rust/activities/standalone-activities.mdx | 40 ++++++++++++------- 2 files changed, 32 insertions(+), 26 deletions(-) diff --git a/docs/develop/rust/activities/standalone-activities-quickstart.mdx b/docs/develop/rust/activities/standalone-activities-quickstart.mdx index 2b14d92075..16d31dd62b 100644 --- a/docs/develop/rust/activities/standalone-activities-quickstart.mdx +++ b/docs/develop/rust/activities/standalone-activities-quickstart.mdx @@ -159,26 +159,21 @@ Filter](/list-filter) queries. -{`use temporalio_client::{ - Client, ClientOptions, Connection, envconfig::LoadClientConfigProfileOptions, -}; -use temporalio_sdk::{Runtime, Worker, WorkerOptions}; - -#[tokio::main] +{`#[tokio::main] async fn main() -> Result<(), Box> { let runtime = Runtime::from_current_tokio(Default::default())?; - - let (connection_options, client_options) = + let (conn_opts, client_opts) = ClientOptions::load_from_config(LoadClientConfigProfileOptions::default())?; - let connection = Connection::connect(connection_options).await?; - let client = Client::new(connection, client_options)?; + let connection = Connection::connect(conn_opts).await?; + let client = Client::new(connection, client_opts)?; + // A Worker that only runs Standalone Activities needs no registered workflows. let worker_options = WorkerOptions::new("standalone-activities") .register_activities(GreetingActivities) .build(); let mut worker = Worker::new(&runtime, client, worker_options)?; - println!("Starting worker (ctrl+c to exit)"); + println!("Worker started on task queue: standalone-activities"); worker.run().await?; Ok(()) @@ -217,6 +212,7 @@ Leave this terminal running — the Worker needs to stay up to process activitie ) .build(); +// There is no single "execute" call: start the activity, then await its result. let handle = client .start_activity( GreetingActivities::compose_greeting, diff --git a/docs/develop/rust/activities/standalone-activities.mdx b/docs/develop/rust/activities/standalone-activities.mdx index 9351c4e99b..5e0f7718ab 100644 --- a/docs/develop/rust/activities/standalone-activities.mdx +++ b/docs/develop/rust/activities/standalone-activities.mdx @@ -73,6 +73,7 @@ let options = ActivityStartOptions::with_start_to_close_timeout( ) .build(); +// Returns as soon as the server has durably enqueued the activity. let handle = client .start_activity( GreetingActivities::compose_greeting, @@ -81,10 +82,11 @@ let handle = client ) .await?; -println!("Started Activity with id={} run_id={:?}", handle.activity_id(), handle.run_id()); - -// Wait for the result later -println!("Activity result: {}", handle.result().await?); +println!( + "Started activity, id: {} run_id: {:?}", + handle.activity_id(), + handle.run_id() +); ``` The first argument identifies the Activity to run. Passing the Activity method itself, such as @@ -131,6 +133,7 @@ for a previously started Standalone Activity: [get_activity_handle.rs](https://github.com/temporalio/sdk-rust/blob/main/crates/sdk/examples/standalone_activities/get_activity_handle.rs) ```rust +// Passing `None` for the run ID targets the latest run with this activity ID. let handle = client.get_activity_handle( GreetingActivities::compose_greeting, "standalone-activity-id", @@ -164,10 +167,15 @@ them: ```rust let description = handle - .describe(ActivityDescribeOptions::builder().include_outcome(true).build()) + .describe( + ActivityDescribeOptions::builder() + .include_outcome(true) + .build(), + ) .await?; -println!("Status: {:?}", description.status()); +println!("Status: {:?}", description.status()); +println!("Type: {}", description.activity_type()); println!("Attempt: {}", description.attempt()); ``` @@ -198,6 +206,7 @@ to block until it completes and return the result: [execute_activity.rs](https://github.com/temporalio/sdk-rust/blob/main/crates/sdk/examples/standalone_activities/execute_activity.rs) ```rust +// There is no single "execute" call: start the activity, then await its result. let handle = client .start_activity( GreetingActivities::compose_greeting, @@ -243,16 +252,16 @@ included. use futures::StreamExt; use temporalio_client::ActivityExecutionInfoLike; -let mut activities = +let mut executions = client.list_activities("TaskQueue = 'standalone-activities'", Default::default()); -while let Some(activity) = activities.next().await { - let activity = activity?; +while let Some(execution) = executions.next().await { + let execution = execution?; println!( "{} {} {:?}", - activity.activity_id(), - activity.activity_type(), - activity.status() + execution.activity_id(), + execution.activity_type(), + execution.status() ); } ``` @@ -287,12 +296,13 @@ It works the same way as counting Workflow Executions. [count_activities.rs](https://github.com/temporalio/sdk-rust/blob/main/crates/sdk/examples/standalone_activities/count_activities.rs) ```rust -let result = client +let count = client .count_activities("TaskQueue = 'standalone-activities'", Default::default()) .await?; -println!("Total: {}", result.count()); -for group in result.groups() { +println!("Total: {}", count.count()); +// Non-empty only when the query has a GROUP BY clause. +for group in count.groups() { println!(" {:?} => {}", group.get::(0), group.count()); } ``` From 17fb38965752e262ba01086019d1c9bc4ea62167 Mon Sep 17 00:00:00 2001 From: Greg Travis Date: Wed, 16 Sep 2026 11:55:20 -0400 Subject: [PATCH 4/6] Add missing references --- docs/develop/rust/activities/basics.mdx | 4 ++++ docs/develop/rust/client/temporal-client.mdx | 2 ++ docs/encyclopedia/activities/activity-execution.mdx | 1 + docs/evaluate/features/job-queue.mdx | 6 ++++++ 4 files changed, 13 insertions(+) diff --git a/docs/develop/rust/activities/basics.mdx b/docs/develop/rust/activities/basics.mdx index af0643f3e7..21245b6414 100644 --- a/docs/develop/rust/activities/basics.mdx +++ b/docs/develop/rust/activities/basics.mdx @@ -15,6 +15,10 @@ One of the primary things that Workflows do is orchestrate the execution of Acti An Activity can interact with the world outside the Temporal Platform or use a Temporal Client to interact with a Temporal Service. For the Workflow to be able to execute the Activity, you need to define the [Activity Definition](/activity-definition). +Standalone Activities are Activities that run independently, without being orchestrated by a Workflow. Instead of executing an Activity from within a Workflow Definition, you execute a Standalone Activity directly from a Temporal Client. + +The way you write the Activity and register it with a Worker is identical to [Workflow Activities](/develop/rust/activities/basics). The only difference is that you execute a Standalone Activity directly from your Temporal Client. See [Standalone Activities](/develop/rust/activities/standalone-activities-quickstart). + The `#[activities]` macro marks an `impl` block as containing Activity definitions. Each method decorated with `#[activity]` becomes an Activity that can be invoked from a Workflow. Here's an example of an Activity: diff --git a/docs/develop/rust/client/temporal-client.mdx b/docs/develop/rust/client/temporal-client.mdx index c2255495b8..b9164c22bf 100644 --- a/docs/develop/rust/client/temporal-client.mdx +++ b/docs/develop/rust/client/temporal-client.mdx @@ -15,6 +15,8 @@ tags: A [Temporal Client](/encyclopedia/temporal-client) lets your application communicate with the Temporal Service. Use it to start Workflow Executions, send Signals, run Queries, fetch Workflow results, and more. +For [Standalone Activities](/standalone-activity), a Temporal Client can also start and manage Standalone Activities directly, without involving a Workflow. + This page shows how to do the following using the Rust SDK and Temporal Client: - [Connect to a local development Temporal Service](#connect-to-development-service) diff --git a/docs/encyclopedia/activities/activity-execution.mdx b/docs/encyclopedia/activities/activity-execution.mdx index 31d2530686..4181dda019 100644 --- a/docs/encyclopedia/activities/activity-execution.mdx +++ b/docs/encyclopedia/activities/activity-execution.mdx @@ -82,6 +82,7 @@ Start a Standalone Activity: | [.NET](/develop/dotnet/activities/standalone-activities-quickstart#execute-activity) | [TypeScript](/develop/typescript/activities/standalone-activities-quickstart#execute-activity-type-checking) | [Ruby](/develop/ruby/activities/standalone-activities-quickstart#execute-activity) +| [Rust](/develop/rust/activities/standalone-activities-quickstart#execute-activity) ::: diff --git a/docs/evaluate/features/job-queue.mdx b/docs/evaluate/features/job-queue.mdx index 03534dc72c..67232dc87e 100644 --- a/docs/evaluate/features/job-queue.mdx +++ b/docs/evaluate/features/job-queue.mdx @@ -91,6 +91,12 @@ Read about [Standalone Activity concepts, features, and limitations](/standalone description: "Start and manage a Standalone Activity Execution in Ruby, with a runnable code sample.", icon: "/img/sdks/svgs/ruby.svg", }, + { + href: "/develop/rust/activities/standalone-activities-quickstart", + title: "Rust SDK", + description: "Start and manage a Standalone Activity Execution in Rust, with a runnable code sample.", + icon: "/img/sdks/svgs/rust.svg", + }, { href: "/develop/typescript/activities/standalone-activities-quickstart", title: "TypeScript SDK", From 71a255bc3a6fc95c8b80c80613a5bd50b9a568b2 Mon Sep 17 00:00:00 2001 From: Jwahir Sundai Date: Fri, 18 Sep 2026 12:44:15 -0700 Subject: [PATCH 5/6] edits --- docs/demos/standalone-activities.mdx | 2 +- .../rust/activities/standalone-activities-quickstart.mdx | 2 +- docs/develop/rust/activities/standalone-activities.mdx | 6 +++--- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/demos/standalone-activities.mdx b/docs/demos/standalone-activities.mdx index cf618f4c0c..69eb9b880e 100644 --- a/docs/demos/standalone-activities.mdx +++ b/docs/demos/standalone-activities.mdx @@ -62,6 +62,6 @@ For complete API reference and advanced usage, see the SDK-specific guides: diff --git a/docs/develop/rust/activities/standalone-activities-quickstart.mdx b/docs/develop/rust/activities/standalone-activities-quickstart.mdx index 16d31dd62b..53d8f48177 100644 --- a/docs/develop/rust/activities/standalone-activities-quickstart.mdx +++ b/docs/develop/rust/activities/standalone-activities-quickstart.mdx @@ -28,7 +28,7 @@ Activity directly from your Temporal Client. :::note This documentation uses source code from the -[standalone_activity](https://github.com/temporalio/sdk-rust/tree/main/crates/sdk/examples/standalone_activities) +[standalone_activities](https://github.com/temporalio/sdk-rust/tree/main/crates/sdk/examples/standalone_activities) sample. ::: diff --git a/docs/develop/rust/activities/standalone-activities.mdx b/docs/develop/rust/activities/standalone-activities.mdx index 5e0f7718ab..30869c7734 100644 --- a/docs/develop/rust/activities/standalone-activities.mdx +++ b/docs/develop/rust/activities/standalone-activities.mdx @@ -39,7 +39,7 @@ This page covers the following: :::note This documentation uses source code from the -[standalone_activity](https://github.com/temporalio/sdk-rust/tree/main/crates/sdk/examples/standalone_activities) +[standalone_activities](https://github.com/temporalio/sdk-rust/tree/main/crates/sdk/examples/standalone_activities) sample. ::: @@ -198,8 +198,8 @@ temporal activity describe --activity-id standalone-activity-id ## Wait for the result of a Standalone Activity {/* #get-activity-result */} -The Rust SDK has no single call that does both. To execute a Standalone Activity and wait for its -result, call `start_activity` to durably enqueue the Activity, then +The Rust SDK has no single call that both starts an Activity and waits for its result. Call +`start_activity` to durably enqueue the Activity, then [`ActivityHandle::result`](https://docs.rs/temporalio-client/latest/temporalio_client/struct.ActivityHandle.html#method.result) to block until it completes and return the result: From 411ca15691dac5acb8ca8c99d61a072e39d145c7 Mon Sep 17 00:00:00 2001 From: Jwahir Sundai Date: Fri, 18 Sep 2026 13:12:27 -0700 Subject: [PATCH 6/6] Align describe defaults with ActivityDescribeOptions --- docs/develop/rust/activities/standalone-activities.mdx | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/develop/rust/activities/standalone-activities.mdx b/docs/develop/rust/activities/standalone-activities.mdx index 30869c7734..50a5d5fdf3 100644 --- a/docs/develop/rust/activities/standalone-activities.mdx +++ b/docs/develop/rust/activities/standalone-activities.mdx @@ -153,7 +153,7 @@ You can then use the handle to wait for the result, describe, cancel, or termina ```rust handle.result().await?; // block until the activity completes -handle.describe(Default::default()).await?; // status, timestamps, attempt, last failure, ... +handle.describe(Default::default()).await?; // status, timestamps, attempt, ... handle.cancel(Default::default()).await?; // request cancellation handle.terminate(Default::default()).await?; // force-close the activity ``` @@ -161,9 +161,9 @@ handle.terminate(Default::default()).await?; // force-close the activity [`describe`](https://docs.rs/temporalio-client/latest/temporalio_client/struct.ActivityHandle.html#method.describe) takes an [`ActivityDescribeOptions`](https://docs.rs/temporalio-client/latest/temporalio_client/struct.ActivityDescribeOptions.html). -Its `include_input`, `include_outcome`, and `include_heartbeat_details` fields are off by default, -because those fields carry Payloads that can be arbitrarily large. Turn them on only when you need -them: +Its `include_input`, `include_outcome`, `include_heartbeat_details`, and `include_last_failure` +fields are off by default, because those fields carry Payloads that can be arbitrarily large. Turn +them on only when you need them: ```rust let description = handle