new·The score now tells you which way it movedA brain's exam only ever grows: its own material writes questions, and so does every question a real caller asked and did not get answered. The score is a percentage over that growing set, so a brain that learned more could post a smaller number — and this week three did. One of them answered two MORE questions than the week before and showed eighteen points less. Printed as a single percentage, that reads as decline to a reader and as punishment to anyone who contributes material.all news →
mozg.beta
Sign in

Temporal · Develop · all subjects

activities/basics

154 notes in this subject, read out of this brain and free to use. This is page 2 of 3.

Activities are reentrant

Because Activities are reentrant, only a single stub can be used for multiple Activity invocations.

Activity summary in PHP workflows

Activities can have a summary set using ActivityOptions::new()->withSummary(). The summary is limited to 200 bytes and appears in the UI. Example: Workflow::newActivityStub(YourActivitiesInterface::class, ActivityOptions::new()->withStartToCloseTimeout('10 seconds')->withSummary('Processing user data')).

Example Activity implementation in PHP

An Activity class example with the Temporal\Activity\ActivityInterface attribute and a method annotated with Temporal\Activity\ActivityMethod: ```php <?php declare(strict_types=1); namespace App; use Temporal\Activity\ActivityInterface; use Temporal\Activity\ActivityMethod; #[ActivityInterface] class GreetingActivity { #[ActivityMethod] public function greet(string $name): string { return "Hello, $name!"; } } ```

Activity class definition in PHP

Define Activities as PHP classes annotated with the #[ActivityInterface] attribute. Each Activity method must be annotated with #[ActivityMethod]. An Activity is a method that executes a single, well-defined action that often involves interacting with the outside world, such as sending emails, making network requests, writing to a database, or calling APIs.

Activity parameter best practice: use single dataclass

For application data passed to Activities, use a single object as an argument that wraps all the application data rather than multiple parameters. This allows you to change what data is passed to the Activity without breaking the function signature. Activity parameters can be any data type Temporal can convert, including dataclasses when properly type-annotated.

Define a basic Activity with @activity.defn decorator

Create an Activity Definition by decorating a function with @activity.defn. You can optionally specify a custom Activity name using the name parameter, for example @activity.defn(name="your_activity"). If the name parameter is not specified, the Activity name defaults to the function name.

Activity function structure in Python

An Activity is a normal function execution that performs a single, well-defined action such as querying a database, calling a third-party API, or transcoding a media file. Activities can interact with the world outside the Temporal Platform or use a Temporal Client to interact with a Temporal Service.

Avoid blocking calls in asynchronous Activities

Do not make blocking calls from within an asynchronous Activity, as this turns your asynchronous program into a synchronous program that executes serially and can lead to deadlock and unpredictable behavior. If you must use a blocking library, use a synchronous Activity instead or use an async safe library.

Basic Activity example in Python

from temporalio import activity from your_dataobject import YourParams @activity.defn(name="your_activity") async def your_activity(input: YourParams) -> str: return f"{input.greeting}, {input.name}!"

Activity single positional argument; multiple arguments via args keyword

A single argument to the Activity is positional. Multiple arguments are not supported in the type-safe form of start_activity() or execute_activity() and must be supplied by the args keyword argument.

Python SDK Activities documentation sections

The Python SDK Activities documentation covers: Activity basics, Activity execution, Standalone Activities, Timeouts, Asynchronous Activity completion, and Benign exceptions.

Python plugin example with activity

Example of registering an activity in a Python plugin: @activity.defn async def some_activity() -> None: return None plugin = SimplePlugin("organization.PluginName", activities=[some_activity])

Ruby plugin example with activity

Example of registering an activity in a Ruby plugin: def some_activity # Activity implementation end plugin = Temporalio::SimplePlugin.new( name: 'organization.PluginName', activities: [method(:some_activity)] )

Go plugin example with activity

