diff --git a/docs/best-practices/cost-optimization.mdx b/docs/best-practices/cost-optimization.mdx index 1448b85782..27e10b4647 100644 --- a/docs/best-practices/cost-optimization.mdx +++ b/docs/best-practices/cost-optimization.mdx @@ -134,6 +134,15 @@ For detailed discussion of this tradeoff, see [How many Activities should I use [Child Workflows cost 2 Actions](/cloud/actions#workflow) compared to an Activity's 1 Action. See [Child Workflows documentation](/child-workflows) for detailed comparison of capabilities and use cases. +### Standalone Activities vs a Workflow that runs a single Activity + +Starting a [Standalone Activity](/standalone-activity) costs 1 Action. +Running the same single Activity in a wrapper Workflow costs 1 Action for the Activity and 1 Action for the Workflow, not including Activity heartbeats, retries, or other billable [Actions](/cloud/actions#activity). + +Use a Workflow when you need multi-step orchestration, human in the loop, signals, timers, updates, queries, or enhanced step-by-step visibility with event history and [replay](/workflow-execution#replay). + +Use a Standalone Activity when you need to execute a single Activity function reliably. + ### Retry Policies Each Activity retry counts as one Action. diff --git a/docs/cloud/metrics/openmetrics/metrics-reference.mdx b/docs/cloud/metrics/openmetrics/metrics-reference.mdx index 2606892cd2..ebdbbd97cf 100644 --- a/docs/cloud/metrics/openmetrics/metrics-reference.mdx +++ b/docs/cloud/metrics/openmetrics/metrics-reference.mdx @@ -310,7 +310,7 @@ These metrics could have high cardinality depending on number of activity types, :::note Standalone Activities -Standalone Activities are Activity Executions that are started independently, without an associated Workflow. For Activity metrics that include the `temporal_workflow_type` label, Standalone Activities use the placeholder value `"__standalone_activity"`. +[Standalone Activities](/standalone-activity) are Activity Executions that are started independently, without an associated Workflow. For Activity metrics that include the `temporal_workflow_type` label, Standalone Activities use the placeholder value `"__standalone_activity"`. ::: diff --git a/docs/demos/standalone-activities.mdx b/docs/demos/standalone-activities.mdx index eb90c8a91c..dbd54f030e 100644 --- a/docs/demos/standalone-activities.mdx +++ b/docs/demos/standalone-activities.mdx @@ -10,17 +10,9 @@ tags: description: An interactive overview of Temporal Standalone Activities. --- -import { StandaloneActivityDemo, ReleaseNoteHeader, SdkGuideLinks } from '@site/src/components'; +import { StandaloneActivityDemo, SdkGuideLinks } from '@site/src/components'; - - Available in [Temporal Cloud](/standalone-activity#temporal-cloud-support) and in the [Temporal CLI](/standalone-activity#temporal-cli-support) v1.7.0 or higher with Temporal Server v1.31.0 or higher. Java SDK support is in [Pre-release](/evaluate/development-production-features/release-stages#pre-release). - - -Standalone Activities let you run a single Activity straight from your application without +[Standalone Activities](/standalone-activity) let you run a single Activity straight from your application without writing a Workflow. Your code uses the Temporal Client to send the request to the Server, the Server durably enqueues the request for a Worker to pick up, and the result comes back through a handle that your code can wait on or check later. diff --git a/docs/develop/dotnet/activities/standalone-activities-quickstart.mdx b/docs/develop/dotnet/activities/standalone-activities-quickstart.mdx index 76dd0ac62c..9a70ee701f 100644 --- a/docs/develop/dotnet/activities/standalone-activities-quickstart.mdx +++ b/docs/develop/dotnet/activities/standalone-activities-quickstart.mdx @@ -50,11 +50,12 @@ This documentation uses source code from the [StandaloneActivity](https://github Prerequisites: -- **[.NET](https://dotnet.microsoft.com/download)** 8.0+ +- **[.NET](https://dotnet.microsoft.com/download)** 8.0+ for the sample project + (the Temporal .NET SDK requires .NET Core 3.1+, Framework 4.6.2+, or Standard 2.0+) -- **Temporal .NET SDK** (v1.12.0 or higher). See the [.NET Quickstart](/develop/dotnet/set-up-your-local-dotnet) for install instructions. +- **Temporal .NET SDK** (v1.19.0 or higher). See the [.NET Quickstart](/develop/dotnet/set-up-your-local-dotnet) for install instructions. -- **Temporal CLI** v1.7.0 or higher. Install with Homebrew, or see the [Temporal CLI install guide](/cli/setup-cli) for other platforms. Verify the installation with `temporal --version`. +- **Temporal CLI** v1.9.0 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`. diff --git a/docs/develop/dotnet/activities/standalone-activities.mdx b/docs/develop/dotnet/activities/standalone-activities.mdx index da70f9028d..b63c8b1972 100644 --- a/docs/develop/dotnet/activities/standalone-activities.mdx +++ b/docs/develop/dotnet/activities/standalone-activities.mdx @@ -11,14 +11,8 @@ tags: description: Execute Activities independently without a Workflow using the Temporal .NET SDK. --- -import { ReleaseNoteHeader } from '@site/src/components'; - - - -Standalone Activities are Activities that run independently, without being orchestrated by a -Workflow. Instead of starting an Activity from within a Workflow Definition, you start a Standalone +[Standalone Activities](/standalone-activity) are Activities that run independently, without being orchestrated +by a Workflow. Instead of starting an Activity from within a Workflow Definition, you start a Standalone Activity directly from a Temporal Client. The way you write the Activity and register it with a Worker is identical to [Workflow @@ -33,6 +27,7 @@ New to Standalone Activities? Start with the [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) @@ -46,6 +41,17 @@ This documentation uses source code from the [StandaloneActivity](https://github ::: +## Prerequisites {/* #prerequisites */} + +Standalone Activities require: + +- **.NET** 8.0+ for the sample project (the Temporal .NET SDK requires .NET Core 3.1+, Framework 4.6.2+, or Standard 2.0+) +- **Temporal .NET SDK** v1.19.0 or higher +- **[Temporal CLI](/cli/setup-cli)** v1.9.0 or higher + +The [Standalone Activities Quickstart](/develop/dotnet/activities/standalone-activities-quickstart) +walks through installing these. + ## Start a Standalone Activity without waiting for the result {/* #start-activity */} Use diff --git a/docs/develop/go/activities/basics.mdx b/docs/develop/go/activities/basics.mdx index 0d36bfb5d4..82ec05eaa3 100644 --- a/docs/develop/go/activities/basics.mdx +++ b/docs/develop/go/activities/basics.mdx @@ -71,7 +71,7 @@ func (a *YourActivityObject) YourActivityDefinition(ctx context.Context, param Y } ``` -### How to develop Activity Parameters {/* #activity-parameters */} +### Activity Parameters {/* #activity-parameters */} There is no explicit limit to the total number of parameters that an [Activity Definition](/activity-definition) may support. However, there is a limit to the total size of the data that ends up encoded into a gRPC message Payload. diff --git a/docs/develop/go/activities/standalone-activities-quickstart.mdx b/docs/develop/go/activities/standalone-activities-quickstart.mdx index c18f88311b..55ce320eb2 100644 --- a/docs/develop/go/activities/standalone-activities-quickstart.mdx +++ b/docs/develop/go/activities/standalone-activities-quickstart.mdx @@ -50,11 +50,11 @@ This documentation uses source code from the Prerequisites: -- **[Go](https://go.dev/dl/)** 1.22+ +- **[Go](https://go.dev/dl/)** 1.24+ -- **[Temporal Go SDK](/develop/go/set-up-your-local-go#install-the-temporal-go-sdk)** (v1.41.0 or higher) +- **[Temporal Go SDK](/develop/go/set-up-your-local-go#install-the-temporal-go-sdk)** (v1.49.0 or higher) -- **Temporal CLI** v1.7.0 or higher. Install with Homebrew, or see the [Temporal CLI install guide](/cli/setup-cli) for other platforms. Verify the installation with `temporal --version`. +- **Temporal CLI** v1.9.0 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`. diff --git a/docs/develop/go/activities/standalone-activities.mdx b/docs/develop/go/activities/standalone-activities.mdx index 62fbbb662c..2b4e2b0129 100644 --- a/docs/develop/go/activities/standalone-activities.mdx +++ b/docs/develop/go/activities/standalone-activities.mdx @@ -11,15 +11,10 @@ tags: description: Execute Activities independently without a Workflow using the Temporal Go SDK. --- -import { ReleaseNoteHeader } from '@site/src/components'; - - - -Standalone Activities are Activity Executions that run independently, without being orchestrated by a Workflow. Instead -of starting an Activity from within a Workflow Definition using `workflow.ExecuteActivity()`, you start a Standalone -Activity directly from a Temporal Client using `client.ExecuteActivity()`. +[Standalone Activities](/standalone-activity) are Activity Executions that run independently, without being +orchestrated by a Workflow. Instead of starting an Activity from within a Workflow Definition using +`workflow.ExecuteActivity()`, you start a Standalone Activity directly from a Temporal Client using +`client.ExecuteActivity()`. The Activity definition and Worker registration are identical to regular Activities, and only the execution path differs. @@ -32,6 +27,7 @@ New to Standalone Activities? Start with the [Standalone Activities Quickstart]( This page covers the following: +- [Prerequisites](#prerequisites) - [Get the result of a Standalone Activity](#get-activity-result) - [Get a handle to an existing Standalone Activity](#get-activity-handle) - [List Standalone Activities](#list-activities) @@ -45,6 +41,17 @@ This documentation uses source code from the ::: +## Prerequisites {/* #prerequisites */} + +Standalone Activities require: + +- **Go** 1.24+ +- **Temporal Go SDK** v1.49.0 or higher +- **[Temporal CLI](/cli/setup-cli)** v1.9.0 or higher + +The [Standalone Activities Quickstart](/develop/go/activities/standalone-activities-quickstart) +walks through installing these. + ## Get the result of a Standalone Activity {/* #get-activity-result */} Use `ActivityHandle.Get()` to block until the Activity completes and retrieve its result. This is analogous to calling diff --git a/docs/develop/java/activities/basics.mdx b/docs/develop/java/activities/basics.mdx index 4a46a2c118..72bf3a7c3c 100644 --- a/docs/develop/java/activities/basics.mdx +++ b/docs/develop/java/activities/basics.mdx @@ -56,7 +56,7 @@ An Activity implementation is a Java class that implements an Activity annotated } ``` -## Define Activity parameters {/* #activity-parameters */} +## Activity parameters {/* #activity-parameters */} There is no explicit limit to the total number of parameters that an [Activity Definition](/activity-definition) may support. However, there is a limit to the total size of the data that ends up encoded into a gRPC message Payload. diff --git a/docs/develop/java/activities/standalone-activities-quickstart.mdx b/docs/develop/java/activities/standalone-activities-quickstart.mdx index 5ed927d359..134cd452db 100644 --- a/docs/develop/java/activities/standalone-activities-quickstart.mdx +++ b/docs/develop/java/activities/standalone-activities-quickstart.mdx @@ -54,10 +54,10 @@ Prerequisites: - **Java** 8+ -- **Temporal Java SDK** (v1.35.0 or higher). See the [Java Quickstart](/develop/java/set-up-your-local-java) for +- **Temporal Java SDK** (v1.39.0 or higher). See the [Java Quickstart](/develop/java/set-up-your-local-java) for install instructions. -- **Temporal CLI** v1.7.0 or higher. Install with Homebrew, or see the [Temporal CLI install guide](/cli/setup-cli) for other platforms. Verify the installation with `temporal --version`. +- **Temporal CLI** v1.9.0 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`. diff --git a/docs/develop/java/activities/standalone-activities.mdx b/docs/develop/java/activities/standalone-activities.mdx index 24d316b4f8..be9536fc35 100644 --- a/docs/develop/java/activities/standalone-activities.mdx +++ b/docs/develop/java/activities/standalone-activities.mdx @@ -11,12 +11,6 @@ tags: description: Execute Activities independently without a Workflow using the Temporal Java SDK. --- -import { ReleaseNoteHeader } from '@site/src/components'; - - - [Standalone Activities](/standalone-activity) are Activities that run independently, without being orchestrated by a Workflow. Instead of starting an Activity from within a Workflow Definition, you start a Standalone Activity directly from a Temporal Client using `ActivityClient`. @@ -33,6 +27,7 @@ New to Standalone Activities? Start with the [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) @@ -48,6 +43,17 @@ sample. ::: +## Prerequisites {/* #prerequisites */} + +Standalone Activities require: + +- **Java** 8+ +- **Temporal Java SDK** v1.39.0 or higher +- **[Temporal CLI](/cli/setup-cli)** v1.9.0 or higher + +The [Standalone Activities Quickstart](/develop/java/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 diff --git a/docs/develop/php/activities/basics.mdx b/docs/develop/php/activities/basics.mdx index f55cfed27f..55cac23776 100644 --- a/docs/develop/php/activities/basics.mdx +++ b/docs/develop/php/activities/basics.mdx @@ -36,7 +36,7 @@ interface FileProcessingActivities } ``` -### How to develop Activity Parameters {/* #activity-parameters */} +### Activity Parameters {/* #activity-parameters */} There is no explicit limit to the total number of parameters that an [Activity Definition](/activity-definition) may support. However, there is a limit to the total size of the data that ends up encoded into a gRPC message Payload. diff --git a/docs/develop/python/activities/basics.mdx b/docs/develop/python/activities/basics.mdx index 473bd2f252..30179cb884 100644 --- a/docs/develop/python/activities/basics.mdx +++ b/docs/develop/python/activities/basics.mdx @@ -56,7 +56,7 @@ async def your_activity(input: YourParams) -> str: return f"{input.greeting}, {input.name}!" ``` -### Develop Activity Parameters {/* #activity-parameters */} +### Activity Parameters {/* #activity-parameters */} There is no explicit limit to the total number of parameters that an [Activity Definition](/activity-definition) may support. However, there is a limit to the total size of the data that ends up encoded into a gRPC message Payload. diff --git a/docs/develop/python/activities/standalone-activities-quickstart.mdx b/docs/develop/python/activities/standalone-activities-quickstart.mdx index 1f8f0e87aa..b8f9f161fa 100644 --- a/docs/develop/python/activities/standalone-activities-quickstart.mdx +++ b/docs/develop/python/activities/standalone-activities-quickstart.mdx @@ -56,13 +56,13 @@ This documentation uses source code from the [hello_standalone_activity](https:/ Prerequisites: -- **Python 3.9+** +- **Python 3.10+** - **[uv](https://docs.astral.sh/uv/)** - Python package manager. Install with Homebrew, or see the [uv installation guide](https://docs.astral.sh/uv/getting-started/installation/) for other platforms. -- **Temporal Python SDK** (v1.23.0 or higher) +- **Temporal Python SDK** (v1.33.0 or higher) -- **Temporal CLI** v1.7.0 or higher. Install with Homebrew, or see the [Temporal CLI install guide](/cli/setup-cli) for other platforms. Verify the installation with `temporal --version`. +- **Temporal CLI** v1.9.0 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`. diff --git a/docs/develop/python/activities/standalone-activities.mdx b/docs/develop/python/activities/standalone-activities.mdx index 5f06dffdd1..37668a2d11 100644 --- a/docs/develop/python/activities/standalone-activities.mdx +++ b/docs/develop/python/activities/standalone-activities.mdx @@ -11,14 +11,8 @@ tags: description: Execute Activities independently without a Workflow using the Temporal Python SDK. --- -import { ReleaseNoteHeader } from '@site/src/components'; - - - -Standalone Activities are Activities that run independently, without being orchestrated by a -Workflow. Instead of starting an Activity from within a Workflow Definition, you start a Standalone +[Standalone Activities](/standalone-activity) are Activities that run independently, without being orchestrated +by a Workflow. Instead of starting an Activity from within a Workflow Definition, you start a Standalone Activity directly from a Temporal Client. The way you write the Activity and register it with a Worker is identical to [Workflow @@ -33,6 +27,7 @@ New to Standalone Activities? Start with the [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) @@ -46,6 +41,17 @@ This documentation uses source code from the [hello_standalone_activity](https:/ ::: +## Prerequisites {/* #prerequisites */} + +Standalone Activities require: + +- **Python** 3.10+ +- **Temporal Python SDK** v1.33.0 or higher +- **[Temporal CLI](/cli/setup-cli)** v1.9.0 or higher + +The [Standalone Activities Quickstart](/develop/python/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 diff --git a/docs/develop/ruby/activities/standalone-activities-quickstart.mdx b/docs/develop/ruby/activities/standalone-activities-quickstart.mdx index 29764521d1..57ebec8884 100644 --- a/docs/develop/ruby/activities/standalone-activities-quickstart.mdx +++ b/docs/develop/ruby/activities/standalone-activities-quickstart.mdx @@ -54,10 +54,10 @@ Prerequisites: - **Ruby** 3.3+ -- **Temporal Ruby SDK** (v1.5.0 or higher). See the [Ruby Quickstart](/develop/ruby/set-up-local-ruby) for +- **Temporal Ruby SDK** (v1.8.0 or higher). See the [Ruby Quickstart](/develop/ruby/set-up-local-ruby) for install instructions. -- **Temporal CLI** v1.7.0 or higher. Install with Homebrew, or see the [Temporal CLI install guide](/cli/setup-cli) for other platforms. Verify the installation with `temporal --version`. +- **Temporal CLI** v1.9.0 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`. diff --git a/docs/develop/ruby/activities/standalone-activities.mdx b/docs/develop/ruby/activities/standalone-activities.mdx index 8ff5fe3b5e..840a3b5f86 100644 --- a/docs/develop/ruby/activities/standalone-activities.mdx +++ b/docs/develop/ruby/activities/standalone-activities.mdx @@ -11,12 +11,8 @@ tags: description: Execute Activities independently without a Workflow using the Temporal Ruby SDK. --- -import { ReleaseNoteHeader } from '@site/src/components'; - - - -Standalone Activities are Activities that run independently, without being orchestrated by a -Workflow. Instead of starting an Activity from within a Workflow Definition, you start a Standalone +[Standalone Activities](/standalone-activity) are Activities that run independently, without being orchestrated +by a Workflow. Instead of starting an Activity from within a Workflow Definition, you start a Standalone Activity directly from a [`Temporalio::Client`](https://ruby.temporal.io/Temporalio/Client.html). The way you write the Activity and register it with a Worker is identical to [Workflow @@ -31,6 +27,7 @@ New to Standalone Activities? Start with the [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) @@ -46,6 +43,17 @@ sample. ::: +## Prerequisites {/* #prerequisites */} + +Standalone Activities require: + +- **Ruby** 3.3+ +- **Temporal Ruby SDK** v1.8.0 or higher +- **[Temporal CLI](/cli/setup-cli)** v1.9.0 or higher + +The [Standalone Activities Quickstart](/develop/ruby/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 diff --git a/docs/develop/rust/activities/basics.mdx b/docs/develop/rust/activities/basics.mdx index 9d3c0203a7..af0643f3e7 100644 --- a/docs/develop/rust/activities/basics.mdx +++ b/docs/develop/rust/activities/basics.mdx @@ -40,7 +40,7 @@ impl GreetingActivities { } ``` -### Define Activity parameters {/* #activity-parameters */} +### Activity parameters {/* #activity-parameters */} There is a limit of 6 parameters that an [Activity Definition](/activity-definition) may support. There is also a limit to the total size of the data that ends up encoded into a gRPC message Payload. diff --git a/docs/develop/typescript/activities/basics.mdx b/docs/develop/typescript/activities/basics.mdx index d973b9bcbc..881396e0a3 100644 --- a/docs/develop/typescript/activities/basics.mdx +++ b/docs/develop/typescript/activities/basics.mdx @@ -38,7 +38,7 @@ export async function greet(name: string): Promise { ``` -## How to develop Activity Parameters {/* #activity-parameters */} +## Activity Parameters {/* #activity-parameters */} There is no explicit limit to the total number of parameters that an [Activity Definition](/activity-definition) may support. However, there is a limit to the total size of the data that ends up encoded into a gRPC message Payload. diff --git a/docs/develop/typescript/activities/standalone-activities-quickstart.mdx b/docs/develop/typescript/activities/standalone-activities-quickstart.mdx index 0f26b866dc..c7b7efcb41 100644 --- a/docs/develop/typescript/activities/standalone-activities-quickstart.mdx +++ b/docs/develop/typescript/activities/standalone-activities-quickstart.mdx @@ -50,9 +50,11 @@ This documentation uses source code from the [standalone-activity](https://githu Prerequisites: -- **Temporal TypeScript SDK** (v1.17.0 or higher). See the [TypeScript Quickstart](/develop/typescript/set-up-your-local-typescript) for install instructions. +- **[Node.js](https://nodejs.org/en/download/)** 20+ -- **Temporal CLI** v1.7.0 or higher. Install with Homebrew, or see the [Temporal CLI install guide](/cli/setup-cli) for other platforms. Verify the installation with `temporal --version`. +- **Temporal TypeScript SDK** (v1.24.0 or higher). See the [TypeScript Quickstart](/develop/typescript/set-up-your-local-typescript) for install instructions. + +- **Temporal CLI** v1.9.0 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`. diff --git a/docs/develop/typescript/activities/standalone-activities.mdx b/docs/develop/typescript/activities/standalone-activities.mdx index 330be0cc20..b308df1e5e 100644 --- a/docs/develop/typescript/activities/standalone-activities.mdx +++ b/docs/develop/typescript/activities/standalone-activities.mdx @@ -11,14 +11,8 @@ tags: description: Execute Activities independently without a Workflow using the Temporal TypeScript SDK. --- -import { ReleaseNoteHeader } from '@site/src/components'; - - - -Standalone Activities are Activities that run independently, without being orchestrated by a -Workflow. Instead of starting an Activity from within a Workflow Definition, you start a Standalone +[Standalone Activities](/standalone-activity) are Activities that run independently, without being orchestrated +by a Workflow. Instead of starting an Activity from within a Workflow Definition, you start a Standalone Activity directly from a [Temporal Client](/develop/typescript/client/temporal-client). The way you write the Activity and register it with a Worker is identical to [Workflow @@ -33,6 +27,7 @@ New to Standalone Activities? Start with the [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) @@ -46,6 +41,17 @@ This documentation uses source code from the [standalone-activity](https://githu ::: +## Prerequisites {/* #prerequisites */} + +Standalone Activities require: + +- **Node.js** 20+ +- **Temporal TypeScript SDK** v1.24.0 or higher +- **[Temporal CLI](/cli/setup-cli)** v1.9.0 or higher + +The [Standalone Activities Quickstart](/develop/typescript/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 diff --git a/docs/encyclopedia/activities/activities.mdx b/docs/encyclopedia/activities/activities.mdx index 2212749c09..db8a398754 100644 --- a/docs/encyclopedia/activities/activities.mdx +++ b/docs/encyclopedia/activities/activities.mdx @@ -3,21 +3,27 @@ id: activities title: What is a Temporal Activity? sidebar_label: Activities description: - Understand Temporal Activities, including Activity Definitions, Types, Executions, idempotency, cancellations, Local Activities, and - Standalone Activities. + Learn how Temporal turns a plain function you write into a Temporal Activity and durably executes it as a Workflow step or background job. slug: /activities toc_max_heading_level: 4 tags: - Concepts - Activities - Durable Execution + - Job Queue --- import { Video } from '@site/src/components'; -This guide provides a comprehensive overview of Temporal Activities including -[Activity Definition](/activity-definition), [Activity Type](/activity-definition#activity-type), -[Activity Execution](/activity-execution), [Local Activity](/local-activity), and [Standalone Activity](/standalone-activity). +An Activity is a normal function or method (an [Activity Definition](/activity-definition)) that executes a single, well-defined action +(either short or long running), such as calling another service, transcoding a media file, or sending an email message. + +Activity functions are registered by name (an [Activity Type](/activity-definition#activity-type)) on a Worker that polls a Task Queue for Activity Tasks to run. +Activity code can do whatever you want, use any library or package, and otherwise be non-deterministic. +We recommend that it be [idempotent](/activity-definition#idempotency), so retries can be processed without duplicate side effects. + +Activities are started as a step in a Workflow (a [Workflow Activity](/workflow-activity)) or as a [Standalone Activity](/standalone-activity) that runs independently for [background job processing](/evaluate/development-production-features/job-queue). +This creates a durable [Activity Execution](/activity-execution) in Temporal that orchestrates the full lifecycle of an Activity, dispatching Tasks to the Activity Worker using its Task Queue and collecting results to determine next steps. :::tip @@ -27,10 +33,6 @@ Watch a short overview of what an Activity is in Temporal: ::: -An Activity is a normal function or method that executes a single, well-defined action (either short or long running), -such as calling another service, transcoding a media file, or sending an email message. Activity code can be -non-deterministic. We recommend that it be [idempotent](/activity-definition#idempotency). - Activities are the most common Temporal primitive and encompass small units of work such as: - Single write operations, like updating user information or submitting a credit card payment @@ -38,16 +40,16 @@ Activities are the most common Temporal primitive and encompass small units of w - One or more read operations followed by a write operation, like checking a product status and user address before updating an order status - A read that should be memoized, like an LLM call, a large download, or a slow-polling read -Larger pieces of functionality should be broken up into multiple activities. This makes it easier to do failure recovery, have short timeouts, and be idempotent. +Larger pieces of functionality should be broken up into multiple Activities. This makes it easier to do failure recovery, have short timeouts, and be idempotent. -Workflow code orchestrates the execution of Activities, persisting the results. If an Activity Execution fails, -any future attempt will start from the initial state, unless your code uses ([Heartbeat details payloads](/encyclopedia/detecting-activity-failures#activity-heartbeat)) -for checkpointing (storing state on the server, and using it when resuming subsequent attempts). +If an Activity attempt fails, it is automatically retried using its [Retry Policy](/activity-definition#activity-retry-policy). +Each attempt starts from the initial state, unless your code uses +a [Heartbeat detail payload](/encyclopedia/detecting-activity-failures#activity-heartbeat) for checkpointing. The +last recorded Heartbeat details are made available to the Activity function on the next attempt, so your code can +continue processing where it left off. -Activity Functions are executed by Worker Processes. When the Activity Function returns, the Worker sends the results -back to the Temporal Service as part of the [ActivityTaskCompleted](/references/events#activitytaskcompleted) Event. The -Event is added to the Workflow Execution's Event History. For other Activity-related Events, see -[Activity Events](/workflow-execution/event#activity-events). +When specific performance optimizations are more important than full durability, an Activity may be executed in the same process as a Workflow (a [Local Activity](/local-activity)), bypassing the regular Activity Execution and Task Queue. +Local Activities are not a replacement for regular Activities. -If you only want to execute one Activity Function, then you don't need to use a Workflow: you can -use your SDK Client to invoke it directly as a [Standalone Activity](/standalone-activity). +Regardless of how you invoke an Activity the [Activity Definition](/activity-definition) and Worker registration is the same. +You can write an Activity once, register it with a Worker, and invoke it as a Workflow Activity, a Standalone Activity or a Local Activity. diff --git a/docs/encyclopedia/activities/activity-definition.mdx b/docs/encyclopedia/activities/activity-definition.mdx index 80e87c8bfe..ac7f027dcc 100644 --- a/docs/encyclopedia/activities/activity-definition.mdx +++ b/docs/encyclopedia/activities/activity-definition.mdx @@ -1,36 +1,35 @@ --- id: activity-definition title: Activity Definition -description: Learn about defining Temporal Activities, including Activity Types, parameters, and implementation details. +description: Learn how to define a Temporal Activity; Activity Types, parameters, constraints, idempotency, and retry behavior for the function your Worker runs. + slug: /activity-definition toc_max_heading_level: 4 tags: - Concepts - Activities - Durable Execution + - Job Queue --- import { CaptionedImage } from '@site/src/components'; This page discusses the following: -- [Activity Definition](#activity-definition) - [Idempotency](#idempotency) -- [Constraints](#activity-constraints) - [Parameters](#activity-parameters) - [Activity Type](#activity-type) -In day-to-day conversation, the term _Activity_ denotes an [Activity Definition](/activity-definition), [Activity Type](/activity-definition#activity-type), or [Activity Execution](/activity-execution). -Temporal documentation aims to be explicit and differentiate between them. +An Activity Definition is a normal function or method that executes a single, well-defined action. +The same Activity Definition can be started as a [step in a Workflow](/workflow-activity) or as a background job using a [Standalone Activity](/standalone-activity) once it's been [registered with a Worker](#worker-registration). -## What is an Activity Definition? {/* #activity-definition */} +An Activity Definition is the code that gives rise to an [Activity Task Execution](/tasks#activity-task-execution). -An Activity Definition is the code that defines the constraints of an [Activity Task Execution](/tasks#activity-task-execution). -Activities encapsulate business logic that is prone to failure, allowing for automatic retries when issues occur. +## Define an Activity function Below are examples of basic Activity Definitions across supported SDKs. - + **[Activity Definition in Go](/develop/go/activities/basics)** @@ -159,42 +158,26 @@ impl GreetingActivities { -For full SDK-specific guides, see: - -- [How to develop an Activity Definition using the .NET SDK](/develop/dotnet/activities/basics) -- [How to develop an Activity Definition using the Go SDK](/develop/go/activities/basics) -- [How to develop an Activity Definition using the Java SDK](/develop/java/activities/basics) -- [How to develop an Activity Definition using the PHP SDK](/develop/php/activities/basics) -- [How to develop an Activity Definition using the Python SDK](/develop/python/activities/basics) -- [How to develop an Activity Definition using the Ruby SDK](/develop/ruby/activities/basics) -- [How to develop an Activity Definition using the Rust SDK](/develop/rust/activities/basics) -- [How to develop an Activity Definition using the TypeScript SDK](/develop/typescript/activities/basics) +:::tip GET STARTED -The term 'Activity Definition' is used to refer to the full set of primitives in any given language SDK that provides an access point to an Activity Function Definition——the method or function that is invoked for an [Activity Task Execution](/tasks#activity-task-execution). -Therefore, the terms Activity Function and Activity Method refer to the source of an instance of an execution. +Write an Activity Definition: +[Go](/develop/go/activities/basics) +| [Java](/develop/java/activities/basics) +| [PHP](/develop/php/activities/basics) +| [Python](/develop/python/activities/basics) +| [TypeScript](/develop/typescript/activities/basics) +| [.NET](/develop/dotnet/activities/basics) +| [Ruby](/develop/ruby/activities/basics) +| [Rust](/develop/rust/activities/basics) -Activity Definitions are named and referenced in code by their [Activity Type](/activity-definition#activity-type). +::: - ### Idempotency {/* #idempotency */} Temporal recommends that Activities be idempotent. - Idempotence means that performing an operation multiple times has the same result as performing it once. In the context of Temporal, Activities should be designed to be safely executed multiple times without causing unexpected or undesired side effects. - -Consider the power button on your laptop. When you press it, the machine is changed from one state to the other, from on to off, and vice versa. This is not an idempotent operation. Each invocation leads to a different state. However, imagine that you modified your laptop to have separate on and off buttons. Pressing the On button multiple times would have no effect beyond the initial invocation as the laptop is already on. This action is considered idempotent. - - - -Idempotency is an important design consideration in software applications as well. You have probably encountered idempotent operations in your work already. - A few examples where idempotent operations are vital would be: - **Infrastructure-as-Code (IaC) tool** - Conserving resources is important when you're provisioning infrastructure in the cloud. An IaC system that was not designed with idempotence in mind could lead to high costs if the function to provision a new server was accidentally invoked multiple times. An IaC tool that is designed with idempotence in mind ensures that multiple invocations of the tool doesn't lead to unintended instances being created. @@ -246,43 +229,151 @@ For example, Temporal will keep track of the [exponential backoff delay](/encycl For an Activity with a [Retry Policy](/encyclopedia/retry-policies) that allows retries, Temporal guarantees that the Activity will be observed as completed exactly once. However, the Activity may be executed multiple times and may even partially complete more than once during this process. This could lead to a scenario where certain parts of the Activity are executed multiple times before a successful execution is completed. :::caution -Be cautious when doing retries within your Activity because it lengthens the needed Activity timeout. Such internal retries also prevent users from counting failure metrics and make it harder for users to debug in Temporal UI when something is wrong. +You should typically not write retry logic manually within your Activity Definition. It lengthens the needed Activity timeout, prevents users from counting failure metrics, and makes it harder for users to debug in Temporal UI when something is wrong. ::: -### Constraints {/* #activity-constraints */} -Activity Definitions are executed as normal functions. +### Activity Parameters {/* #activity-parameters */} + +An Activity Definition can use function/method parameters as usual for your language. +When called from a Workflow, the parameter values and return value are recorded in the [Event History](/workflow-execution/event#event-history) of the Workflow Execution. + + +## Activity Type {/* #activity-type */} + +An Activity Type is a name given to an Activity Definition. +When starting an Activity, you can identify it by the name (Activity Type), or by a reference to its function/method/class (Activity Definition) + +## Register the Activity with a Worker {/* #worker-registration */} + +An Activity Definition doesn't run until a [Worker](/workers) registers it and starts polling the +[Task Queue](/task-queue) its Activity Tasks are dispatched on. Registration maps the +[Activity Type](#activity-type) name to your function, so a caller can start the Activity by name without holding a +reference to the code. + +One Worker can register many Activities, and one registration serves both callers: once the Worker is polling, the same +Activity can be started as a [Workflow Activity](/workflow-activity) or as a [Standalone Activity](/standalone-activity), with no +code change using the existing Worker deployment. + + + + +**[Run a Worker in Go](/develop/go/workers/run-worker-process)** + +```go +w := worker.New(c, "my-task-queue", worker.Options{}) + +w.RegisterActivity(helloworld.Activity) + +err = w.Run(worker.InterruptCh()) +``` + + + + +**[Run a Worker in Java](/develop/java/workers/run-process)** + +```java +WorkerFactory factory = WorkerFactory.newInstance(client); + +Worker worker = factory.newWorker("my-task-queue"); +worker.registerActivitiesImplementations(new GreetingActivitiesImpl()); + +factory.start(); +``` + + + + +**[Run a Worker in PHP](/develop/php/workers/run-worker-process)** + +```php +$factory = WorkerFactory::create(); + +$worker = $factory->newWorker('my-task-queue'); +$worker->registerActivity(App\DemoActivity::class); + +$factory->run(); +``` + + + + +**[Run a Worker in Python](/develop/python/workers/run-process)** + +```python +worker = Worker( + client, + task_queue="my-task-queue", + activities=[some_activity], +) +await worker.run() +``` + + + + +**[Run a Worker in TypeScript](/develop/typescript/workers/run-process)** + +```ts +const worker = await Worker.create({ + taskQueue: 'my-task-queue', + activities, +}); + +await worker.run(); +``` -In the event of failure, the function begins at its initial state when retried (except when Activity Heartbeats are established). + + -Therefore, an Activity Definition has no restrictions on the code it contains. +**[Run a Worker in C# and .NET](/develop/dotnet/workers/run-worker-process)** + +```csharp +var options = new TemporalWorkerOptions("my-task-queue"); +options.AddAllActivities(typeof(GreetingActivities), null); + +using var worker = new TemporalWorker(client, options); +await worker.ExecuteAsync(CancellationToken.None); +``` -### Parameters {/* #activity-parameters */} + + -An Activity Definition can support as many parameters as needed. +**[Run a Worker in Ruby](/develop/ruby/workers/run-worker-process)** -All values passed through these parameters are recorded in the [Event History](/workflow-execution/event#event-history) of the Workflow Execution. -Return values are also captured in the Event History for the calling Workflow Execution. +```ruby +worker = Temporalio::Worker.new( + client: client, + task_queue: 'my-task-queue', + activities: [SayHello] +) -Activity Definitions must contain the following parameters: +worker.run +``` -- Context: an optional parameter that provides Activity context within multiple APIs. -- Heartbeat: a notification from the Worker to the Temporal Service that the Activity Execution is progressing. Cancelations are allowed only if the Activity Definition permits Heartbeating. -- Timeouts: intervals that control the execution and retrying of Activity Task Executions. + + -Other parameters, such as [Retry Policies](/encyclopedia/retry-policies) and return values, can be seen in the implementation guides, listed in the next section. +**[Run a Worker in Rust](/develop/rust/workers/worker-process)** -## What is an Activity Type? {/* #activity-type */} +```rust +let worker_options = WorkerOptions::new("my-task-queue") + .register_activities(GreetingActivities) + .build(); +``` -An Activity Type is the mapping of a name to an Activity Definition. + + -Activity Types are scoped through Task Queues. +Go and TypeScript can set the [Activity Type](#activity-type) name at registration. The other SDKs set it on the +definition itself, as shown in the examples at the top of this page. ## Best practices for defining Activities Here are some best practices you can use when you are creating Activities for your Workflow: -- Activity arguments and return values should be serializable. +- Activity arguments and return values must be serializable. - Activities that perform writes should be idempotent. -- Activities have [timeouts](/develop/python/activities/timeouts#activity-heartbeats) and [retry policies](/encyclopedia/retry-policies). For Activities, your operation should either complete within a few minutes or it should support the ability to heartbeat or poll for a result. This way it will be clear to the Workflow when the Activity is still making progress. -- You need to specify at least one timeout, typically the [start_to_close timeout](/encyclopedia/detecting-activity-failures#start-to-close-timeout). Keep in mind that the shorter the timeout, the faster Temporal will retry upon failure. See the [Activity retry policy section](#activity-retry-policy) to learn more. +- Activities have [timeouts](/develop/python/activities/timeouts#activity-heartbeats) and [retry policies](/encyclopedia/retry-policies). For Activities, your operation should either complete within a few minutes or it should heartbeat. This way it will be clear to the Workflow when the Activity is still making progress. +- You need to specify at least one timeout, typically the [start_to_close timeout](/encyclopedia/detecting-activity-failures#start-to-close-timeout). Keep in mind that the shorter the timeout, the faster Temporal will detect a problem and retry. See the [Activity retry policy section](#activity-retry-policy) to learn more. diff --git a/docs/encyclopedia/activities/activity-execution.mdx b/docs/encyclopedia/activities/activity-execution.mdx index 613e6cfb6b..8dd1d598ba 100644 --- a/docs/encyclopedia/activities/activity-execution.mdx +++ b/docs/encyclopedia/activities/activity-execution.mdx @@ -1,13 +1,14 @@ --- id: activity-execution title: Activity Execution -description: Understand how Activity Executions work in Temporal, including retries, timeouts, and failure handling. +description: Learn how to start an Activity as a durable Activity Execution with built-in retries, timeouts, and failure handling. slug: /activity-execution toc_max_heading_level: 4 tags: - Concepts - Activities - Durable Execution + - Job Queue --- import { CaptionedImage } from '@site/src/components'; @@ -15,28 +16,89 @@ import { CaptionedImage } from '@site/src/components'; This page discusses the following: - [Activity Execution](#activity-execution) +- [Activity Execution Lifecycle](#activity-execution-lifecycle) - [Cancellation](#cancellation) - [Activity Id](#activity-id) - [Asynchronous Activity Completion](#asynchronous-activity-completion) - [Task Token](#task-token) -## What is an Activity Execution? {/* #activity-execution */} -An Activity Execution is the full chain of [Activity Task Executions](/tasks#activity-task-execution). +When an Activity caller starts an [Activity](/activities), an Activity Execution is created that orchestrates its full lifecycle, including retries. -:::info +[Workflow Activities](/workflow-activity) and [Standalone Activities](/standalone-activity) are durable Activity Executions that live in the Temporal Service. +They [dispatch Tasks to Activity Workers using an Activity Task Queue](/activity-execution#activity-execution-lifecycle) and collect results to determine next steps. -- [How to start an Activity Execution using the Go SDK](/develop/go/activities/execution) -- [How to start an Activity Execution using the Java SDK](/develop/java/activities/execution) -- [How to start an Activity Execution using the PHP SDK](/develop/php/activities/execution) -- [How to start an Activity Execution using the Python SDK](/develop/python/activities/execution) -- [How to start an Activity Execution using the TypeScript SDK](/develop/typescript/activities/execution) -- [How to start an Activity Execution using the .NET SDK](/develop/dotnet/activities/execution) -- [How to start an Activity Execution using the Ruby SDK](/develop/ruby/activities/execution) -- [How to start an Activity Execution using the Rust SDK](/develop/rust/activities/execution) +## How can an Activity be invoked? {/* #activity-execution */} + +Once an Activity function has been [defined and registred in a Worker](/activity-definition) it can be invoked in different ways. + +### Workflow Activity Executions {/* #workflow-activity-executions */} + +A [Workflow Activity](/workflow-activity) is started as a step in a Workflow using the Temporal SDK and its lifetime is scoped to the Workflow. +The Workflow schedules the Activity, and the result is delivered back to the Workflow when the +Activity Execution closes. Each step is recorded in the Workflow Execution's +[Event History](/workflow-execution/event), for example the +Workflow [ActivityTaskCompleted](/references/events#activitytaskcompleted) Event. For other related Events, see +[Workflow Activity Events](/workflow-execution/event#activity-events). + +:::tip GET STARTED + +Start a Workflow Activity: +[Go](/develop/go/activities/execution) +| [Java](/develop/java/activities/execution) +| [PHP](/develop/php/activities/execution) +| [Python](/develop/python/activities/execution) +| [TypeScript](/develop/typescript/activities/execution) +| [.NET](/develop/dotnet/activities/execution) +| [Ruby](/develop/ruby/activities/execution) +| [Rust](/develop/rust/activities/execution) ::: +### Standalone Activity Executions {/* #standalone-activity-executions */} + +A [Standalone Activity](/standalone-activity) is an independent top-level execution, started directly by a Temporal SDK [Client](/encyclopedia/temporal-client), with its own lifetime. + The Client gets a handle and +fetches the result through it. +Because there's no Workflow, there is no Workflow Event History. +Standalone Activities use a [separate Id space](/standalone-activity#deduplication-and-id-space-uniqueness) for deduplication and uniqueness and provide full [visibility](/standalone-activity#visibility) and [lifecycle control](/standalone-activity#lifecycle-control). + + +| | [Standalone Activity](/standalone-activity) | [Workflow Activity](/workflow-activity) | +| --- | --- | --- | +| Started by | [Client](/encyclopedia/temporal-client) | Workflow code | +| Lifetime | Independent top-level execution | Scoped to the Workflow Run | +| Result delivered to | The Client, through a handle | The Workflow | +| Recorded in Event History | No Workflow, so no Event History | Yes | +| Activity Id space | [Separate Id space](/standalone-activity#deduplication-and-id-space-uniqueness) | Scoped to the Workflow Run | +| Best for | [Durable job processing](/evaluate/development-production-features/job-queue) | Multi-step orchestration | + +:::tip GET STARTED + +Start a Standalone Activity: +[Go](/develop/go/activities/standalone-activities-quickstart#execute-activity) +| [Python](/develop/python/activities/standalone-activities-quickstart#execute-a-standalone-activity) +| [Java](/develop/java/activities/standalone-activities-quickstart#execute-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) + +::: + +### Local Activity Executions {/* #local-activity-executions */} + +When specific performance optimizations are more important than full durability, an Activity may be executed in the same process as a Workflow (a [Local Activity](/local-activity)), bypassing the regular Activity Execution and Task Queue. + +:::tip + +[Local Activities](/local-activity) are not a replacement for regular Activities, since they bypass the regular Activity Execution lifecycle and lack full durability. + +::: + +## Activity Execution lifecycle + +[Workflow Activities](/workflow-activity) and [Standalone Activities](/standalone-activity) use the regular Activity Execution lifecycle, which includes the full chain of [Activity Task Executions](/tasks#activity-task-execution). + You can customize [Activity Execution timeouts](/encyclopedia/detecting-activity-failures#start-to-close-timeout) and @@ -111,8 +173,7 @@ an Activity Id if an earlier Activity Execution with the same Id has closed.) An Activity Id can be used to [complete the Activity asynchronously](#asynchronous-activity-completion). -[Standalone Activities](/standalone-activity) have a separate ID space from Workflows and other Temporal primitives. -This means use of conflict policy (`USE_EXISTING`, …) and reuse policy (`REJECT_DUPLICATES`, …) will only observe the Standalone Activity ID space. +[Standalone Activities](/standalone-activity) have a [separate Id space](/standalone-activity#deduplication-and-id-space-uniqueness) from [the Workflow Id space](/workflow-execution/workflowid-runid) for deduplication and uniqueness. ## What is Asynchronous Activity Completion? {/* #asynchronous-activity-completion */} @@ -120,15 +181,18 @@ Asynchronous Activity Completion is a feature that enables an Activity Function Execution to complete. The Temporal Client can then be used from anywhere to both Heartbeat Activity Execution progress and eventually complete the Activity Execution and provide a result. -How to complete an Activity Asynchronously in: +:::tip GET STARTED -- [.NET](/develop/dotnet/activities/asynchronous-activity) -- [Go](/develop/go/activities/asynchronous-activity) -- [Java](/develop/java/activities/asynchronous-activity) -- [PHP](/develop/php/activities/asynchronous-activity) -- [Python](/develop/python/activities/asynchronous-activity) -- [Ruby](/develop/ruby/activities/asynchronous-activity) -- [TypeScript](/develop/typescript/activities/asynchronous-activity) +Complete an Activity Asynchronously: +[Go](/develop/go/activities/asynchronous-activity) +| [Java](/develop/java/activities/asynchronous-activity) +| [PHP](/develop/php/activities/asynchronous-activity) +| [Python](/develop/python/activities/asynchronous-activity) +| [TypeScript](/develop/typescript/activities/asynchronous-activity) +| [.NET](/develop/dotnet/activities/asynchronous-activity) +| [Ruby](/develop/ruby/activities/asynchronous-activity) + +::: ### When to use Async Completion diff --git a/docs/encyclopedia/activities/activity-operations.mdx b/docs/encyclopedia/activities/activity-operations.mdx index 7ea73a490a..63e4d278af 100644 --- a/docs/encyclopedia/activities/activity-operations.mdx +++ b/docs/encyclopedia/activities/activity-operations.mdx @@ -1,12 +1,14 @@ --- id: activity-operations title: Activity Operations -description: Operations you can perform on an Activity - Pause, Unpause, Reset, and Update Options. +description: Learn how to manage a running Activity Execution with commands to Pause, Unpause, Reset, Update Options, Request Cancel, Terminate, and Delete. slug: /activity-operations toc_max_heading_level: 4 tags: - Concepts - Activities + - Temporal CLI + - Job Queue --- This page discusses the following: @@ -15,6 +17,10 @@ This page discusses the following: - [Unpause](#unpause) - [Reset](#reset) - [Update Options](#update-options) +- [Request Cancel](#request-cancel) +- [Terminate](#terminate) +- [Delete](#delete) +- [Batch operations](#batch-operations) - [Observability](#observability) Activity Operations are deliberate actions you perform on a specific [Activity Execution](/activity-execution), as @@ -22,27 +28,53 @@ opposed to lifecycle behaviors like [retries](/encyclopedia/retry-policies) and [timeouts](/encyclopedia/detecting-activity-failures) which happen automatically. You can perform Activity Operations through the [CLI](/cli/command-reference/activity), the UI, or directly via the gRPC -API. Activity Operations don't apply to [Local Activities](/local-activity) or -[Standalone Activities](/standalone-activity). +API. They apply to Workflow Activities and to [Standalone Activities](/standalone-activity). They don't apply to +[Local Activities](/local-activity). :::note Public Preview -Activity Operations are in [Public Preview](/evaluate/development-production-features/release-stages#public-preview). -Pause, Unpause, and Reset are available in Server v1.28.0+. Self-hosted UI requires v2.47.0+. +Activity Operations are in [Public Preview](/evaluate/development-production-features/release-stages#public-preview), +except for Standalone Activity commands: Request Cancel, Terminate, Delete which are GA. + +For [Workflow Activities](/workflow-activity), Pause, Unpause, and Reset are available in Server +v1.28.0+. Self-hosted UI requires v2.47.0+. For [Standalone Activities](/standalone-activity), Pause, +Unpause, Reset, and Update Options are available in Server v1.32.0+. Activity Operations aren't available as SDK client methods. They're operational controls designed for the CLI, UI, and -gRPC API - not for programmatic use in Workflow or Activity code. +gRPC API - they are not for programmatic use in Workflow or Activity code. ::: ## Operations summary -| Operation | What it does | CLI | -| --------------------------------- | -------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------ | -| [Pause](#pause) | Stops retries. In-flight execution continues unless the Activity uses Heartbeat. | [`temporal activity pause`](/cli/command-reference/activity#pause) | -| [Unpause](#unpause) | Resumes a Paused Activity. The next execution starts immediately. | [`temporal activity unpause`](/cli/command-reference/activity#unpause) | -| [Reset](#reset) | Clears retry state (attempts, backoff) and schedules a new execution. | [`temporal activity reset`](/cli/command-reference/activity#reset) | -| [Update Options](#update-options) | Changes timeouts, Retry Policy, or Task Queue without restarting the Activity. | [`temporal activity update-options`](/cli/command-reference/activity#update-options) | +| Operation | What it does | Workflow Activity | Standalone Activity | CLI | +| --------------------------------- | -------------------------------------------------------------------------------- | ----------------- | ------------------- | ------------------------------------------------------------------------------------ | +| [Pause](#pause) | Stops retries. In-flight execution continues unless the Activity uses Heartbeat. | Yes | Yes | [`temporal activity pause`](/cli/command-reference/activity#pause) | +| [Unpause](#unpause) | Resumes a Paused Activity. The next execution starts immediately. | Yes | Yes | [`temporal activity unpause`](/cli/command-reference/activity#unpause) | +| [Reset](#reset) | Clears retry state (attempts, backoff) and schedules a new execution. | Yes | Yes | [`temporal activity reset`](/cli/command-reference/activity#reset) | +| [Update Options](#update-options) | Changes timeouts, Retry Policy, or Task Queue without restarting the Activity. | Yes | Yes | [`temporal activity update-options`](/cli/command-reference/activity#update-options) | +| [Request Cancel](#request-cancel) | Requests that an execution close gracefully, letting your code clean up. | Through the Workflow | Yes | [`temporal activity cancel`](/cli/command-reference/activity#cancel) | +| [Terminate](#terminate) | Forcefully closes an execution with no opportunity for your code to clean up. | No | Yes | [`temporal activity terminate`](/cli/command-reference/activity#terminate) | +| [Delete](#delete) | Terminates the execution if it's running, then deletes it asynchronously. | No | Yes | [`temporal activity delete`](/cli/command-reference/activity) | + +A Workflow Activity can't be cancelled directly. It receives a cancellation request as a result of its +[Workflow](/workflows) being cancelled, and from that point behaves the same way a Standalone Activity does. + +### What an operation guarantees + +Every operation does two things, and they succeed independently. + +**Server-side state changes immediately.** Terminate closes the execution. Request Cancel closes it immediately when no +attempt is running. This doesn't depend on the Activity Heartbeating. + +**Interrupting an already-running attempt is best-effort.** Request Cancel, Terminate, Reset, and Pause all attempt it, +by the same mechanism: the request reaches your code through the Activity's Heartbeat. An Activity that doesn't +Heartbeat isn't interrupted mid-attempt. + +Because interruption is best-effort, **a Request Cancel, Reset, or Pause request can succeed without the operation +taking effect.** When an attempt is running, your code may complete or fail non-retryably instead of honoring the +request. Only Terminate and Delete discard Activity progress unconditionally. A successful response means the request +was accepted, not that the Activity stopped. ## Pause {/* #pause */} @@ -81,6 +113,14 @@ temporal activity pause \ --reason "Downstream API is down, pausing until recovery" ``` +To target a Standalone Activity, omit `--workflow-id`: + +```bash +temporal activity pause \ + --activity-id my-activity \ + --reason "Downstream API is down, pausing until recovery" +``` + See the [CLI reference for `temporal activity pause`](/cli/command-reference/activity#pause) for all options. ### Detect Pause in Activity code @@ -115,9 +155,10 @@ but they must be Unpaused separately. ### Limitations -- **Pause operates on individual Activities by ID within a single Workflow.** Unlike Unpause, Reset, and Update Options, - there's no `--query` flag. To pause multiple Activities, issue separate commands for each Activity ID. -- **No Namespace-wide query for Paused Activities.** You must know the Workflow Id. See [Observability](#observability). +- **Pause operates on individual Activities.** There's no `--query` flag on `pause`, so there's no batch form. To pause + multiple Activities, issue separate commands for each Activity Id. See [Batch operations](#batch-operations). +- **No Namespace-wide query for Paused Workflow Activities.** You must know the Workflow Id. See + [Observability](#observability). ## Unpause {/* #unpause */} @@ -133,9 +174,8 @@ Unpause resumes a Paused Activity Execution. - **The Activity is rescheduled immediately.** Any remaining retry backoff is discarded. The next execution starts right away. -- **Attempt count and Heartbeat data are preserved by default.** The Activity resumes from where it left off. Use - `--reset-attempts` or `--reset-heartbeats` on the CLI to clear these, or use [Reset](#reset) to restart from - attempt 1. +- **Attempt count, Heartbeat details, and timeouts are preserved.** The Activity resumes from where it left off. Use + [Reset](#reset) to restart from attempt 1. Unpause is idempotent. Unpausing an Activity that isn't Paused has no effect. Unpausing an Activity that has already completed returns an error. @@ -148,8 +188,14 @@ temporal activity unpause \ --activity-id my-activity ``` -See the [CLI reference for `temporal activity unpause`](/cli/command-reference/activity#unpause) for all options, -including `--reset-attempts` and `--reset-heartbeats` to clear state on resume. +To target a Standalone Activity, omit `--workflow-id`: + +```bash +temporal activity unpause \ + --activity-id my-activity +``` + +See the [CLI reference for `temporal activity unpause`](/cli/command-reference/activity#unpause) for all options. ### Important considerations @@ -182,26 +228,38 @@ Reset clears an Activity's retry state and schedules a fresh execution. ### What happens when you Reset an Activity - **The attempt count resets to 1.** The Activity gets a full set of retry attempts regardless of how many it had used. -- **Retry backoff is discarded.** If the Activity was in a backoff wait, it's rescheduled to run immediately. +- **Heartbeat details are preserved.** The new attempt starts with the last recorded Heartbeat details available, so + your code can use a checkpoint it previously saved in Heartbeat details. Pass `--clear-heartbeat-details` to discard + them instead. +- **Per-attempt timeouts are re-armed.** They restart for the new attempt rather than being removed. +- **Retry backoff is discarded.** If the Activity is between attempts, waiting out a backoff, the new attempt is + dispatched right away. If an attempt is running, see + [Reset while an attempt is running](#reset-while-an-attempt-is-running). - **If the Activity is Paused, Reset also Unpauses it.** Use `--keep-paused` to Reset the attempt count without resuming - execution. With `--keep-paused`, the attempt count and Heartbeat data (if `--reset-heartbeats`) are reset, but the - Activity stays Paused. No retry is scheduled until you [Unpause](#unpause) separately. + execution. With `--keep-paused`, the attempt count is reset but the Activity stays Paused. No retry is scheduled + until you [Unpause](#unpause) separately. - **Resetting an Activity doesn't affect the parent Workflow.** The Workflow continues Running, and Signals, Queries, and Updates on the parent Workflow are unaffected. - **Workflow code has no visibility into Activity Operations.** Reset doesn't produce an Event History event, so the Workflow can't detect or react to it. See [Observability](#observability). -- **[Heartbeating](/encyclopedia/detecting-activity-failures#activity-heartbeat) determines whether an in-flight - execution is interrupted:** - - **Activities with Heartbeat** are interrupted on their next Heartbeat. The SDK may raise a Reset-specific error so - the Activity can clean up before exiting. The next execution starts at attempt 1. - - **Activities without Heartbeat** continue running to completion. Reset doesn't cancel, interrupt, or schedule a - concurrent execution. If the Activity was already retrying, the Temporal Service rejects the current execution's - result because Reset changed the expected attempt number, and a fresh execution is scheduled after the - [Start-To-Close Timeout](/encyclopedia/detecting-activity-failures#start-to-close-timeout) expires. If it was on its - first execution, a successful result is still delivered to the Workflow normally. - **Reset is idempotent.** Resetting an Activity that's already at attempt 1 with no backoff has no effect. Resetting a completed Activity returns an error. +#### Reset while an attempt is running + +Reset is handled cooperatively. + +- The reset request is delivered to the running attempt through the Activity's + [Heartbeat](/encyclopedia/detecting-activity-failures#activity-heartbeat), if the Activity heartbeats. +- Your Worker can accept the request and stop processing the current attempt, or carry on and complete the Activity + successfully. +- The Temporal Service processes the reset once the current attempt finishes, including by hitting its + [Start-To-Close Timeout](/encyclopedia/detecting-activity-failures#start-to-close-timeout). A new attempt then + starts and a new Activity Task is dispatched to a Worker. + +Reset never dispatches a new attempt while one is still running, and it never runs two attempts concurrently. This is +the same for Workflow Activities and Standalone Activities. + ### CLI usage ```bash @@ -216,8 +274,14 @@ temporal activity reset \ --keep-paused ``` -See the [CLI reference for `temporal activity reset`](/cli/command-reference/activity#reset) for all options, including -`--reset-heartbeats` and bulk mode via `--query`. +To target a Standalone Activity, omit `--workflow-id`: + +```bash +temporal activity reset \ + --activity-id my-activity +``` + +See the [CLI reference for `temporal activity reset`](/cli/command-reference/activity#reset) for all options. ### Detect Reset in Activity code @@ -239,13 +303,14 @@ handle these cases differently, for example saving partial progress on Reset whi [Schedule-To-Close Timeout](/encyclopedia/detecting-activity-failures#schedule-to-close-timeout). The deadline is calculated from when the Activity was originally scheduled. Use [`update-options`](#update-options) to extend the timeout before or after Reset. -- **Heartbeat details are preserved by default.** If your Activity uses Heartbeat details for progress tracking and you - want a clean restart, pass `--reset-heartbeats`. -- **Reset won't interrupt an Activity that doesn't Heartbeat.** The current execution runs to completion, which could - take up to the full [Start-To-Close Timeout](/encyclopedia/detecting-activity-failures#start-to-close-timeout). If the - Activity had already retried (attempt > 1), the Temporal Service rejects the current execution's result because Reset - changed the expected attempt number. The Activity waits for its Start-To-Close Timeout to expire before a new - execution is scheduled. +- **Heartbeat details survive a Reset.** If your Activity uses Heartbeat details for progress tracking, the new attempt + still has the last recorded details, so your code can use a checkpoint it previously saved in them. Pass + `--clear-heartbeat-details` when you want the new attempt to start over from the beginning. +- **Reset won't reach an Activity that doesn't Heartbeat.** The request has no way to be delivered, so the current + attempt runs to completion, which could take up to the full + [Start-To-Close Timeout](/encyclopedia/detecting-activity-failures#start-to-close-timeout). The reset still applies + afterwards, if the Activity is still Open. See + [Reset while an attempt is running](#reset-while-an-attempt-is-running). - **`--restore-original-options` restores the Activity's original configuration.** It reverts timeouts, Retry Policy, and Task Queue to the values from when the Activity was first scheduled. - **Bulk Reset can overwhelm downstream services.** When using `--query` to Reset Activities across many Workflows, use @@ -292,8 +357,16 @@ temporal activity update-options \ --schedule-to-close-timeout 24h ``` +To target a Standalone Activity, omit `--workflow-id`: + +```bash +temporal activity update-options \ + --activity-id my-activity \ + --schedule-to-close-timeout 24h +``` + See the [CLI reference for `temporal activity update-options`](/cli/command-reference/activity#update-options) for all -options, including Retry Policy, Task Queue, and bulk mode via `--query`. +options, including Retry Policy and Task Queue. ### Important considerations @@ -301,6 +374,171 @@ options, including Retry Policy, Task Queue, and bulk mode via `--query`. apply immediately, the Activity must finish or fail its current execution first. - **`--restore-original-options` is batch-only.** This flag only works with `--query`. It's silently ignored in single-workflow mode. It can't be combined with other option changes in the same command. +- **Restoring original options requires a stored snapshot.** For Activities that started before your Temporal Service + supported Activity Operations, no snapshot exists and the request is rejected. + +## Request Cancel {/* #request-cancel */} + +Request Cancel asks an Activity Execution to close gracefully, giving your code a chance to clean up. + +### When to Request Cancel + +- A [Standalone Activity](/standalone-activity) is no longer needed, and you want it to stop at a safe point rather + than be killed mid-attempt. +- A job was submitted in error, and you want the Activity to release the resources it has already acquired. + +A [Workflow Activity](/workflow-activity) can't be canceled directly. It receives a cancellation request when its +Workflow is canceled, and from that point behaves the same way a Standalone Activity does. + +### What happens when you Request Cancel an Activity + +The Activity Execution transitions to `CancelRequested`. + +- **If no attempt is running,** the execution closes immediately. This doesn't depend on the Activity Heartbeating. +- **If an attempt is running,** the request reaches your code through the Activity's + [Heartbeat](/encyclopedia/detecting-activity-failures#activity-heartbeat). A Cancellation error is raised when the + next Heartbeat response is received, and the Activity transitions to canceled status if your code lets that error + propagate. +- **If the Activity doesn't Heartbeat,** it isn't interrupted mid-attempt. The request takes effect at the next attempt + boundary, for example when the + [Start-To-Close Timeout](/encyclopedia/detecting-activity-failures#start-to-close-timeout) elapses. + +See [Cancellation](/activity-execution#cancellation) for how your Activity code accepts or ignores a Cancellation. + +### CLI usage + +```bash +temporal activity cancel \ + --activity-id my-activity \ + --reason "No longer needed" +``` + +See the [CLI reference for `temporal activity cancel`](/cli/command-reference/activity#cancel) for all options. + +### Important considerations + +- **A successful response means the request was accepted, not that the Activity stopped.** Your code may complete or + fail non-retryably instead of honoring the request. +- **Cancellation can be requested only once.** Repeating the request doesn't deliver a second Cancellation. +- **Request Cancel takes precedence** over Reset and Pause. See [Successive operations](#successive-operations). + +## Terminate {/* #terminate */} + +Terminate forcefully closes an Activity Execution with no opportunity for your code to clean up. + +### When to Terminate + +- A [Standalone Activity](/standalone-activity) is stuck or misbehaving and you need it closed now, whether or not it + Heartbeats. +- A Request Cancel was already sent and the Activity didn't honor it. + +Terminate isn't available for [Workflow Activities](/workflow-activity), because the Workflow owns the execution's +lifetime. + +### What happens when you Terminate an Activity + +The Activity Execution closes immediately and discards its progress. Activity code can't see or respond to a +termination, so no cleanup runs and no Cancellation error is raised. Unlike Request Cancel, this doesn't depend on the +Activity Heartbeating, and it can't be declined by your code. + +The Execution and its result remain visible to `temporal activity describe` and `temporal activity list` for the +Namespace [Retention Period](/temporal-service/temporal-server#retention-period). To remove the record sooner, use +[Delete](#delete). + +### CLI usage + +```bash +temporal activity terminate \ + --activity-id my-activity \ + --reason "Bad input" +``` + +`--reason` defaults to a message naming the current user. See the +[CLI reference for `temporal activity terminate`](/cli/command-reference/activity#terminate) for all options. + +### Important considerations + +- **Terminate discards Activity progress unconditionally.** Prefer [Request Cancel](#request-cancel) when your code + needs to release resources or record a checkpoint. +- **Terminating doesn't delete the record.** The closed Execution stays queryable until the Retention Period elapses. + +## Delete {/* #delete */} + +Delete terminates the Activity Execution if it's running, then deletes it asynchronously. + +### When to Delete + +- You need an Execution and its result removed before the Namespace + [Retention Period](/temporal-service/temporal-server#retention-period) elapses. +- You want to free an Activity Id for reuse without waiting out retention. See + [Activity Id Reuse Policy](/standalone-activity#activity-id-reuse-policy). + +Delete isn't available for [Workflow Activities](/workflow-activity). + +### What happens when you Delete an Activity + +If the Execution is still running, it's terminated first, with the same semantics as [Terminate](#terminate): no +cleanup runs and progress is discarded. The Execution record is then removed asynchronously, so it may remain visible +briefly after the command returns. + +Once deleted, the Execution no longer appears in `temporal activity describe` or `temporal activity list`, and its +Activity Id becomes available for reuse. + +### CLI usage + +```bash +temporal activity delete \ + --activity-id my-activity +``` + +See the [CLI reference for `temporal activity`](/cli/command-reference/activity) for all options. + +### Important considerations + +- **Delete is irreversible.** The Execution, its inputs, and its result are gone; there's no recovery. +- **Deletion is asynchronous.** A successful response means the request was accepted, not that the record is already + removed. + +## Successive operations {/* #successive-operations */} + +When operations conflict, precedence is **Request Cancel, then Reset, then Pause**. A higher-precedence request wins +over a pending lower-precedence one. + +Requests that can't apply to the Activity's current state return an error rather than being queued: + +- `FailedPrecondition` when the Activity exists but isn't in a state that accepts the operation. +- `NotFound` when the Activity or its run can't be found. + +Pause and Unpause interact with timers in a way worth knowing before you use them together: + +- **Timers keep running while an Activity is Paused.** Pausing doesn't stop the Schedule-To-Close Timeout. +- **No new attempt is scheduled while Paused.** +- **On Unpause, a retry that's already past due starts immediately.** +- **Before the first attempt, Unpause honors the Activity's original Start Delay deadline.** If that deadline has + passed, the Activity is dispatched immediately. Start Delay isn't restarted from the Unpause time, and it doesn't + apply to retry attempts. + +## Batch operations {/* #batch-operations */} + +You can apply some operations to many Activities at once with a `--query` [List Filter](/list-filter) instead of a +single Activity Id. + +**Standalone Activities** currently only support batch operations for Request Cancel, Terminate, and Delete: + +```bash +temporal activity terminate \ + --query 'ActivityType="ProcessImage" AND ExecutionStatus="Running"' \ + --reason "Bad input batch" +``` + +For **Workflow Activities**, `--query` applies to Reset, Unpause, and Update Options. + +Use `--jitter` to stagger a batch so a recovering downstream service isn't hit by every retry at once. + +## Billable Actions {/* #billable-actions */} + +In Temporal Cloud, Pause, Reset, and Update Options each count as one +[Action](/cloud/actions#activity). Unpause is free. ## Observability {/* #observability */} diff --git a/docs/encyclopedia/activities/local-activity.mdx b/docs/encyclopedia/activities/local-activity.mdx index ceeb554bf4..129e992e71 100644 --- a/docs/encyclopedia/activities/local-activity.mdx +++ b/docs/encyclopedia/activities/local-activity.mdx @@ -1,7 +1,7 @@ --- id: local-activity title: Local Activity -description: Learn about Local Activities in Temporal, how they work, when to use them, and how they differ from regular Activities. +description: Learn about Local Activities that run in the same Worker process as the Workflow that schedules it, trading full durability for lower latency and a smaller Event History. slug: /local-activity toc_max_heading_level: 4 tags: diff --git a/docs/encyclopedia/activities/standalone-activity.mdx b/docs/encyclopedia/activities/standalone-activity.mdx index 200ec13f25..528869273d 100644 --- a/docs/encyclopedia/activities/standalone-activity.mdx +++ b/docs/encyclopedia/activities/standalone-activity.mdx @@ -1,110 +1,373 @@ --- id: standalone-activity title: Standalone Activity -description: Learn about Standalone Activities in Temporal, their benefits, execution model, and when to use them. +description: Learn about durable job processing with Standalone Activities that run independently from a Workflow. slug: /standalone-activity toc_max_heading_level: 4 tags: - Concepts - Activities - Durable Execution + - Job Queue --- -import { CaptionedImage, ReleaseNoteHeader } from '@site/src/components'; +import { CaptionedImage } from '@site/src/components'; - - Available in [Temporal Cloud](#temporal-cloud-support) and in Temporal Server v1.31.0 or higher (included in [Temporal CLI](#temporal-cli-support) v1.7.0 or higher). - +## What is a Standalone Activity? {/* #standalone-activity */} -See [limitations](#public-preview-limitations) below. +A Standalone [Activity](/activities) is a top-level [Activity Execution](/activity-execution) started directly by a +[Client](/encyclopedia/temporal-client), without using a Workflow. -## What is a Standalone Activity? {/* #standalone-activity */} +**Standalone Activities are Temporal's [job queue](/evaluate/development-production-features/job-queue)** - the +simplest way to run durable, retryable background jobs on Temporal. A job is queued, dispatched to one of your Workers, +retried on failure, and kept addressable the whole time. -If you need to orchestrate multiple Activities, use a [Workflow](/workflows). But if you just need to -execute a single Activity, use a Standalone Activity. +Use it to run a single Activity reliably - sending an email, processing a webhook, syncing data, transcoding a file. +If you need to orchestrate multiple steps that depend on each other, use a [Workflow](/workflows) instead. Standalone +Activities don't replace Workflows, and you can use both in the same application. -Standalone Activities are Temporal’s [job queue](/evaluate/development-production-features/job-queue) - -the simplest way to run durable, retryable tasks on Temporal. +## Coming from another job queue? {/* #coming-from-another-job-queue */} -
- -
+Temporal uses its own names for some job queue concepts, here's how they map: -A Standalone Activity is a top-level [Activity Execution](/activity-execution) started directly by a -[Client](/encyclopedia/temporal-client), without using a Workflow. This results in -fewer [Billable Actions](/cloud/actions-usage#actions-in-workflows) in Temporal Cloud than using a Workflow -to run a single Activity. If your Activity Execution is short-lived, you will also notice lower -latency, since there are fewer Worker round-trips. +| In a job queue | In Temporal | +| --- | --- | +| The function a job runs | An [Activity Definition](/activity-definition) - a normal function, registered by name | +| One enqueued job | A **Standalone Activity Execution** - one durable run, addressable by its Activity Id | +| The queue | A [Task Queue](/task-queue) that your Workers poll | +| A worker process | An [Activity Worker](/workers) - your process, running your code | -You write your Activity Functions the same way for both. In fact, the same Activity Function can be -executed as a Standalone Activity and as a Workflow Activity with no code changes. +For the full comparison and a migration path, see +[Job Queue](/evaluate/development-production-features/job-queue) and +[Migrate a Celery task queue to a Standalone Activity](/guides/celery-to-standalone-activity). :::tip GET STARTED Pick your SDK and follow the quickstart: - -- [Go SDK - Standalone Activities quickstart and code sample](/develop/go/activities/standalone-activities-quickstart) -- [Python SDK - Standalone Activities quickstart and code sample](/develop/python/activities/standalone-activities-quickstart) -- [.NET SDK - Standalone Activities quickstart and code sample](/develop/dotnet/activities/standalone-activities-quickstart) -- [Java SDK - Standalone Activities quickstart and code sample](/develop/java/activities/standalone-activities-quickstart) -- [Ruby SDK - Standalone Activities quickstart and code sample](/develop/ruby/activities/standalone-activities-quickstart) -- [TypeScript SDK - Standalone Activities quickstart and code sample](/develop/typescript/activities/standalone-activities-quickstart) +[Go](/develop/go/activities/standalone-activities-quickstart) +| [Java](/develop/java/activities/standalone-activities-quickstart) +| [Python](/develop/python/activities/standalone-activities-quickstart) +| [TypeScript](/develop/typescript/activities/standalone-activities-quickstart) +| [.NET](/develop/dotnet/activities/standalone-activities-quickstart) +| [Ruby](/develop/ruby/activities/standalone-activities-quickstart) ::: -## Use cases +## Key features -Standalone Activities can be used for [durable job processing use -cases](/evaluate/development-production-features/job-queue) such as sending an email, processing a -webhook, syncing data, or executing a single function reliably with built-in retries and timeouts. +### Durable job lifecycle {/* #job-lifecycle */} -## Key features -- Execute any Temporal Activity as a top-level primitive without the overhead of a Workflow -- Native async job processing model: schedule -> dispatch -> process -> result -- No head-of-line blocking - a slow job doesn’t block the dispatch of other Tasks -- Arbitrary length jobs with heartbeats for liveness and checkpointing progress -- At-least-once execution by default with native retry policy and timeouts -- At-most-once execution if retry max attempts is 1 -- Addressable - get an Activity ID / Run ID and get the result, cancel, and terminate -- Deduplication - with conflict policy: (USE_EXISTING, ...), reuse policy: (REJECT_DUPLICATES, ...) -- Separate ID space from Workflows - Standalone Activities are a different kind of top-level execution -- Priority and fairness - multi-tenant fairness, weighted priority tiers, and safeguards against starvation of lower-weighted tasks -- Visibility - list Activity Executions and view status, retry count, and last error -- Manual completion by ID (or token): ignore activity return and wait for external completion -- Activity metrics - including counts for success, failure, timeout, and cancel -- Dual use - execute Activities within a Workflow or standalone with no Worker code changes - -## Observability {/* #observability */} +Each job is durably persisted before any Worker sees it, so jobs aren't lost. +Workers pull work from a [Task Queue](/task-queue) and there's no head-of-line blocking, so a slow job doesn't block the dispatch of other Tasks. +See [Activity Execution Lifecycle](/activity-execution#activity-execution-lifecycle). + +### Retries and timeouts {/* #retries-and-timeouts */} + +Every job carries a [Retry Policy](/encyclopedia/retry-policies) and +[timeouts](/encyclopedia/detecting-activity-failures) you set when you start it. The default is at-least-once: retry +with exponential backoff until the job succeeds or its Schedule-To-Close Timeout elapses. Set Maximum Attempts to 1 for +at-most-once. + +Because a retry runs your function again, Activity code should be +[idempotent](/activity-definition#idempotency). + +### Long-running jobs and Heartbeats {/* #heartbeats */} + +Jobs can run for any duration. [Heartbeat](/encyclopedia/detecting-activity-failures#activity-heartbeat) to signal +liveness and to checkpoint progress. + +A retry restarts your Activity function from the top - it doesn't resume mid-function. The last recorded Heartbeat +details are made available to the next attempt, so your code can read the checkpoint and skip the work it already +finished. + +### Deduplicate with the Activity Id {/* #deduplication */} + +Use a business identifier you already have as the Activity Id, and Temporal enforces uniqueness for you: an +[Activity Id Conflict Policy](#activity-id-conflict-policy) covers a job that's already running, and an +[Activity Id Reuse Policy](#activity-id-reuse-policy) covers one that already completed. + +This is a different problem from idempotency, and you need both. The Activity Id stops you submitting the same job +twice. Idempotent code stops one job's side effects happening twice if retried. + +### Priority and fairness {/* #priority-and-fairness */} + +[Priority](/develop/task-queue-priority-fairness#task-queue-priority) is strict: higher-priority Tasks dispatch before +lower-priority ones. [Fairness](/develop/task-queue-priority-fairness#task-queue-fairness) prevents starvation: each +fairness key gets its own virtual queue and dispatch cycles round-robin across keys, so one tenant's backlog doesn't +starve everyone else. + +On Temporal Cloud, enabling Fairness carries a [per-Action surcharge](/cloud/actions#fairness). + +### Schedule a job for later {/* #start-delay */} + +Start Delay dispatches the first Activity Task after a delay instead of immediately. Use it for work that shouldn't run +until later, such as a reminder email or a deferred cleanup step. + +```bash +temporal activity start \ + --activity-id my-activity \ + --type MyActivity \ + --task-queue my-task-queue \ + --start-to-close-timeout 5m \ + --start-delay 1h +``` + +The delay applies to the first Activity Task only. Retry attempts are dispatched according to the +[Retry Policy](/encyclopedia/retry-policies), not the delay. + +Start Delay schedules one job at a future time. It doesn't create a recurring schedule. + +### Visibility {/* #visibility */} + +Query jobs with [List Filter](/list-filter) by type, status, Task Queue, and other attributes, from the SDK or with +`temporal activity list`. See [Search Attributes](/search-attribute) for the attributes set on Standalone Activity +Executions, and add your own to filter on your business data. + +`temporal activity list` shows a list of jobs optionally matching a [List Filter](/list-filter). + +``` +./temporal activity list --query "ExecutionStatus='Running'" + Status ActivityId Type StartTime + Running process_files-1786633958 process_files 1 week ago +``` + +`temporal activity count` returns the total number of Standalone Activity Executions optionally matching a [List Filters](/list-filter), analogous to counting Workflow Executions. + +``` +./temporal activity count --query "GROUP BY ExecutionStatus" +Total: 45 +Group total: 30, values: Completed +Group total: 10, values: Canceled +Group total: 4, values: Terminated +Group total: 1, values: Running +``` + +This is the count of Activity Executions (Completed, Running, Failed, etc.) - not the number of queued tasks. + +`temporal activity describe` shows one job's status, attempt count, and last error. + +``` +./temporal activity describe -a process_files-1786633958 +Activity Execution Info: + ActivityId process_files-1786633958 + RunId 01a06322-99ac-7972-8829-65352fc5d158 + Type process_files + Status Running + RunState Scheduled + TaskQueue demo-task-queue + StartToCloseTimeout 24h0m0s + Attempt 1 + ScheduleTime 1 week ago + StateTransitionCount 3 +``` + +### Observability {/* #observability */} All existing [Activity metrics](/cloud/metrics/openmetrics/metrics-reference#activity-metrics) apply to Standalone Activities. This includes counts for scheduled, started, completed, failed, timed out, and canceled activities. -You can use [List Filters](/list-filter) to query Standalone Activity Executions by type, status, -task queue, and other attributes using the SDK or the `temporal activity list` CLI command. -`CountActivities` returns the total number of Standalone Activity Executions matching a filter, -analogous to counting Workflow Executions. This is the total count of executions (running, completed, -failed, etc.) - not the number of queued tasks. +### Lifecycle control {/* #lifecycle-control */} + +Because a Standalone Activity has no Workflow to own it, you act on the execution directly by Activity Id: + +- **Request Cancel** asks the execution to close gracefully, letting your code clean up. See + [Cancellation](/activity-execution#cancellation). +- **Terminate** forcefully closes the execution, with no opportunity for your code to clean up. +- **Delete** terminates the execution if it's running, then deletes it asynchronously. + +Activities must [Heartbeat](/encyclopedia/detecting-activity-failures#activity-heartbeat) to receive Cancellation, so +interrupting an already-running attempt is cooperative: Temporal can accept a Cancel request without the Worker +honoring it. If the Worker is unresponsive, the request takes effect at the next attempt boundary, for example when the +[Start-To-Close Timeout](/encyclopedia/detecting-activity-failures#start-to-close-timeout) elapses. + +Only Terminate and Delete discard Activity progress unconditionally. + +### Operator commands {/* #operator-commands */} + +Pause, Unpause, Reset, and Update Options let an operator intervene in a running job from the CLI, the UI, or the gRPC +API. + +These commands are in +[Public Preview](/evaluate/development-production-features/release-stages#public-preview). Request Cancel, Terminate, +and Delete are Generally Available. + +See [Activity Operations](/activity-operations) for behavior, precedence, and batch support. + +### Asynchronous completion {/* #asynchronous-completion */} + +A Standalone Activity can return from its function without completing the Activity Execution, leaving an external +system to Heartbeat progress and deliver the final result by Activity Id or Task Token. See +[Asynchronous Activity Completion](/activity-execution#asynchronous-activity-completion). + +### Reuse Activities for jobs and Workflows {/* #dual-use */} -## Public Preview limitations +You define the Activity and register it on an Activity Worker once. The same function runs as a Standalone Activity or +as a step in a Workflow, with no changes to your Activity code or your Worker. Start with background jobs, and add +Workflow orchestration later without a rewrite. -The Public Preview of Standalone Activities has some known limitations: +## Activity options {/* #activity-options */} -- Pause, reset, and update options are not supported in Public Preview but scheduled for GA. -- `TerminateExisting` conflict policy / `TerminateIfRunning` reuse policy is not supported yet. +You set Activity Options on the Client when you start the job. At minimum, specify a timeout - typically the +[Start-To-Close Timeout](/encyclopedia/detecting-activity-failures#start-to-close-timeout). + +| Option | What it controls | +| --- | --- | +| [Timeouts](/encyclopedia/detecting-activity-failures) | Schedule-To-Start, Start-To-Close, Schedule-To-Close, and Heartbeat | +| [Retry Policy](/encyclopedia/retry-policies) | Retry backoff and Maximum Attempts. Set Maximum Attempts to 1 for at-most-once | +| Task Queue | Which Workers get the job | +| Activity Id | The deduplication key, with its [Conflict](#activity-id-conflict-policy) and [Reuse](#activity-id-reuse-policy) policies | +| [Priority and fairness](/develop/task-queue-priority-fairness) | Dispatch order when jobs compete for the same Workers | +| [Start Delay](#start-delay) | Run the job after a start delay | + +:::tip GET STARTED + +Get results, get handles, and list Standalone Activities: +[Go](/develop/go/activities/standalone-activities) +| [Java](/develop/java/activities/standalone-activities) +| [Python](/develop/python/activities/standalone-activities) +| [TypeScript](/develop/typescript/activities/standalone-activities) +| [.NET](/develop/dotnet/activities/standalone-activities) +| [Ruby](/develop/ruby/activities/standalone-activities) + +::: + +## Activity Id and deduplication {/* #deduplication-and-id-space-uniqueness */} + +Standalone Activities have a separate Id space from [the Workflow Id space](/workflow-execution/workflowid-runid) and +other Temporal primitives, so the [Activity Id Conflict Policy](#activity-id-conflict-policy) and the +[Activity Id Reuse Policy](#activity-id-reuse-policy) observe only the Standalone Activity Id space for deduplication +and uniqueness. + +### What is an Activity Id Reuse Policy? {/* #activity-id-reuse-policy */} + +An Activity Id Reuse Policy determines whether a [Standalone Activity](/standalone-activity) Execution can start with an +Activity Id that a previous, and now closed, Standalone Activity Execution used. If the request is denied, the Temporal +Service returns an `ActivityExecutionAlreadyStarted` error. + +See [Activity Id Conflict Policy](#activity-id-conflict-policy) for resolving a conflict with a running Standalone +Activity Execution. + +The Activity Id Reuse Policy can have one of the following values: + +- **Allow Duplicate:** The Standalone Activity Execution can start regardless of the closed status of a previous + Standalone Activity Execution with the same Activity Id. + **This is the default policy, if one isn't specified.** +- **Allow Duplicate Failed Only:** The Standalone Activity Execution can start only if the previous Standalone Activity + Execution with the same Activity Id failed, was canceled, was terminated, or timed out. +- **Reject Duplicate:** The Standalone Activity Execution can't start if a previous Standalone Activity Execution has + the same Activity Id, regardless of its closed status. + +These values apply to closed Standalone Activity Executions that are still retained in the Namespace, so the check +reaches back only as far as the [retention period](#result-retention). + +### What is an Activity Id Conflict Policy? {/* #activity-id-conflict-policy */} + +An Activity Id Conflict Policy determines what happens when you start a Standalone Activity with an Activity Id that a +running Standalone Activity Execution already uses. Two Standalone Activity Executions never run at the same time with +the same Activity Id. + +See [Activity Id Reuse Policy](#activity-id-reuse-policy) for reusing the Activity Id of a closed Standalone Activity +Execution. + +The Activity Id Conflict Policy can have one of the following values: + +- **Fail:** Doesn't start a new Standalone Activity Execution and returns an `ActivityExecutionAlreadyStarted` error. + **This is the default policy, if one isn't specified.** +- **Use Existing:** Doesn't start a new Standalone Activity Execution and returns a handle to the running one. + +## Result retention {/* #result-retention */} + +A Standalone Activity Execution and its result are retained for the +[Retention Period](/temporal-service/temporal-server#retention-period) of the Namespace it ran in, the same as other +closed Executions. Within that window the Execution stays visible to `temporal activity describe` and +`temporal activity list`. After the Retention Period elapses, the Execution and its result are deleted and the +Activity Id becomes available for reuse. + +Retention is also what enforces deduplication: the [Reuse Policy](#activity-id-reuse-policy) checks against the retained +record of a completed job, so a job older than the Retention Period no longer blocks reuse of its Activity Id. + +To remove an Execution before then, use `temporal activity delete`. + +## Worker configuration {/* #worker-configuration */} + +An Activity Worker's default poller count is lower than the concurrency many job queue frameworks use, and some of them +prefetch several tasks per poll. If you're moving existing work to Standalone Activities and comparing throughput, +match the poller count to your previous system before you measure. Otherwise the comparison reflects poller +configuration rather than the platform. + +See [Worker performance](/develop/worker-performance/configuration#configuring-poller-options) for poller autoscaling +and the manual settings. + +For long-running Activities, start the Activity and hold the handle rather than blocking on the result, so a Worker +slot and poller aren't held for the duration. + +## Serverless Workers {/* #serverless-workers */} + +Job queue load is bursty, so Activity Workers often sit idle between jobs. With +[Serverless Workers](/serverless-workers), Temporal starts the Worker instead: when a job arrives and no Worker is +available to take it, Temporal invokes your configured compute provider, the Worker polls the Task Queue, processes the +job, and scales back down. + +Your Activity code and Worker registration are unchanged. The Worker must belong to a +[Worker Deployment Version](/worker-versioning#deployment-versions) with a compute provider configured, which is how +Temporal knows what to invoke. + +AWS Lambda support is in [Public Preview](/evaluate/development-production-features/release-stages#public-preview) and +GCP Cloud Run is in [Pre-release](/evaluate/development-production-features/release-stages#pre-release). See +[Deploy a Serverless Worker](/production-deployment/worker-deployments/serverless-workers). + +## Standalone Activity versus Workflow Activity + +A Standalone Activity follows the same execution semantics as an Activity in a Workflow: it's queued, retried until it +succeeds or its Schedule-To-Close Timeout elapses, and it requires idempotent Activity code. What differs is that it's +orchestrated by its own state machine, so there's no Workflow [Event History](/workflow-execution/event#event-history) +and no deterministic replay. + +
+ +
+ +Both are durable [Activity Executions](/activity-execution) that use the same Activity Execution +lifecycle. The [Activity Definition](/activity-definition) and Worker registration are identical, so +the same Activity function can run either way with no code changes. What differs is who starts it +and what owns its lifetime. + +Running a single Activity as a Standalone Activity also costs fewer [Billable Actions](/cloud/actions-usage#actions-in-workflows) in +Temporal Cloud than wrapping it in a Workflow, and short jobs see lower latency because there are fewer Worker +round-trips. See [cost optimization](/best-practices/cost-optimization#standalone-activities-vs-a-workflow-that-runs-a-single-activity) for details. + + +## Feature release stages {/* #feature-release-stages */} + +Standalone Activities are Generally Available, including Start Delay, Request Cancel, Terminate, and Delete. + +These capabilities are in +[Public Preview](/evaluate/development-production-features/release-stages#public-preview): + +- [Operator commands](/activity-operations): Pause, Unpause, Reset, and Update Options. +- Batch operations by [List Filter](/list-filter): Request Cancel, Terminate, and Delete. + +## Limitations {/* #limitations */} + +The following features are not yet supported: + +- `TerminateExisting` conflict policy. Use `Fail` or `UseExisting` instead. +- Starting from a recurring [Schedule](/schedule). For a one-time job at a future time, use + [Start Delay](#start-delay). For recurring work, schedule a Workflow that invokes the Activity, which runs it as a + [Workflow Activity](/workflow-activity) rather than a Standalone Activity. +- Starting from [Temporal Nexus](/evaluate/nexus). +- Batch Reset, Pause, Unpause, Update Options, Complete, and Fail. +- Export for Standalone Activities similar to [Workflow Export](/cloud/export). ## Temporal CLI support -Standalone Activities require [Temporal CLI](https://github.com/temporalio/cli/releases/tag/v1.7.0) v1.7.0 or higher and [Temporal Server](https://github.com/temporalio/temporal/releases/tag/v1.31.0) v1.31.0 or higher. +Standalone Activities require [Temporal CLI](https://github.com/temporalio/cli/releases) v1.9.0 or higher and [Temporal Server](https://github.com/temporalio/temporal/releases) v1.32.0 or higher. Install with Homebrew: @@ -120,16 +383,30 @@ Verify the installation: temporal --version ``` -Which should output v1.7.0 or higher, for example: +Which should output v1.9.0 or higher, for example: ``` -temporal version 1.7.0 (Server 1.31.0, UI 2.49.1) +temporal version 1.9.0 (Server 1.32.0, UI 2.53.3) ``` -The `temporal activity` subcommand supports Standalone Activities with commands including: `start`, -`execute`, `result`, `list`, `count`, `describe`, `cancel`, and `terminate`. - -The Temporal Dev Server has Standalone Activities enabled by default for local testing. +The `temporal activity` subcommand supports Standalone Activities with `start`, `execute`, `result`, `list`, `count`, +`describe`, `cancel`, `terminate`, and `delete`. It also supports the Public Preview operator commands `pause`, +`unpause`, `reset`, and `update-options`. See [Activity Operations](/activity-operations). ## Temporal Cloud support -Standalone Activities in Temporal Cloud is available as a Public Preview feature. +Standalone Activities are Generally Available in Temporal Cloud, in all [regions](/cloud/regions). + +Service Level Objectives and the Service Level Agreement match those for Workflows. See +[Service availability](/cloud/service-availability) and [SLA](/cloud/sla). + +:::tip RESOURCES + +- Try it end to end with the [Standalone Activities demo](/demos/standalone-activities). +- Build a job queue with priority and fairness: + [Go](https://learn.temporal.io/tutorials/go/standalone-activities/), + [Java](https://learn.temporal.io/tutorials/java/standalone-activities/), + [Python](https://learn.temporal.io/tutorials/python/standalone-activities/), + [TypeScript](https://learn.temporal.io/tutorials/typescript/standalone-activities/). +- Add orchestration when you need it: see [Workflow Activity](/workflow-activity). + +::: diff --git a/docs/encyclopedia/activities/workflow-activity.mdx b/docs/encyclopedia/activities/workflow-activity.mdx new file mode 100644 index 0000000000..de1e22d6e1 --- /dev/null +++ b/docs/encyclopedia/activities/workflow-activity.mdx @@ -0,0 +1,110 @@ +--- +id: workflow-activity +title: Workflow Activity +description: Learn about Activities started as a step in a Workflow, scoped to that Workflow's lifetime and recorded in Workflow Event History. +slug: /workflow-activity +toc_max_heading_level: 4 +tags: + - Concepts + - Activities + - Durable Execution +--- + +## What is a Workflow Activity? {/* #workflow-activity */} + +A Workflow Activity is an [Activity Execution](/activity-execution) started as a step in a +[Workflow](/workflows), using the Temporal SDK from your Workflow code. + +The Workflow schedules the Activity, the Temporal Service dispatches an Activity Task to an Activity +Worker polling the Activity's Task Queue, and the result is delivered back to the Workflow when the +Activity Execution closes. Each step is recorded in the Workflow Execution's +[Event History](/workflow-execution/event#event-history). + +Use a Workflow Activity when you need to orchestrate multiple steps: sequencing, branching on a +result, compensating a failure, waiting on a Signal or Timer between steps. If you just need to +execute a single Activity, use a [Standalone Activity](/standalone-activity) instead. + +:::tip GET STARTED + +Start a Workflow Activity: +[Go](/develop/go/activities/execution) +| [Java](/develop/java/activities/execution) +| [PHP](/develop/php/activities/execution) +| [Python](/develop/python/activities/execution) +| [TypeScript](/develop/typescript/activities/execution) +| [.NET](/develop/dotnet/activities/execution) +| [Ruby](/develop/ruby/activities/execution) +| [Rust](/develop/rust/activities/execution) + +::: + +## Activity options {/* #activity-options */} + +You set Activity Options in your Workflow code when you schedule the Activity. At minimum, specify a +timeout - typically the [Start-To-Close Timeout](/encyclopedia/detecting-activity-failures#start-to-close-timeout). + +- [Timeouts](/encyclopedia/detecting-activity-failures): Schedule-To-Start, Start-To-Close, + Schedule-To-Close, and Heartbeat. +- [Retry Policy](/encyclopedia/retry-policies): Activities retry automatically by default, with + exponential backoff and unlimited Maximum Attempts. +- Task Queue: routes the Activity Task to the Workers that should run it. It doesn't have to be the + Workflow's Task Queue. + +:::tip GET STARTED + +Set Activity timeouts and Heartbeats: +[Go](/develop/go/activities/timeouts) +| [Java](/develop/java/activities/timeouts) +| [PHP](/develop/php/activities/timeouts) +| [Python](/develop/python/activities/timeouts) +| [TypeScript](/develop/typescript/activities/timeouts) +| [.NET](/develop/dotnet/activities/timeouts) +| [Ruby](/develop/ruby/activities/timeouts) +| [Rust](/develop/rust/activities/timeouts) + +::: + +## Event History {/* #event-history */} + +A Workflow Activity writes [Activity Events](/workflow-execution/event#activity-events) to the +Workflow Execution's Event History, such as +[ActivityTaskScheduled](/references/events#activitytaskscheduled), +[ActivityTaskStarted](/references/events#activitytaskstarted), and +[ActivityTaskCompleted](/references/events#activitytaskcompleted). + +Two consequences follow: + +- **Replay uses the recorded result.** A completed Activity isn't executed again when the Workflow + [replays](/workflow-execution#replay). +- **Arguments and return values are persisted.** They count toward + [Event History limits](/workflow-execution/event#event-history-limits), so be mindful of payload + size and of how many Activities a single Workflow Execution schedules. + +## Activity Id {/* #activity-id */} + +A Workflow Activity's [Activity Id](/activity-execution#activity-id) is unique among the open +Activity Executions of a [Workflow Run](/workflow-execution/workflowid-runid#run-id). A Workflow Run +may reuse an Activity Id once an earlier Activity Execution with that Id has closed. + +## Cancellation {/* #cancellation */} + +A Workflow Activity can't be canceled directly. It receives a +[Cancellation](/activity-execution#cancellation) request as a result of its Workflow being canceled, +or because the Workflow code requested it. Activities must +[Heartbeat](/encyclopedia/detecting-activity-failures#activity-heartbeat) to receive Cancellation. + +The Workflow decides whether to wait for the Cancellation to be accepted or to proceed without +waiting. + +## Asynchronous completion {/* #asynchronous-completion */} + +A Workflow Activity can return from its function without completing the Activity Execution, leaving +an external system to Heartbeat progress and deliver the final result. See +[Asynchronous Activity Completion](/activity-execution#asynchronous-activity-completion). + +## Operator commands {/* #operator-commands */} + +Pause, Unpause, Reset and Update Options let an operator intervene in a running Workflow Activity. +These commands are in [Public Preview](/evaluate/development-production-features/release-stages#public-preview). + +See [Activity Operations](/activity-operations) for details. diff --git a/docs/encyclopedia/detecting-activity-failures.mdx b/docs/encyclopedia/detecting-activity-failures.mdx index c8e2b5b5ba..466bc5cf5c 100644 --- a/docs/encyclopedia/detecting-activity-failures.mdx +++ b/docs/encyclopedia/detecting-activity-failures.mdx @@ -274,3 +274,11 @@ A Heartbeat Timeout is the maximum time between [Activity Heartbeats](#activity- title="Heartbeat Timeout periods" /> If this timeout is reached, the Activity Task fails and a retry occurs if a [Retry Policy](/encyclopedia/retry-policies) dictates it. + +#### What a Heartbeat Timeout of `0s` means {/* #heartbeat-timeout-zero */} + +`0s` means the Heartbeat Timeout is disabled. No Heartbeat timer is started, so the Activity never fails for missing a Heartbeat. It does not mean an unbounded timeout, and it does not mean the Activity times out immediately. + +`0s` is also the normalized value the Temporal Service stores when you leave the Heartbeat Timeout unset. An unset Heartbeat Timeout and an explicit `0s` are therefore indistinguishable once the Activity is scheduled: both are reported as `0s` and both behave as disabled. + +The Heartbeat Timeout is also capped at the [Start-To-Close Timeout](#start-to-close-timeout). Setting a Heartbeat Timeout longer than the Start-To-Close Timeout stores the Start-To-Close Timeout instead. diff --git a/docs/encyclopedia/visibility/list-filter.mdx b/docs/encyclopedia/visibility/list-filter.mdx index 8f80105ad7..fa4b6d617d 100644 --- a/docs/encyclopedia/visibility/list-filter.mdx +++ b/docs/encyclopedia/visibility/list-filter.mdx @@ -216,6 +216,40 @@ ExecutionTime < '2021-08-28T15:04:05+00:00' or ExecutionTime > '2021-08-22T15:04 WorkflowType STARTS_WITH '' ``` +#### Standalone Activity Execution List Filter examples + +[Standalone Activity Executions](/standalone-activity) use the same List Filter syntax over their own Search Attributes. +Pass these to `ListActivities` and `CountActivities`, or to [`temporal activity list`](/cli/command-reference/activity#list) and [`temporal activity count`](/cli/command-reference/activity#count). +These APIs return Standalone Activity Executions only; Activities that run inside a Workflow are not included. + +Find every running Standalone Activity of one Activity Type: + +```sql +ActivityType = '' and ExecutionStatus = 'Running' +``` + +Find the Standalone Activities an operator has [paused](/activity-operations): + +```sql +ExecutionStatus = 'Paused' +``` + +```sql +ExecutionStatus = 'Paused' and ActivityType = '' +``` + +Find delayed jobs, meaning Standalone Activities whose first Activity Task has not been dispatched yet because of a [Start Delay](/standalone-activity#start-delay): + +```sql +ExecutionStatus = 'Running' and ExecutionTime > '2021-08-22T15:04:05+00:00' +``` + +Find one Standalone Activity by its business identifier: + +```sql +ActivityId = '' +``` + ### Search Attribute aliasing Temporal prefixes most [default Search Attributes](./search-attributes.mdx#default-search-attribute) with `Temporal` to avoid naming conflicts with custom Search Attributes. diff --git a/docs/encyclopedia/visibility/search-attributes.mdx b/docs/encyclopedia/visibility/search-attributes.mdx index 416a02a15f..5172891ee8 100644 --- a/docs/encyclopedia/visibility/search-attributes.mdx +++ b/docs/encyclopedia/visibility/search-attributes.mdx @@ -72,8 +72,8 @@ These Search Attributes are created when the initial index is created. | ~BuildIds~ | ~Keyword List~ | List of Worker Build Ids that have processed the Workflow Execution, formatted as `versioned:{BuildId}` or `unversioned:{BuildId}`, or the sentinel `unversioned` value. Deprecated since server version 1.31 in favor of the `TemporalUsedWorkerDeploymentVersions` search attribute. | | CloseTime | Datetime | The time at which the Workflow Execution completed. | | ExecutionDuration | Int | The time needed to run the Workflow Execution (in nanoseconds). Available only for closed Workflows. | -| ExecutionStatus | Keyword | The current state of the Workflow Execution. | -| ExecutionTime | Datetime | The time at which the Workflow Execution actually begins running; same as `StartTime` for most cases but different for Cron Workflows and retried Workflows. | +| ExecutionStatus | Keyword | The current state of the Workflow Execution. Also set on [Standalone Activity Executions](/standalone-activity), where it holds the Activity Execution status. | +| ExecutionTime | Datetime | The time at which the Execution actually begins running; same as `StartTime` for most cases but different for Cron Workflows and retried Workflows. Also set on [Standalone Activity Executions](/standalone-activity), where a [Start Delay](/standalone-activity#start-delay) pushes it past `StartTime`, making it the attribute to query for delayed jobs. | | HistoryLength | Int | The number of events in the history of Workflow Execution. Available only for closed Workflows. | | HistorySizeBytes | Long | The size of the Event History. | | RunId | Keyword | Identifies the current Workflow Execution Run. | @@ -101,7 +101,10 @@ These Search Attributes are created when the initial index is created. - To use default Search Attributes with the `Temporal` prefix in a List Filter, you can use their non-prefixed alias. Refer to [Search Attribute aliasing](./list-filter.mdx#search-attribute-aliasing) for details. -- ExecutionStatus values correspond to Workflow Execution statuses: Running, Completed, Failed, Canceled, Terminated, ContinuedAsNew, TimedOut. +- On a Workflow Execution, ExecutionStatus values correspond to Workflow Execution statuses: Running, Completed, Failed, Canceled, Terminated, ContinuedAsNew, TimedOut. + +- On a [Standalone Activity Execution](/standalone-activity), ExecutionStatus values correspond to Activity Execution statuses: Running, Completed, Failed, Canceled, Terminated, TimedOut, Paused. + `Paused` is the status of an Activity that an operator has paused with [Pause](/activity-operations). Query it with `ExecutionStatus = 'Paused'`. - StartTime, CloseTime, and ExecutionTime are stored as dates but are supported by queries that use either EpochTime in nanoseconds or a string in [RFC3339Nano format](https://pkg.go.dev/time#pkg-constants) (such as "2006-01-02T15:04:05.999999999Z07:00"). @@ -244,6 +247,26 @@ This is configurable with [`SearchAttributesNumberOfKeysLimit`, `SearchAttribute For Temporal Cloud specific configurations, see the [Defaults, limits, and configurable settings -Temporal Cloud](/cloud/limits#number-of-custom-search-attributes) guide. +### Search Attributes on Standalone Activity Executions {/* #standalone-activity-search-attributes */} + +[Standalone Activity Executions](/standalone-activity) have their own Visibility records, separate from Workflow Executions. +`ListActivities` and `CountActivities` (and `temporal activity list` and `temporal activity count`) return Standalone Activity Executions only. +Activities that run inside a Workflow are not returned by them, and they have no Visibility record of their own; find them through their Workflow Execution. + +The Temporal Service sets the following Search Attributes on every Standalone Activity Execution: + +| Name | Type | Definition | +|------|------|------------| +| ActivityId | Keyword | The business identifier of the Standalone Activity Execution. | +| ActivityType | Keyword | The Activity Type name. | +| ExecutionStatus | Keyword | The current state of the Standalone Activity Execution: Running, Completed, Failed, Canceled, Terminated, TimedOut, or Paused. | +| ExecutionTime | Datetime | The time at which the first Activity Task is dispatched. A [Start Delay](/standalone-activity#start-delay) pushes this past the time the Activity was started. | +| TaskQueue | Keyword | Task Queue the Standalone Activity Execution is dispatched on. | + +Custom Search Attributes also apply. Set them when you start the Standalone Activity, then filter on them the same way you would for a Workflow Execution. + +Search Attributes that describe Workflow structure or Event History, such as `WorkflowType`, `HistoryLength`, `HistorySizeBytes`, `ParentWorkflowId`, and `RootWorkflowId`, apply to Workflow Executions and are not set on Standalone Activity Executions. + ### Usage {/* #usage */} Search Attributes available in your Visibility store can be used with Workflow Executions for the Temporal Service. diff --git a/docs/evaluate/development-production-features/job-queue.mdx b/docs/evaluate/development-production-features/job-queue.mdx index 2d79cd6592..3d5768b9f0 100644 --- a/docs/evaluate/development-production-features/job-queue.mdx +++ b/docs/evaluate/development-production-features/job-queue.mdx @@ -3,8 +3,7 @@ id: job-queue title: Job Queue description: Standalone Activities adds the ability to execute any Temporal Activity as a top-level primitive without the full overhead of a Workflow. tags: - - Features - - Standalone Activities + - Job Queue --- import { RelatedReadContainer, RelatedReadItem } from '@site/src/components'; @@ -45,7 +44,8 @@ Standalone Activities add the ability to execute any Temporal Activity as a top- - Full job visibility (list, search) with detailed execution state, retry count, errors & results - OpenMetrics support -- Lifecycle controls: cancel, pause, unpause, reset, terminate +- Lifecycle controls: cancel, pause, unpause, reset, terminate, delete +- Batch operations: cancel, terminate, delete - Manual completion for external integrations & on-call management ## Next steps @@ -57,5 +57,6 @@ Learn more about [Standalone Activity concepts, features, and limitations](/stan - [.NET SDK - Standalone Activities quickstart and code sample](/develop/dotnet/activities/standalone-activities-quickstart) - [Java SDK - Standalone Activities quickstart and code sample](/develop/java/activities/standalone-activities-quickstart) - [TypeScript SDK - Standalone Activities quickstart and code sample](/develop/typescript/activities/standalone-activities-quickstart) +- [Ruby SDK - Standalone Activities quickstart and code sample](/develop/ruby/activities/standalone-activities-quickstart) To build a job queue end to end, follow the Build a Job Queue with Standalone Activities tutorial in [Go](https://learn.temporal.io/tutorials/go/standalone-activities/), [Java](https://learn.temporal.io/tutorials/java/standalone-activities/), [Python](https://learn.temporal.io/tutorials/python/standalone-activities/), or [TypeScript](https://learn.temporal.io/tutorials/typescript/standalone-activities/). It covers idempotency keys, server-side deduplication, throughput limits, [Priority and Fairness](/develop/task-queue-priority-fairness), heartbeat checkpoints, and reusing the same Activity inside a Workflow. diff --git a/docs/evaluate/temporal-cloud/actions.mdx b/docs/evaluate/temporal-cloud/actions.mdx index 73775761b5..4efa47823c 100644 --- a/docs/evaluate/temporal-cloud/actions.mdx +++ b/docs/evaluate/temporal-cloud/actions.mdx @@ -99,11 +99,12 @@ available endpoints are listed in the following sections: ## Activity {/* #activity */} -- **Activity started or retried**. Occurs each time an Activity is started or retried. -- **Standalone Activity started**. Occurs when a [Standalone Activity](/standalone-activity) is started. +- **Activity started or retried**. Occurs each time a [**Workflow Activity**](/workflow-activity) or [**Standalone Activity**](/standalone-activity) is started or retried. - De-duplicated Standalone Activity starts that return an already-running Activity (sharing an Activity Id) do _not_ - count as an Action, unless the start request tries to attach a callback to the running Activity — for example, + count as an Action, unless the start request performs an Activity options update, like attaching a callback to the running Activity — for example, within a Nexus handler using the `USE_EXISTING` conflict policy. +- **Standalone Activity pause, reset, and update options**. Each count as one Action. Unpause does _not_ count as an Action. + See [Activity Operations](/activity-operations). - **Local Activity started**. All [Local Activities](/local-activity) associated with one Workflow Task count as a single Action. Temporal Cloud counts all [RecordMarkers](/references/commands#recordmarker) from each Workflow Task as one action, and not _N_ actions. Note: diff --git a/docs/evaluate/temporal-cloud/service-availability.mdx b/docs/evaluate/temporal-cloud/service-availability.mdx index 00599d030e..1efff8eda4 100644 --- a/docs/evaluate/temporal-cloud/service-availability.mdx +++ b/docs/evaluate/temporal-cloud/service-availability.mdx @@ -33,7 +33,8 @@ The same SLO for normal Worker requests (commands and polling) apply to Nexus in ### Historical latency data -Latency over a week-long period for starting and signaling Workflow Executions was as follows: +Latency over a week-long period for starting and signaling Workflow Executions, and for starting [Standalone Activities](/standalone-activity) (`StartActivityExecution`), +was as follows: #### August 2026 @@ -42,6 +43,7 @@ Latency over a week-long period for starting and signaling Workflow Executions w | `StartWorkflowExecution` | 20ms | 32ms | 78ms | | `SignalWorkflowExecution` | 19ms | 42ms | 91ms | | `SignalWithStartWorkflowExecution` | 30ms | 47ms | 109ms | +| `StartActivityExecution` | 13ms | 19ms | 45ms | #### January 2026 diff --git a/docs/glossary.md b/docs/glossary.md index 5e3913d684..4bfd7a66e7 100644 --- a/docs/glossary.md +++ b/docs/glossary.md @@ -593,6 +593,14 @@ Signal-With-Start starts and Signals a Workflow Execution, or just Signals it if +#### [Standalone Activity](/standalone-activity) + +A Standalone Activity is an Activity Execution invoked outside of a Workflow, directly from a Temporal Client. It has a +separate Id space from Workflows and other Temporal primitives. Existing Activity Functions can be invoked as +Standalone with no code changes. + + + #### [Start-To-Close Timeout](/encyclopedia/detecting-activity-failures#start-to-close-timeout) A Start-To-Close Timeout is the maximum time allowed for a single Activity Task Execution. @@ -817,6 +825,14 @@ An in-memory cache on a Worker that holds the state of Workflow Executions it ha +#### [Workflow Activity](/workflow-activity) + +A Workflow Activity is an Activity Execution orchestrated by a Workflow. Its results are persisted to the Workflow and +Events are added to the Workflow Execution's Event History. Contrast with +[Standalone Activity](/standalone-activity) and [Local Activity](/local-activity). + + + #### [Workflow Definition](/workflow-definition) A Workflow Definition is the code that defines the constraints of a Workflow Execution. diff --git a/docs/guides/celery-to-standalone-activity.mdx b/docs/guides/celery-to-standalone-activity.mdx index 79f9d6149d..0498fc28e6 100644 --- a/docs/guides/celery-to-standalone-activity.mdx +++ b/docs/guides/celery-to-standalone-activity.mdx @@ -1,27 +1,19 @@ --- id: celery-to-standalone-activity title: Migrate a Celery task queue to a Temporal Standalone Activity -description: Migrate Celery tasks to a Temporal Standalone Activity. +description: Migrate Celery tasks to a Temporal Standalone Activity, for durable job processing with full visibility and lifecycle control. sidebar_label: Migrate from Celery toc_max_heading_level: 3 author: n/a tags: - Migration - - Celery - - Standalone Activities - - Python + - Job Queue - Workers --- -import { ReleaseNoteHeader } from '@site/src/components'; - - - [Celery](https://docs.celeryq.dev/en/stable/) is a distributed task queue that runs background jobs by pushing messages through a broker (such as Redis or RabbitMQ) to a pool of worker processes. Most Celery tasks are self-contained: send one email, resize one image, call one API. For that kind of single-step job, you want Durable Execution and automatic retries without having to stand up an orchestration layer around each task. -[**Standalone Activities**](/standalone-activity) fit that need. A Standalone Activity is an Activity you start directly from a Temporal Client, without wrapping it in a Workflow. You get Temporal's durability, retries, timeouts, and visibility for an individual unit of work, which maps almost one-to-one onto a Celery task. Because there is no Workflow to run a single Activity, Standalone Activities also use fewer resources than orchestrating one Activity through a Workflow. +[**Standalone Activities**](/standalone-activity) are Temporal's [job queue](/evaluate/development-production-features/job-queue). A Standalone Activity is an Activity you start directly from a Temporal Client, without wrapping it in a Workflow. You get Temporal's durability, retries, timeouts, and visibility for an individual unit of work, which maps almost one-to-one onto a Celery task. Because there is no Workflow to run a single Activity, Standalone Activities also use fewer resources than orchestrating one Activity through a Workflow. In this guide, you will migrate a Celery task to a Temporal Standalone Activity. You will convert the task into an Activity, run a Worker to process it, execute it both synchronously and fire-and-forget in place of your `.get()` and `.delay()` calls, migrate its retries to a Retry Policy, and inspect running Activities in place of Flower. By the end, you will have a working Temporal Application that reproduces the behavior of your Celery app with no Workflow code. @@ -38,15 +30,18 @@ Before you start, it helps to know which Temporal building block replaces each C | `AsyncResult.get()` | `client.execute_activity(...)` or `handle.result()` | Retrieve the return value | | `max_retries` / `self.retry()` | `RetryPolicy` | Automatic retries | | Flower / `celery inspect` | `client.list_activities()` / `client.count_activities()` | Monitor jobs | +| `countdown` / `eta` | Start Delay | Run a job later instead of immediately | +| `task_routes` priority queues | [Task Queue Priority and Fairness](/develop/task-queue-priority-fairness) | Control dispatch order under contention | +| `celery control` (`revoke`, rate limits) | [Activity Operations](/activity-operations) | Intervene in running jobs | ## Prerequisites Before you begin, you will need the following: - Python 3.9 or higher installed on your machine. -- Temporal Server v1.31.0 or higher (for Standalone Activities) +- Temporal Server v1.32.0 or higher (for Standalone Activities) - The Temporal Python SDK, version 1.23.0 or higher (installed in Step 2). -- The Temporal CLI, version 1.7.0 or higher (installed in Step 2). +- The Temporal CLI, version 1.9.0 or higher (installed in Step 2). - An existing Celery task you want to migrate, or the sample task shown in Step 4 if you are following along from scratch. ## Step 1: Set up your project directory @@ -82,7 +77,7 @@ Install the Temporal Python SDK (version 1.23.0 or higher) with `pip`: pip install "temporalio>=1.23.0" ``` -Next, install the Temporal CLI (version 1.7.0 or higher). On macOS or Linux with [Homebrew](https://brew.sh/), run: +Next, install the Temporal CLI (version 1.9.0 or higher). On macOS or Linux with [Homebrew](https://brew.sh/), run: ```bash brew install temporal @@ -90,13 +85,13 @@ brew install temporal If you aren't using Homebrew, download the binary for your platform from the [Temporal CLI install guide](/cli/setup-cli) and add it to your `PATH`. -Verify the CLI version, since Standalone Activities require 1.7.0 or higher: +Verify the CLI version, since Standalone Activities require 1.9.0 or higher: ```bash temporal --version ``` -Confirm the printed version is at least 1.7.0. With the tools installed, you can start a local Temporal Service. +Confirm the printed version is at least 1.9.0. With the tools installed, you can start a local Temporal Service. ## Step 3: Start the Temporal Development Server @@ -442,8 +437,14 @@ A rule of thumb: migrate a task to a Standalone Activity when it stands on its o In this tutorial, you migrated a Celery task to a Temporal Standalone Activity. You converted the task into an Activity, ran a Worker to execute it, invoked it both synchronously and fire-and-forget in place of your `.get()` and `.delay()` calls, replaced hand-written retries with a retry policy, and inspected your Activities in place of Flower — all without writing a single Workflow. Your jobs now survive Worker crashes, retry on well-defined policies, and remain queryable through the client and Web UI. -Because Standalone Activities are in Public Preview, review the [Standalone Activities feature guide](/develop/python/activities/standalone-activities) for the latest API details before relying on them in production. Useful next topics include: +Useful next topics: +- [Python SDK quickstart - Standalone Activities](/develop/python/activities/standalone-activities-quickstart) to get running on your machine. +- [Python SDK feature guide - Standalone Activities](/develop/python/activities/standalone-activities) for the full API surface. +- [Python SDK tutorial - Standalone Activities](https://learn.temporal.io/tutorials/python/standalone-activities/) to build a job queue with Standalone Activities. + +## Before you benchmark -- The [Standalone Activities Quickstart](/develop/python/activities/standalone-activities-quickstart) for the runnable reference sample. -- [Activity timeouts](/develop/python/activities/timeouts) for tuning `start_to_close` and related limits. -- The original [Celery documentation](https://docs.celeryq.dev/en/stable/) for confirming the exact behavior of the tasks you are migrating. +If you plan to compare throughput against your Celery deployment, match the Worker poller configuration first. Celery +prefetches several tasks per worker process by default (`worker_prefetch_multiplier`), while a Temporal Worker fetches +per poll. We recommend [poller autoscaling](/develop/worker-performance/configuration#configuring-poller-options) for +more efficient poller usage, better throughput, and schedule-to-start latency improvements. diff --git a/sidebars.js b/sidebars.js index ba42163641..19bb7bffa4 100644 --- a/sidebars.js +++ b/sidebars.js @@ -1970,10 +1970,21 @@ module.exports = { }, items: [ 'encyclopedia/activities/activity-definition', - 'encyclopedia/activities/activity-execution', + { + type: 'category', + label: 'Activity Execution', + collapsed: false, + link: { + type: 'doc', + id: 'encyclopedia/activities/activity-execution', + }, + items: [ + 'encyclopedia/activities/workflow-activity', + 'encyclopedia/activities/standalone-activity', + 'encyclopedia/activities/local-activity', + ], + }, 'encyclopedia/activities/activity-operations', - 'encyclopedia/activities/local-activity', - 'encyclopedia/activities/standalone-activity', ], }, { diff --git a/src/constants/featureReleaseTypes.js b/src/constants/featureReleaseTypes.js index e26d9ceac1..6519bcdf48 100644 --- a/src/constants/featureReleaseTypes.js +++ b/src/constants/featureReleaseTypes.js @@ -2,7 +2,6 @@ // ReleaseNoteHeader label resolution. Keep in sync when adding feature mappings. export const FEATURE_RELEASE_TYPES = { cloudCli: "publicPreview", - standaloneActivity: "publicPreview", standaloneNexusOperation: "prerelease", workflowStreams: "publicPreview", serverlessWorkersLambda: "publicPreview", diff --git a/static/diagrams/activity-definition.svg b/static/diagrams/activity-definition.svg deleted file mode 100644 index 77c2b25366..0000000000 --- a/static/diagrams/activity-definition.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/static/diagrams/idempotence-image.png b/static/diagrams/idempotence-image.png deleted file mode 100644 index 104a6f05ef..0000000000 Binary files a/static/diagrams/idempotence-image.png and /dev/null differ diff --git a/vale/styles/Temporal/Headings.yml b/vale/styles/Temporal/Headings.yml index a5af829bc7..1090b71582 100644 --- a/vale/styles/Temporal/Headings.yml +++ b/vale/styles/Temporal/Headings.yml @@ -33,6 +33,8 @@ exceptions: - QPS - RPS # Temporal primitives and proper nouns + - Action + - Actions - Activity - Activities - Application @@ -177,11 +179,24 @@ exceptions: - Continue-As-New - Plugin - Plugins + # Activity Operations named on the Activity Operations page — capitalized + # consistently as operation names throughout that page's headings and body + # prose, the same treatment already given to Signal/Query/Update above. + - Pause + - Unpause + - Reset + - Terminate + - Delete + - Paused # Exact phrases; "Audit Logging" is the canonical term in Temporal/terms.yml, # so keep "Log"/"Logs" out of the single-word list above. - Audit Log - Audit Logs - Audit Logging + # Exact phrases; the named Activity Operations, not generic bare words + # ("cancel" as a verb, "options" as in the unrelated "Activity options"). + - Request Cancel + - Update Options # Cloud provider / networking / industry acronyms - Amazon - AWS