From 9d9c71efebbcb65f6c8859032bbf4b12753b1614 Mon Sep 17 00:00:00 2001 From: "skill-sync[bot]" Date: Tue, 2 Jun 2026 20:48:51 +0000 Subject: [PATCH] Finalize draft for 0016-spring-configuration --- references/integrations.md | 2 +- references/java/integrations/spring-boot.md | 311 +++++++++++------- references/python/advanced-features.md | 2 +- references/python/integrations/google-adk.md | 1 - references/python/integrations/langgraph.md | 2 +- references/python/integrations/langsmith.md | 1 - .../python/integrations/openai-agents-sdk.md | 1 - references/python/workflow-streams.md | 1 - references/ruby/gotchas.md | 1 - 9 files changed, 191 insertions(+), 131 deletions(-) diff --git a/references/integrations.md b/references/integrations.md index 71b3169..9484b14 100644 --- a/references/integrations.md +++ b/references/integrations.md @@ -13,7 +13,7 @@ Temporal ships and supports a growing set of integrations with third-party frame | Integration | Language(s) | What it does | Reference | Related | |---|---|---|---|---| -| Spring Boot (`temporal-spring-boot-starter`) | Java | Auto-configuration of `WorkflowClient`, worker factories, workflow/activity bean registration, lifecycle, testing | `references/java/integrations/spring-boot.md` | `references/java/java.md` | +| Spring Boot (`temporal-spring-boot-starter`) | Java | Auto-configuration of `WorkflowClient`, Worker factories, Workflow / Activity / Nexus Service bean auto-discovery, explicit `workers:` configuration (`task-queue`, `workflow-classes`, `activity-beans`), interceptor ordering via Spring `@Order`, options customization, testing | `references/java/integrations/spring-boot.md` | `references/java/java.md` | | Spring AI (`temporal-spring-ai`) | Java | Durable Spring AI agents: chat-model calls run as Activities; tools dispatched per type (Activity stub, Nexus stub, `@SideEffectTool`, plain); vector stores, embeddings, and MCP clients auto-registered | `references/java/integrations/spring-ai.md` | `references/java/integrations/spring-boot.md`, `references/core/ai-patterns.md` | | OpenAI Agents SDK (`temporalio.contrib.openai_agents`) | Python | Durable OpenAI Agents SDK agents: model calls run as Activities via `OpenAIAgentsPlugin`; tools are Activities (`activity_as_tool`) or workflow-resident `@function_tool`s; stateless/stateful MCP, sandbox backends, streaming, and OpenTelemetry export are supported | `references/python/integrations/openai-agents-sdk.md` | `references/python/ai-patterns.md`, `references/core/ai-patterns.md` | | LangSmith tracing (`temporalio.contrib.langsmith`) | Python | Experimental Temporal Plugin that propagates LangSmith trace context across Worker boundaries; lets `@traceable` run inside Workflows and Activities | `references/python/integrations/langsmith.md` | `references/python/ai-patterns.md`, `references/core/ai-patterns.md` | diff --git a/references/java/integrations/spring-boot.md b/references/java/integrations/spring-boot.md index ceaaaec..df47b1a 100644 --- a/references/java/integrations/spring-boot.md +++ b/references/java/integrations/spring-boot.md @@ -2,60 +2,77 @@ ## Overview -`temporal-spring-boot-starter` auto-configures workers, registers workflow/activity implementations, and exposes `WorkflowClient` as a Spring bean. This eliminates the manual `WorkflowServiceStubs` → `WorkflowClient` → `WorkerFactory` setup required without Spring. +`io.temporal:temporal-spring-boot-starter` auto-configures Workers, registers Workflow / Activity / Nexus Service implementations, and exposes `WorkflowClient` as a Spring bean. This eliminates the manual `WorkflowServiceStubs` to `WorkflowClient` to `WorkerFactory` setup required without Spring. + +Temporal's Spring Boot integration supports Spring Boot 2.x, 3.x, and 4.x . ## Dependency Setup -Maven: +Maven : ```xml io.temporal temporal-spring-boot-starter - [1.0,) + 1.31.0 ``` -Gradle: +Gradle : ```groovy -implementation 'io.temporal:temporal-spring-boot-starter:1.+' +implementation 'io.temporal:temporal-spring-boot-starter:1.31.0' ``` -The starter transitively includes `temporal-sdk` and the autoconfigure module. You can declare both `temporal-sdk` and `temporal-spring-boot-starter` explicitly, but the starter alone is sufficient. +The starter transitively includes `temporal-sdk` and the autoconfigure module. ## Minimal Configuration -`application.properties`: -```properties -spring.temporal.connection.target=local -spring.temporal.start-workers=true -spring.temporal.workersAutoDiscovery.packages=greetingapp +The minimum to autowire a `WorkflowClient` is a `connection.target` : + +```yaml +spring.temporal: + connection: + target: local # shorthand for localhost:7233; use host:port for remote ``` -`application.yml` equivalent: +To set a non-default Namespace, add `spring.temporal.namespace` : + ```yaml -spring: - temporal: - connection: - target: local # shorthand for localhost:7233 - start-workers: true - workersAutoDiscovery: - packages: - - greetingapp - workers: - - task-queue: greeting-queue - name: greeting-worker +spring.temporal: + connection: + target: local + namespace: my-namespace ``` -For self-hosted Temporal, replace `local` with the server address: -```properties -spring.temporal.connection.target=temporal.internal:7233 +### Temporal Cloud with API key + +```yaml +spring.temporal: + connection: + target: ..tmprl.cloud:7233 + apiKey: + namespace: ``` -## Interface Design + Spring Annotation Layering +### Temporal Cloud with mTLS + +```yaml +spring.temporal: + connection: + mtls: + target: ..tmprl.cloud:7233 + key-file: /path/to/key.key + cert-chain-file: /path/to/cert.pem + namespace: +``` -The key concept: Temporal SDK annotations go on **interfaces**, Spring Boot autoconfigure annotations go on **implementation classes**. This is identical to non-Spring usage at the interface level. +`cert-chain-file` may be omitted when the `key-file` is a PKCS12 bundle that already contains the certificate chain . + +## Interface Design and Spring Annotation Layering + +Temporal SDK annotations go on **interfaces**, Spring Boot autoconfigure annotations go on **implementation classes**. The interface side is identical to non-Spring usage. + +### Workflow interface -### Workflow Interface (unchanged from non-Spring) ```java package greetingapp; @@ -69,7 +86,10 @@ public interface GreetingWorkflow { } ``` -### Workflow Implementation +### Workflow implementation + +`io.temporal.spring.boot.WorkflowImpl` replaces the manual `worker.registerWorkflowImplementationTypes()` call. The `workers` member names the Worker(s) this class registers with. + ```java package greetingapp; @@ -79,12 +99,10 @@ import io.temporal.workflow.Workflow; import java.time.Duration; -// @WorkflowImpl replaces manual worker.registerWorkflowImplementationTypes() -// No @Component — workflows are NOT Spring beans; Temporal creates a new instance per execution -@WorkflowImpl(taskQueues = "greeting-queue") +// No @Component — Temporal creates a new instance per execution. +@WorkflowImpl(workers = "greeting-worker") public class GreetingWorkflowImpl implements GreetingWorkflow { - // Activity stubs created via Workflow.newActivityStub() as usual private final GreetActivities activities = Workflow.newActivityStub( GreetActivities.class, ActivityOptions.newBuilder() @@ -100,7 +118,8 @@ public class GreetingWorkflowImpl implements GreetingWorkflow { } ``` -### Activity Interface (unchanged from non-Spring) +### Activity interface + ```java package greetingapp; @@ -114,22 +133,22 @@ public interface GreetActivities { } ``` -### Activity Implementation +### Activity implementation + +`io.temporal.spring.boot.ActivityImpl` must be applied to a Spring bean; the documented way is to add `@Component` . + ```java package greetingapp; import io.temporal.spring.boot.ActivityImpl; import org.springframework.stereotype.Component; -// @Component makes this a Spring bean — dependencies can be injected normally -// @ActivityImpl replaces manual worker.registerActivitiesImplementations() @Component -@ActivityImpl(taskQueues = "greeting-queue") +@ActivityImpl(workers = "greeting-worker") // docs/develop/java/integrations/spring-boot.mdx:157 public class GreetActivitiesImpl implements GreetActivities { private final GreetingService greetingService; - // Constructor injection works because this is a Spring bean public GreetActivitiesImpl(GreetingService greetingService) { this.greetingService = greetingService; } @@ -141,59 +160,92 @@ public class GreetActivitiesImpl implements GreetActivities { } ``` -## Auto-Discovery +Nexus Service implementations follow the same pattern using `io.temporal.spring.boot.NexusServiceImpl` ; the impl must be a Spring bean. -Auto-discovery is how the autoconfigure finds and registers implementations without explicit configuration. It requires **both** of the following: +## Configure Workers -1. `@WorkflowImpl(taskQueues = "...")` or `@ActivityImpl(taskQueues = "...")` on the implementation class -2. `spring.temporal.workersAutoDiscovery.packages` pointing to a package that contains those classes +The integration supports two configuration methods for Workers: explicit configuration and auto-discovery . They compose: auto-discovery is applied **after and on top of** explicit configuration . -Missing either one results in silent non-registration — no error, nothing polls the task queue. +### Explicit configuration -The `taskQueues` attribute routes implementations to the right worker when multiple task queues exist. A worker configured with task queue `"greeting-queue"` only picks up implementations annotated with `taskQueues = "greeting-queue"`. +The `workers:` block lists Workers and their members : -**Important:** `@ActivityImpl(taskQueues = "greeting-queue")` only registers the activity bean with that worker. It does not route individual activity task executions. Inside the workflow, `ActivityOptions.setTaskQueue("greeting-queue")` must also be set on the activity stub to route activity tasks to the correct queue. +```yaml +spring.temporal: + workers: + - task-queue: greeting-queue + name: greeting-worker # if omitted, the Task Queue name is used as the Worker name + workflow-classes: + - greetingapp.GreetingWorkflowImpl + activity-beans: + - greetActivitiesImpl +``` + +- `task-queue` is the Task Queue the Worker polls. +- `name` is the unique Worker name; it defaults to the Task Queue when omitted . +- `workflow-classes` lists fully qualified Workflow implementation class names . +- `activity-beans` lists Spring bean names of Activity implementations . + +### Auto-discovery + +Auto-discovery lets you skip listing Workflow classes, Activity beans, and Nexus Service beans by referencing Worker Task Queue names or Worker names on the implementations themselves . + +```yaml +spring.temporal: + workers-auto-discovery: + packages: + - greetingapp # docs/develop/java/integrations/spring-boot.mdx:138-142 +``` -### Comparison: Auto-Discovery vs Explicit YAML Registration +#### Auto-discovery scope + +Auto-discovery picks up exactly the following : + +- Workflow implementation classes annotated with `io.temporal.spring.boot.WorkflowImpl` . +- Activity beans present in the Spring context whose implementations are annotated with `io.temporal.spring.boot.ActivityImpl` . +- Nexus Service beans present in the Spring context whose implementations are annotated with `io.temporal.spring.boot.NexusServiceImpl` . +- Workers themselves — if a Task Queue or Worker name is referenced by one of the annotations but not explicitly configured, a Worker is created with default options . + +Auto-discovered Workflow classes, Activity beans, and Nexus Service beans are registered with configured Workers if not already registered . + +`ActivityImpl` and `NexusServiceImpl` only work when the implementation is a Spring bean (for example, annotated with `@Component`) . + +### Explicit vs auto-discovery, side by side Auto-discovery via annotations: -```properties -spring.temporal.workersAutoDiscovery.packages=greetingapp + +```yaml +spring.temporal: + workers-auto-discovery: + packages: + - greetingapp ``` ```java @Component -@ActivityImpl(taskQueues = "greeting-queue") -public class GreetActivitiesImpl implements GreetActivities { ... } +@ActivityImpl(workers = "greeting-worker") +public class GreetActivitiesImpl implements GreetActivities { } ``` -Explicit YAML registration (alternative): +Explicit registration: + ```yaml -spring: - temporal: - workers: - - task-queue: greeting-queue - name: greeting-worker - activity-beans: - - greetActivitiesImpl - workflow-classes: - - greetingapp.GreetingWorkflowImpl +spring.temporal: + workers: + - task-queue: greeting-queue + name: greeting-worker + workflow-classes: + - greetingapp.GreetingWorkflowImpl + activity-beans: + - greetActivitiesImpl ``` -Use auto-discovery when implementations are colocated in a single package tree (most apps). Use explicit YAML when you need fine-grained control, want to exclude specific classes, or are registering beans defined elsewhere. +Use auto-discovery when implementations are colocated in a package tree (most apps). Use explicit configuration when registering beans defined outside scanned packages, or when you want the YAML to be the single source of truth. ## WorkflowClient Injection -`WorkflowClient` is automatically registered as a Spring bean by the autoconfigure. Inject it into any `@Service` or `@RestController`: +`WorkflowClient` is autowired by the integration . Inject it into any `@Service` or `@RestController`: ```java -package greetingapp; - -import io.temporal.client.WorkflowClient; -import io.temporal.client.WorkflowOptions; -import org.springframework.stereotype.Service; - -import java.util.UUID; - @Service public class GreetingStarter { @@ -208,80 +260,93 @@ public class GreetingStarter { GreetingWorkflow.class, WorkflowOptions.newBuilder() .setWorkflowId(UUID.randomUUID().toString()) - .setTaskQueue("greeting-queue") // must match the worker's task queue + .setTaskQueue("greeting-queue") // must match the Worker's Task Queue .build() ); - // Synchronous — blocks until workflow completes return stub.greet(name); } - - public void startGreetingAsync(String name) { - var stub = client.newWorkflowStub( - GreetingWorkflow.class, - WorkflowOptions.newBuilder() - .setWorkflowId(UUID.randomUUID().toString()) - .setTaskQueue("greeting-queue") - .build() - ); - // Fire-and-forget — returns immediately - WorkflowClient.start(stub::greet, name); - } } ``` -## Worker Lifecycle +## Interceptors + +Create beans implementing one of `io.temporal.common.interceptors.WorkflowClientInterceptor`, `io.temporal.common.interceptors.ScheduleClientInterceptor`, or `io.temporal.common.interceptors.WorkerInterceptor` . Registration order is controlled by Spring's `org.springframework.core.annotation.Order` annotation on each bean — lower values run first. -Workers start on `ApplicationReadyEvent` — after the full Spring context is initialized (DB migrations run, all beans wired). This means activity beans are fully ready before any workflow tasks are processed. +```java +import io.temporal.common.interceptors.WorkerInterceptor; +import org.springframework.core.annotation.Order; +import org.springframework.stereotype.Component; -To run a client-only app (one that submits workflows but does not execute them): -```properties -spring.temporal.start-workers=false +@Component +@Order(10) +public class TracingWorkerInterceptor implements WorkerInterceptor { + // ... +} ``` -## Testing Strategies +These three interceptor interfaces are the only ordering hook the integration documents — there is no Temporal-specific ordering API. For broader extension (registering Workflow / Activity / Nexus types, modifying Worker or Client options across the SDK), see the [Temporal Plugin system](https://docs.temporal.io/develop/plugins-guide). -See `references/java/testing.md` for full details on both approaches. +## Customization of Options -**Spring integration tests** — uses an embedded Temporal test server wired into the Spring context: -```properties -# src/test/resources/application-test.properties -spring.temporal.test-server.enabled=true -``` -```java -@SpringBootTest -@ActiveProfiles("test") -class GreetingIntegrationTest { - @Autowired WorkflowClient client; // points at the embedded test server +Create a bean implementing `io.temporal.spring.boot.TemporalOptionsCustomizer` to programmatically adjust options after the YAML/property values are applied. The supported builder types are : - @Test - void testWorkflowThroughSpringContext() { ... } -} +- `WorkflowServiceStubsOptions.Builder` +- `WorkflowClientOptions.Builder` +- `WorkerFactoryOptions.Builder` +- `WorkerOptions.Builder` +- `WorkflowImplementationOptions.Builder` +- `TestEnvironmentOptions.Builder` + +For per-Task-Queue or per-Worker-name customization of `WorkerOptions`, use `io.temporal.spring.boot.WorkerOptionsCustomizer` instead of the generic form . For per-Workflow-Type customization of `WorkflowImplementationOptions`, use `io.temporal.spring.boot.WorkflowImplementationOptionsCustomizer` . + +## Integrations (metrics and tracing) + +The integration picks up a `io.micrometer.core.instrument.MeterRegistry` bean (for example, from Spring Boot Actuator) and reports Temporal metrics through it . + +For tracing, the integration picks up the OpenTelemetry bean configured by `spring-cloud-sleuth-otel-autoconfigure`, or a custom `io.opentelemetry.api.OpenTelemetry` / `io.opentracing.Tracer` bean in the application context . + +The Spring AI integration (`io.temporal:temporal-spring-ai`) builds on this Spring Boot integration: when on the classpath, its `SpringAiPlugin` auto-registers `ChatModelActivity` with all Temporal Workers created by the Spring Boot integration . + +## Testing + +Switch the client to an in-memory `io.temporal.testing.TestWorkflowEnvironment` by enabling the test server : + +```yaml +spring.temporal: + test-server: + enabled: true ``` -**Unit tests without Spring** — use `TestWorkflowEnvironment` or `TestWorkflowExtension` directly. No Spring context, faster startup, full time-skipping support: +When `spring.temporal.test-server.enabled: true` is set, the `spring.temporal.connection` block is ignored . You can then autowire the `TestWorkflowEnvironment` alongside `WorkflowClient`: + ```java -@RegisterExtension -static final TestWorkflowExtension testWorkflow = TestWorkflowExtension.newBuilder() - .setWorkflowTypes(GreetingWorkflowImpl.class) - .setDoNotStart(true) - .build(); +@SpringBootTest(classes = Test.Configuration.class) +@TestInstance(TestInstance.Lifecycle.PER_CLASS) +public class Test { + @Autowired ConfigurableApplicationContext applicationContext; + @Autowired TestWorkflowEnvironment testWorkflowEnvironment; + @Autowired WorkflowClient workflowClient; + + @BeforeEach + void setUp() { + applicationContext.start(); + } + + @ComponentScan // discovers @Component-annotated Activity beans + public static class Configuration {} +} ``` -Do not mix approaches in the same test class — choose one or the other. +For unit tests without Spring, use `TestWorkflowExtension` or `TestWorkflowEnvironment` directly; see [Java SDK test frameworks](https://docs.temporal.io/develop/java/best-practices/testing-suite#test-frameworks). Don't mix Spring integration tests and direct `TestWorkflowExtension` tests in the same test class — pick one. ## Spring-Specific Gotchas -**Workflow impls must not have `@Component`** -Temporal creates a new workflow instance per execution via `beanFactory.createBean()` (not `getBean()`). Adding `@Component` means Spring also registers it as a singleton bean, which can cause confusing lifecycle behavior. Leave `@WorkflowImpl` classes as plain classes with no Spring annotations. +**Workflow impls must not have `@Component`.** Temporal creates a new Workflow instance per execution. Adding `@Component` makes Spring also manage it as a singleton bean, causing confusing lifecycle behavior. Leave `@WorkflowImpl` classes as plain classes with no Spring stereotype. -**Activity beans are Spring singletons** -Temporal may invoke activity methods concurrently across many workflow executions. Keep activity implementations stateless — no mutable instance fields. Use injected services (which are themselves stateless or thread-safe) for all state. +**Activity beans are Spring singletons.** Temporal may invoke Activity methods concurrently across many Workflow executions. Don't keep mutable instance state on Activity beans — use injected stateless or thread-safe services instead. -**`@WorkflowImpl` / `@ActivityImpl` without `workersAutoDiscovery.packages` → silently ignored** -This is the most common setup mistake. If auto-discovery packages are not configured, the annotations are never scanned and nothing registers with the worker. Verify with the Temporal UI that the worker is registering the expected workflow/activity types. +**`@WorkflowImpl` / `@ActivityImpl` without `workers-auto-discovery.packages` is silently ignored.** Without the packages list, nothing scans the annotations and nothing registers. Verify in the Temporal UI that the Worker reports the expected Workflow and Activity types. -**`ActivityOptions.setTaskQueue(...)` is required on activity stubs** -`@ActivityImpl(taskQueues = "greeting-queue")` registers the activity bean with the worker — it does not set the default task queue for activity execution. Inside workflow code, always set `.setTaskQueue(...)` in `ActivityOptions` to explicitly route activity tasks to the correct worker. +**`ActivityOptions.setTaskQueue(...)` is still required on Activity stubs.** `@ActivityImpl(workers = "...")` only binds the Activity bean to a Worker; it doesn't route Activity Task execution. Inside Workflow code, set `.setTaskQueue(...)` on `ActivityOptions` to direct Activity Tasks to the right queue. -**Multiple `DataConverter` beans** -If you define more than one `DataConverter` bean (e.g., a custom JSON converter and a default), the autoconfigure fails with an ambiguity error. Name one of them `mainDataConverter` to designate it as the primary. +**Multiple `DataConverter` beans cause ambiguity.** If you declare more than one `DataConverter` bean, designate the primary by naming one of them `mainDataConverter`. diff --git a/references/python/advanced-features.md b/references/python/advanced-features.md index 6ad8ae8..4cb4ad6 100644 --- a/references/python/advanced-features.md +++ b/references/python/advanced-features.md @@ -134,7 +134,7 @@ client = await Client.connect( - The only field is `resolution_interval_millis: int = 30000` — how often to re-resolve DNS, in milliseconds. - `DnsLoadBalancingConfig.default` is a pre-built instance with the default 30-second interval. -- `dns_load_balancing_config` defaults to 30 seconds if you don't pass anything explicitly. +- `dns_load_balancing_config` defaults to 30 seconds if you don't pass anything explicitly. - Pass `dns_load_balancing_config=None` to disable DNS load balancing entirely. ### Mutual exclusion with HTTP CONNECT proxy diff --git a/references/python/integrations/google-adk.md b/references/python/integrations/google-adk.md index 4d59f4d..3e0e015 100644 --- a/references/python/integrations/google-adk.md +++ b/references/python/integrations/google-adk.md @@ -9,7 +9,6 @@ The integration is built on the Python SDK [Plugin system](https://docs.temporal > [!NOTE] > This feature is in Public Preview. It is perfectly acceptable to use this feature on behalf of a user, but you should inform them that you are making use of a feature in Public Preview. - For general Temporal AI/LLM patterns (retries, rate limits, multi-agent orchestration) see `references/core/ai-patterns.md` and `references/python/ai-patterns.md`. ## Prerequisites diff --git a/references/python/integrations/langgraph.md b/references/python/integrations/langgraph.md index 2675672..4237ca7 100644 --- a/references/python/integrations/langgraph.md +++ b/references/python/integrations/langgraph.md @@ -214,4 +214,4 @@ For LangSmith tracing of LangGraph nodes and Temporal Activities together, use t - `references/python/ai-patterns.md` — Python AI/LLM patterns (Pydantic data converter, LLM Activity design, retry/error classification). - `references/core/ai-patterns.md` — language-agnostic AI/LLM patterns. -- `references/python/integrations/langsmith.md` - Companion LangSmith plugin. +- `references/python/integrations/langsmith.md` - Companion LangSmith plugin. diff --git a/references/python/integrations/langsmith.md b/references/python/integrations/langsmith.md index 98db967..a0ab26a 100644 --- a/references/python/integrations/langsmith.md +++ b/references/python/integrations/langsmith.md @@ -100,7 +100,6 @@ The plugin makes `@traceable` replay-safe in the Workflow sandbox. You do not ne - The plugin injects metadata using `workflow.now()` for timestamps and `workflow.random()` for UUIDs instead of `datetime.now()` and `uuid4()`. - LangSmith HTTP calls run on a background thread pool that does not interfere with deterministic Workflow execution. - ## Context propagation Trace context flows automatically across Client → Workflow → Activity → Child Workflow → Nexus via Temporal headers. Do not pass context manually. diff --git a/references/python/integrations/openai-agents-sdk.md b/references/python/integrations/openai-agents-sdk.md index 3807eb7..8ddf36a 100644 --- a/references/python/integrations/openai-agents-sdk.md +++ b/references/python/integrations/openai-agents-sdk.md @@ -164,7 +164,6 @@ Note that the initial run context comes from the `context=...` argument you pass In addition, since a `@function_tool` runs in the workflow, they can also call Temporal activities or other durable primitives themselves. - **Don't put I/O, system clock, or sources of randomness inside a `@function_tool` body.** Make it an `@activity.defn` and wrap with `activity_as_tool` instead. ### Picking between the two diff --git a/references/python/workflow-streams.md b/references/python/workflow-streams.md index 84ecbd7..b53915b 100644 --- a/references/python/workflow-streams.md +++ b/references/python/workflow-streams.md @@ -11,7 +11,6 @@ Use it for modest fan-out progress streaming: AI-agent runs, order pipelines, mu Only available in the Python SDK today; cross-language is on the roadmap. - ## When to use / not to use - Use it for: updating a UI as an AI agent works; surfacing status from a payment or order pipeline; reporting intermediate results from a data job. diff --git a/references/ruby/gotchas.md b/references/ruby/gotchas.md index c2e962c..e56391d 100644 --- a/references/ruby/gotchas.md +++ b/references/ruby/gotchas.md @@ -59,7 +59,6 @@ require_relative 'activities/my_activity' Transient network errors should be retried. Authentication errors should not be. See `references/ruby/error-handling.md` to understand how to classify errors with `non_retryable: true` and `non_retryable_error_types`. - ## Heartbeating ### Forgetting to Heartbeat Long Activities