Example of registering an activity in a Go plugin: func SomeActivity(ctx context.Context) error { // Activity implementation return nil } func createActivityPlugin() (*temporal.SimplePlugin, error) { return temporal.NewSimplePlugin(temporal.SimplePluginOptions{ Name: "organization.PluginName", RunContextBefore: func(ctx context.Context, options temporal.SimplePluginRunContextBeforeOptions) error { options.Registry.RegisterActivityWithOptions( SomeActivity, activity.RegisterOptions{Name: "SomeActivity"}, ) return nil }, }) }

DotNet plugin example with activity

Example of registering an activity in a DotNet plugin: [Activity] static void SomeActivity() => throw new NotImplementedException(); SimplePlugin activityPlugin = new SimplePlugin( "organization.PluginName", new SimplePluginOptions() { }.AddActivity(SomeActivity));

TypeScript plugin example with activity

Example of registering an activity in a TypeScript plugin: const activity = async () => 'activity'; const plugin = new SimplePlugin({ name: 'organization.PluginName', activities: { pluginActivity: activity, }, });

Java plugin example with activity

Example of registering an activity in a Java plugin: @ActivityInterface public interface SomeActivity { @ActivityMethod void someActivity(); } public class SomeActivityImpl implements SomeActivity { @Override public void someActivity() { // Activity implementation } } SimplePlugin activityPlugin = SimplePlugin.newBuilder("organization.PluginName") .registerActivitiesImplementations(new SomeActivityImpl()) .build();

Standalone Activity example with compose_greeting

Complete example showing how to define and execute a Standalone Activity. The activity function compose_greeting takes ComposeGreetingInput (with greeting and name fields), logs with activity.logger.info(), and returns a formatted string. Executed with client.execute_activity(compose_greeting, args=[ComposeGreetingInput('Hello', 'World')], id='my-standalone-activity-id', task_queue='my-standalone-activity-task-queue', start_to_close_timeout=timedelta(seconds=10)).

Write a Standalone Activity with @activity.defn decorator

An Activity in the Temporal Python SDK is a normal function with the @activity.defn decorator, and can optionally be an async def. The same Activity can be executed both as a Standalone Activity and as a Workflow Activity. Example: @activity.defn decorator applied to compose_greeting function that takes ComposeGreetingInput and returns a string.

Activity idempotency key example in Python

from temporalio import activity @activity.defn async def process_payment(amount: float, account: str): info = activity.info() idempotency_key = f"{info.workflow_run_id}-{info.activity_id}" result = await payment_service.charge( amount=amount, account=account, idempotency_key=idempotency_key ) return result

Activity atomicity and retry behavior

Activities are atomic—they either complete successfully or not. If an Activity performs multiple steps and any step fails, the entire Activity is retried. You can split multi-step Activities into separate Activities so only the failed step retries, but this increases Event History size with more Activity Executions.

Make activities idempotent using idempotency keys

Because Activities may be retried due to failures, they should be made idempotent. Create an idempotency key by combining the Workflow Run ID and Activity ID. Pass this to external services to prevent duplicate operations. This value remains constant across Activity retries but is unique among all Workflow Executions.

Benefits of synchronous Activities

Synchronous Activities help avoid blocking because they run in the activity_executor rather than in the global event loop. This provides two benefits: there is no risk of accidentally blocking the global event loop, and if you have multiple Activity Tasks running in a thread pool rather than an event loop, one bad Activity Task cannot slow down the others because the OS scheduler preemptively switches between threads, which the event loop coordinator does not do.

Synchronous Activity example with requests library

This synchronous Activity uses the requests library to make HTTP calls, which is safe in synchronous Activities: ```python import urllib.parse import requests from temporalio import activity class TranslateActivities: @activity.defn def greet_in_spanish(self, name: str) -> str: greeting = self.call_service("get-spanish-greeting", name) return greeting # Utility method for making calls to the microservices def call_service(self, stem: str, name: str) -> str: base = f"http://localhost:9999/{stem}" url = f"{base}?name={urllib.parse.quote(name)}" response = requests.get(url) return response.text ```

Synchronous Activity as function instead of class

When cross-activity state is not needed, Activities can be implemented as decorated functions rather than class methods: ```python @activity.defn def greet_in_spanish(name: str) -> str: greeting = call_service("get-spanish-greeting", name) return greeting # Utility method for making calls to the microservices def call_service(stem: str, name: str) -> str: base = f"http://localhost:9999/{stem}" url = f"{base}?name={urllib.parse.quote(name)}" response = requests.get(url) return response.text ```

Three ways to implement Activities in Python SDK

The Temporal Python SDK supports three ways of implementing Activities: asynchronously using asyncio, synchronously multithreaded using concurrent.futures.ThreadPoolExecutor, or synchronously multiprocess using concurrent.futures.ProcessPoolExecutor and multiprocessing.managers.SyncManager.

Async and synchronous Activities run in different contexts

Async Activities and the temporal worker SDK code both run in the default asyncio event loop or whatever event loop is given to the Worker. Synchronous Activities run in the activity_executor.

Default recommendation: synchronous Activities over asynchronous

By default, Activities should be synchronous rather than asynchronous. You should only make an Activity asynchronous if you are certain that it doesn't block the event loop. If you have blocking code in an async def function, it blocks the event loop and the rest of Temporal, which can cause bugs hard to diagnose including freezing the worker and blocking Workflow progress because Temporal cannot tell the server that Workflow Tasks are completing.

Add summary metadata to activities in workflows

When executing an Activity from within a Workflow, you can attach a summary parameter to workflow.execute_activity(). The summary is a string limited to 200 bytes that provides context about the Activity execution.

Python example: execute activity with summary

```python @workflow.defn class YourWorkflow: @workflow.run async def run(self, input: str) -> str: # Start an activity with a summary result = await workflow.execute_activity( your_activity, input, start_to_close_timeout=timedelta(seconds=10), summary="Processing user data" ) return result ``` This example shows how to add a summary to an Activity execution.

Example Activity definition in Python

```python from temporalio import activity @activity.defn async def greet(name: str) -> str: return f"Hello {name}" ``` This example shows a simple Activity that takes a name and returns a greeting string.

Define Activity with @activity.defn decorator

Define an Activity by creating an async function and decorating it with `@activity.defn`. An Activity is a normal function that executes a single, well-defined action, often involving interactions with the outside world such as sending emails, making network requests, writing to a database, or calling an API.

Synchronous activities require executor in Python

Activities defined with `async def` run on the Worker's event loop. Activities defined with a plain `def` are synchronous and require an executor. Pass a ThreadPoolExecutor instance to the `activity_executor` parameter. The same executor can be shared across multiple Workers.

Synchronous activity executor example in Python

Example of creating a Worker with synchronous activities using ThreadPoolExecutor: worker = Worker( client, task_queue="my-task-queue", workflows=[MyWorkflow], activities=[my_sync_activity], activity_executor=ThreadPoolExecutor(5), )

Ruby SDK Activities documentation sections

The Ruby SDK Activities documentation is organized into the following sections: Activity basics, Activity execution, Standalone Activities, Timeouts, Asynchronous Activity completion, Dynamic Activity, and Benign exceptions.

Standalone Activity definition in Ruby

A Standalone Activity in the Ruby SDK is defined as a subclass of Temporalio::Activity::Definition with an execute method. The way you define a Standalone Activity is identical to how you define an Activity orchestrated by a Workflow. The same Activity can be executed both as a Standalone Activity and as a Workflow Activity.

Standalone Activities environment configuration

Code samples using Temporalio::EnvConfig::ClientConfig.load_client_connect_options respond to environment variables and TOML configuration files, so the same code works against a local dev server and Temporal Cloud without changes.

Standalone Activities prerequisites Ruby

Prerequisites for Standalone Activities in Ruby SDK: Ruby 3.3 or higher, Temporal Ruby SDK v1.5.0 or higher, and Temporal CLI v1.7.0 or higher.

Standalone Activity Activity definition example

Example of defining a Standalone Activity in Ruby: ```ruby require 'temporalio/activity' module StandaloneActivity module MyActivities class ComposeGreeting < Temporalio::Activity::Definition def execute(greeting, name) "#{greeting}, #{name}!" end end end end ```

Example: Execute activity with summary in Ruby

require 'temporalio' class YourWorkflow < Temporalio::Workflow::Definition def execute(input) # Execute an activity with a summary result = Temporalio::Workflow.execute_activity( 'YourActivity', input, start_to_close_timeout: 10, summary: 'Processing user data' ) result end end

summary parameter for activities in Ruby workflows

When executing an activity within a workflow using Temporalio::Workflow.execute_activity() in the Ruby SDK, you can provide a summary parameter. This is a string limited to 200 bytes that appears in the Temporal UI Timeline and Event History to help identify and distinguish individual activity instances.

Define a simple Activity in Ruby

Create an Activity by extending Temporalio::Activity::Definition and implementing an execute method. Example: require 'temporalio/activity'; class SayHelloActivity < Temporalio::Activity::Definition; def execute(name); "Hello, #{name}!"; end; end

Using Arc<Self> with Activity methods in Rust

Activities can take Arc<Self> as a parameter and be registered using an instance. This allows shared state to be accessed across multiple Activity invocations.

Activity definition with #[activities] and #[activity] macros in Rust

The #[activities] macro marks an impl block as containing Activity definitions. Each method decorated with #[activity] becomes an Activity that can be invoked from a Workflow. Activity methods must be async, take ActivityContext as the first parameter, return Result<T, ActivityError>, and be public.

Activity parameter limits and size constraints

Activity Definitions may support a maximum of 6 parameters. A single argument is limited to a maximum size of 2 MB. The total size of a gRPC message, which includes all arguments, is limited to a maximum of 4 MB. All Payload data is recorded in the Workflow Execution Event History, and large Event Histories can affect Worker performance.

Activity parameter requirements in Rust SDK

Each Activity method must be async (return a future), take ActivityContext as the first parameter, return Result<T, ActivityError> where T is the return type, and be public. The ActivityContext parameter provides access to Activity execution information and capabilities like heartbeating. If not needed, you can name the parameter _ctx.

Activity parameter serialization requirement in Rust

Activity parameters must be serializable and deserializable using serde. Use #[derive(Serialize, Deserialize)] on your data types to enable proper serialization of Activity inputs.

Customizing Activity Type name in Rust with #[activity] macro

Activities have a Type that refers to the Activity name, used to identify Activity Types in the Workflow Execution Event History, Visibility Queries, and Metrics. By default, the Activity name is the method name. You can customize it by providing a name parameter to the #[activity] macro, for example #[activity(name = "compose_greeting")].

Basic Activity example in Rust SDK

use temporalio_sdk::activities::{ActivityContext, ActivityError}; use temporalio_macros::activities; pub struct GreetingActivities; #[activities] impl GreetingActivities { #[activity] pub async fn greet(_ctx: ActivityContext, name: String) -> Result<String, ActivityError> { Ok(format!("Hello, {}!", name)) } #[activity] pub async fn send_notification(_ctx: ActivityContext, message: String) -> Result<(), ActivityError> { println!("Sending notification: {}", message); Ok(()) } }

Activity with structured input using serde in Rust

use serde::{Serialize, Deserialize}; use temporalio_macros::activities; use temporalio_sdk::activities::{ActivityContext, ActivityError}; #[derive(Serialize, Deserialize)] pub struct GreetingInput { pub greeting: String, pub name: String, } pub struct GreetingActivities; #[activities] impl GreetingActivities { #[activity] pub async fn compose_greeting( _ctx: ActivityContext, input: GreetingInput, ) -> Result<String, ActivityError> { Ok(format!("{} {}!", input.greeting, input.name)) } }

Activity with Arc<Self> and shared state example

struct SleeperActivities { acts_started: Arc<Semaphore>, acts_done: Arc<Semaphore>, } #[activities] impl SleeperActivities { #[activity] async fn sleeper( self: Arc<Self>, ctx: ActivityContext, _: String, ) -> Result<(), ActivityError> { self.acts_started.add_permits(1); // just wait to be cancelled ctx.cancelled().await; self.acts_done.add_permits(1); Err(ActivityError::cancelled()) } }

Rust SDK Activities documentation structure

The Rust SDK Activities documentation is organized into three main sections: Activity basics, Activity execution, and Timeouts.

Activity definition in Rust

Activities are defined using the #[activities] macro on an impl block. Each activity method is marked with #[activity] macro, receives an ActivityContext parameter, and returns Result<T, ActivityError>. Example: pub struct MyActivities; #[activities] impl MyActivities { #[activity] pub async fn greet(_ctx: ActivityContext, name: String) -> Result<String, ActivityError> { Ok(format!("Hello, {}!", name)) } }

proxyLocalActivities example in TypeScript workflow

import * as workflow from '@temporalio/workflow'; const { getEnvVar } = workflow.proxyLocalActivities({ startToCloseTimeout: '2 seconds', }); export async function yourWorkflow(): Promise<void> { const someSetting = await getEnvVar('SOME_SETTING'); // ... } This example shows how to create a proxy to Local Activities with proxyLocalActivities and call them as regular async functions within a workflow.

Local Activities in TypeScript using proxyLocalActivities

To call Local Activities in TypeScript, use workflow.proxyLocalActivities() to create a proxy object with the Activity methods. Specify the startToCloseTimeout option when calling proxyLocalActivities.

Local Activities registration in TypeScript

Local Activities must be registered with the Worker the same way non-local Activities are registered.

Share dependencies in Activity functions using dependency injection

Activities are just functions, so you can create functions that create Activities. This pattern uses closures to store expensive dependencies such as database connections and inject secret keys from the Worker to the Activity. Example: ```ts export interface DB { get(key: string): Promise<string>; } export const createActivities = (db: DB) => ({ async greet(msg: string): Promise<string> { const name = await db.get('name'); return `${msg}: ${name}`; }, async greet_es(mensaje: string): Promise<string> { const name = await db.get('name'); return `${mensaje}: ${name}`; }, }); ```

Standalone Activities run independently without Workflow orchestration

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 Activity directly from a Temporal Client. The way you write the Activity and register it with a Worker is identical to Workflow Activities, with the only difference being that you execute a Standalone Activity directly from your Temporal Client.

Use ReturnType generic for factory function Activity typing

When proxying Activities created by a factory function, use the `ReturnType<>` generic to properly type them: ```ts import type { createActivities } from './activities'; const { greet, greet_es } = proxyActivities<ReturnType<typeof createActivities>>({ startToCloseTimeout: '30 seconds', }); ```

Dynamically reference Activities by string name

Because Activities are referenced only by their string names, you can reference them dynamically: ```js export async function DynamicWorkflow(activityName, ...args) { const acts = proxyActivities(); // these are equivalent await acts.activity1(); await acts['activity1'](); // dynamic reference to activities using activityName let result = await acts[activityName](...args); } ``` Validate and handle mismatches in Activity names. An invalid Activity name leads to a `NotFoundError` with a message like: `ApplicationFailure: Activity function actC is not registered on this Worker, available activities: ["actA", "actB"]`

Give your agent this brain