Early Return pattern benefits
The Early Return pattern provides immediate client feedback via Update-with-Start in a single round trip. Clients do not wait for full operation completion. Local Activities avoid extra server roundtrips during initialization, there is a clear separation between validation and execution phases, and automatic cancellation handling runs on initialization failure.
Early Return pattern is not suitable for
The Early Return pattern is not a good fit for fully automated processes that require no intermediate feedback, operations that cannot be split into fast and slow phases, or fire-and-forget operations where no immediate response is needed (use Signals instead).
Early Return best practice: handle Update-with-Start non-atomicity
Update-with-Start is not atomic. The Workflow may start even if the Update fails. Ensure Workers are running and handle the case where the Update is not delivered.
Early Return pattern use cases
The Early Return pattern is a good fit when clients need immediate feedback but operations take time to complete, validation or initialization can be done quickly (under 5 seconds), the operation can be safely cancelled if initialization fails, and the initialization result determines whether to proceed or abort. Common use cases include e-commerce payment processing (immediate authorization while settlement runs in the background), user onboarding and KYC verification (quick user ID return while background checks continue), resource provisioning (fast validation results while infrastructure is set up), document processing (immediate receipt confirmation while OCR and content analysis continue), and order processing (fast inventory check while fulfillment runs in the background).
Concurrent Update limit in Temporal
The default maxInFlightUpdates is 10 per Workflow. If you expect high concurrency, design accordingly or use separate Workflows.
Early Return pattern implementation across SDKs
The Workflow registers an Update handler that blocks until initialization completes using a condition flag (workflow.Await in Go, Workflow.await in Java, condition in TypeScript, workflow.wait_condition in Python), then returns the result to the caller. The client receives the initialization result via Update-with-Start in a single API call that also starts the Workflow.
Early Return best practice: keep Update handler lightweight
Use Workflow.await in the Update handler. Keep the Update handler lightweight — block on a condition flag and let the main Workflow method do the real work.
Early Return pattern trade-offs
Trade-offs to consider are that you must tune timeouts carefully for local Activities. There is a concurrent Update limit (10 per Workflow) that can bottleneck high-throughput scenarios requiring multiple simultaneous Updates. Clients must handle asynchronous completion separately, initialization must complete within a single Workflow Task, and the pattern is limited to operations that can be split into fast and slow phases.
Early Return pattern solution approach
The Workflow uses local Activities for quick initialization, signals completion via Update handlers, then either completes or cancels the operation based on initialization success. The client receives the initialization result in a single round trip while the Workflow continues processing.
ScheduleToCloseTimeout configuration
ScheduleToCloseTimeout is set on the Activity call options, not in RetryPolicy. It caps the total wall-clock time from when the Activity is first scheduled to when it must complete, across all retry attempts.
RetryPolicy fields and defaults
The RetryPolicy fields are: MaximumAttempts (default: 0, unlimited; caps total attempts including the first), InitialInterval (default: 1 second; delay before first retry), BackoffCoefficient (default: 2.0; multiplier applied after each retry), MaximumInterval (default: 100× InitialInterval; upper bound on backoff delay), NonRetryableErrorTypes (default: empty list; error types that skip retries entirely).
Error handling patterns overview
Temporal provides patterns to control how Activities are retried, how persistent failures surface to users, and how to recover from errors that require human intervention.
Default RetryPolicy behavior in Temporal
Temporal's default RetryPolicy retries Activities indefinitely with exponential backoff. Unless you configure a policy, a failing Activity will keep retrying until the ScheduleToCloseTimeout or the Workflow itself completes.
Error handling pattern decision tree
The decision tree for choosing a retry pattern: (1) If each attempt costs money/quota, use Fixed Count of Retries. (2) If error is structural, ask if human can fix it — if yes use Resumable Activity, if no use Non-Retryable Errors. (3) If downstream has scheduled maintenance with known duration, use Delayed Retry. (4) If must resolve within SLA window, use Fixed Wall-Time Retries. (5) If want aggressive initial retries then patient recovery, use Fast/Slow Retries. (6) For any long-running retry, add Retry Alerting via Metrics.
Entity Workflow pitfall: not waiting for handlers to finish
Not waiting for handlers to finish before Continue-As-New leads to in-flight handlers not completing before the transition. Use `allHandlersFinished` (TypeScript), `Workflow.isEveryHandlerFinished()` (Java), or `workflow.all_handlers_finished()` (Python) before transitioning.
Entity Workflow pitfall: Continue-As-New from handlers
Calling Continue-As-New from Signal or Update handlers causes non-determinism errors. Continue-As-New must be called from the main Workflow method, never from inside a handler.
Entity Workflow not appropriate for
The Entity Workflow pattern is not a good fit for short-lived processes (use regular Workflows), stateless operations (use Activities), high-frequency updates (more than 100 per second per entity), or entities with only CRUD operations (use a database).
Entity Workflow appropriate use cases
The Entity Workflow pattern is a good fit for user accounts and profiles, IoT devices and sensors, customer relationships (CRM), shopping carts and orders, financial accounts, subscription management, device provisioning and lifecycle, and multi-tenant resources.
Entity Workflow handlers finishing before Continue-As-New
Use `allHandlersFinished` (TypeScript), `Workflow.isEveryHandlerFinished()` (Java), or `workflow.all_handlers_finished()` (Python) to ensure in-flight handlers complete before calling Continue-As-New.
Entity Workflow when Continue-As-New is triggered
Continue-As-New is triggered when `isContinueAsNewSuggested()` returns true. The SDK provides this method which accounts for actual history size. Always use `isContinueAsNewSuggested()` instead of a hardcoded counter.
Entity Workflow state passing on Continue-As-New
The Workflow takes a single input object that carries both the entity ID and the current state, so state is passed forward on Continue-As-New rather than reset. The state field is unset for the original caller and populated only on continuation; the new run restores it before processing further operations.
Entity Workflow Continue-As-New placement
Always call Continue-As-New from the main Workflow method, never from handlers. Handlers set state, and the main Workflow method checks whether to Continue-As-New. Calling Continue-As-New from a handler causes non-determinism errors.
Entity Workflow best practice: use entity ID as Workflow ID
Use entity ID as Workflow ID. This ensures uniqueness and idempotent starts.
Entity Workflow benefits
All operations on an entity go through a single Workflow, eliminating race conditions. The Workflow history provides a complete audit trail of all state changes. All entity logic lives in one place, and state survives process crashes and restarts. Temporal provides exactly-once execution and automatic retries. You can inspect current state through Queries without side effects.
Entity Workflow monitor history size
Alert when approaching the Continue-As-New threshold.
Entity Workflow set timeouts
Use Workflow execution timeout as a safety net.
Entity Workflow version carefully
Use Worker versioning for Workflow code changes.
Entity Workflow handle deletion
Implement an explicit deletion or decommission Signal.
Entity Workflow add Queries
Expose state for monitoring and debugging.
Entity Workflow keep state minimal
Store large data externally and reference it in the Workflow.
Entity Workflow use Updates for operations needing validation
Use Updates for operations that require validation and a return value.
Entity Workflow use Signals for asynchronous events
Use Signals for asynchronous notifications that do not need responses.
Entity Workflow Update ID deduplication across Continue-As-New
Update IDs are scoped to a single Workflow Execution. After Continue-As-New, the same Update ID can be accepted again. Carry processed IDs in the Continue-As-New input if deduplication is needed.
Entity Workflow 2 MB payload limit on Continue-As-New input
State passed to Continue-As-New is subject to the same 2 MB blob size limit as Workflow inputs. Use external storage for large state.
Entity Workflow trade-offs
You must use Continue-As-New to prevent unbounded history growth. A single Workflow handles all operations for one entity, which limits throughput. State is kept in Workflow memory, so you should use Activities for large data. One Workflow per entity means you should consider costs at scale. The first operation after an idle period may have latency.
Pattern selection rule: delayed execution
When execution should begin later, use Delayed Start.
Pattern selection rule: HTTP callbacks
When you send or receive HTTP callbacks, use Delayed Callback (Webhooks).
External interaction patterns overview
External Interaction Patterns cover how a Workflow waits on or interacts with systems outside it — external APIs, human decisions, scheduled delays, and inbound or outbound callbacks — while staying durable across failures.
Pattern selection rule: external decision required
When a person or external system must decide, use Approval to block on a Signal.
Pattern selection rule: long-running activity
When one Activity runs for a long time, use Long Running Activity with heartbeats so failures resume instead of restarting.
Pattern selection rule: no external notification
When the external system offers no notification, use Polling External Services and tune the interval to the expected latency.
Polling External Services pattern
Polling External Services pattern checks an external resource on a schedule until it reaches the state you need, with frequent, infrequent, and periodic variants. Use this pattern when the external system offers no notification.
Approval pattern
Approval pattern blocks the Workflow until an external decision arrives, capturing the approval and its metadata through a Signal. Use this pattern when a person or external system must decide.
Fan-Out should use offset and length, not explicit IDs
Pass only two integers (offset and length) to each child Workflow rather than a full slice of record IDs. The child fetches its own records using these parameters. This keeps history events small and avoids passing large lists of IDs over the wire.
Fan-Out chunk size should respect Activity limits
Size chunks to stay under the Activity limit. Each child Workflow can have at most 2,000 in-flight Activities. Aim for chunks of 500 records or fewer if each record maps to one Activity.
Fan-Out should cap concurrent children in parent
Starting thousands of child Workflows simultaneously puts pressure on the namespace. Consider batching child starts or using Sliding Window pattern if you need tighter concurrency control.
Fan-Out parent close policy for fire-and-forget
Set `PARENT_CLOSE_POLICY_ABANDON` for fire-and-forget fan-outs where the parent does not need to collect results. With the default `TERMINATE` policy, cancelling or timing out the parent will terminate all in-flight children.
Fan-Out pattern use case and constraints
Use Fan-Out when you want maximum concurrency with no rate control and you can pre-compute how many chunks you need before the job starts. A single Workflow run can have at most 2,000 in-flight Activities (aim for 500) and at most 50,000 history events. Keep the number of in-flight children per parent well under the default limit of 2,000. Use Sliding Window or Batch Iterator patterns for larger workloads.
Fan-Out pitfall: starting too many children at once
Each child start adds to the parent's history. Temporal enforces a default limit of 2,000 pending (in-flight) child Workflows per parent; keep well under it. If you need more children, switch to MapReduce Tree or Sliding Window patterns.
Fan-Out pitfall: passing large lists of IDs
Workflow inputs are stored in event history. Passing millions of record IDs as a list will blow the history size limit. Use offset + length instead to avoid this problem.
Fan-Out with Child Workflows pattern overview
The Fan-Out pattern distributes a large record set across multiple independent child Workflows, each responsible for processing a fixed-size chunk. The parent Workflow assigns work by offset and length so that no record IDs need to be passed over the wire — only two integers per child. This approach keeps each Workflow's history within safe bounds while enabling maximum concurrency with no rate control.
Fan-Out child Workflow IDs should be deterministic
Give each child a deterministic Workflow ID such as `parentId/batch-<offset>`. This makes it safe to re-run the parent: Temporal deduplicates child starts by Workflow ID, so already-completed children are not re-executed.
Fan-Out pitfall: ignoring child failures
A failed child does not automatically fail the parent unless you await all results. Always await child handles and handle errors explicitly to catch child workflow failures.
Fast/Slow Retries pitfall: setting MaximumAttempts in phase 2
If you set a finite MaximumAttempts in the slow phase, it will eventually exhaust and propagate a failure to the Workflow. Only add a limit if the business process has a defined maximum wait time; in that case, pair it with a ScheduleToCloseTimeout to make the budget explicit.
Fast/Slow Retries phase 2 execution
Phase 2 (Slow retries) is triggered when the fast retry policy is exhausted. The Workflow catches the ActivityError and executes the Activity again with a long InitialInterval and unlimited MaximumAttempts. The Temporal Service owns the slow retry management; the Workflow blocks until the Activity eventually succeeds.
Fast/Slow Retries phase 1 execution
Phase 1 (Fast retries) executes the Activity with a short InitialInterval and bounded MaximumAttempts. This phase recovers from transient errors within seconds or minutes. If the Activity succeeds during fast phase, the Workflow returns the result immediately.
Fast/Slow Retries pattern overview
The Fast/Slow Retries pattern orchestrates two retry phases in a Workflow: a fast phase with short intervals and bounded attempts for transient errors, followed by a slow phase with long intervals and unlimited retries for extended outages. Use this when a single RetryPolicy should not cover both brief blips and hour-long outages or maintenance windows.
Fast/Slow Retries outer bound with timeout
Phase 2 runs indefinitely by default. If the business process has a maximum wait time, add a ScheduleToCloseTimeout or use a Workflow execution timeout to impose an outer bound.
Fast/Slow Retries pitfall: catching too broadly in phase 1
Catch ActivityError specifically. Catching all exceptions in Phase 1 may swallow errors that should propagate immediately, such as CancelledError in Python or a PanicError in Go.
Fast/Slow Retries pitfall: exponential backoff in phase 2
Do not use exponential backoff in Phase 2. The default BackoffCoefficient is 2.0, which doubles the interval with each attempt. Set BackoffCoefficient=1.0 in the slow phase to keep the interval fixed and predictable.