> ## Documentation Index
> Fetch the complete documentation index at: https://mintlify.com/temporalio/temporal/llms.txt
> Use this file to discover all available pages before exploring further.

# Workflow Updates

> Safely update running workflows with validation and rollback support

## Overview

Workflow Update combines the capabilities of Signals and Queries in a single API call:

* **Bidirectional** - Send data to workflow and receive results back
* **Validated** - Workflow can reject updates before processing
* **Efficient** - Rejected updates leave no trace in workflow history
* **Synchronous** - Caller blocks until update is accepted or rejected

<Info>
  Workflow Update is a complex feature that acts as a proxy between the API caller and workflow code, enabling workflows to expose custom APIs.
</Info>

## Update vs Signal vs Query

<CardGroup cols={3}>
  <Card title="Signal" icon="paper-plane">
    **Fire-and-forget**

    * Cannot be rejected
    * Always writes events
    * No return value
    * Cannot know if processed
  </Card>

  <Card title="Query" icon="magnifying-glass">
    **Read-only**

    * Cannot modify state
    * Returns data
    * No history events
    * Synchronous response
  </Card>

  <Card title="Update" icon="arrows-rotate">
    **Read-write with validation**

    * Can be rejected
    * Only accepted updates write events
    * Returns data
    * Synchronous accept/reject
  </Card>
</CardGroup>

## Key Requirement: No Persistence on Reject

Updates must be "cheap" when rejected:

1. **No "Update Received" event** - Updates arrive as Messages, not Events
2. **No "Update Rejected" event** - Rejected updates simply disappear
3. **First event is "Update Accepted"** - Contains the original request payload
4. **Update outcome in "Update Completed" event** - Success or failure result
5. **Speculative Workflow Task** - Task to ship update is not persisted in mutable state

<Warning>
  Update rejection must leave no traces in workflow history. This requirement drives much of the implementation complexity.
</Warning>

## Update Registry

Updates are managed through the `update.Registry` interface:

* **Location**: `workflow.ContextImpl` struct
* **Stores**: Admitted and accepted updates (in-flight only)
* **Completed updates**: Accessed through `UpdateStore` interface
* **Mutable state**: Contains `UpdateInfo` map linking ID to acceptance/completion info

### Update States

```mermaid theme={null}
stateDiagram-v2
    [*] --> Admitted: Update request arrives
    Admitted --> Accepted: Workflow accepts
    Admitted --> Rejected: Workflow rejects
    Accepted --> Completed: Update handler returns
    Accepted --> Failed: Update handler throws
    Rejected --> [*]: No history trace
    Completed --> [*]: Event written
    Failed --> [*]: Event written
```

## Update Lifecycle

<Steps>
  <Step title="Client sends update request">
    Request arrives at Frontend service via `UpdateWorkflowExecution` API.

    ```go theme={null}
    resp, err := client.UpdateWorkflow(ctx, &workflowpb.UpdateWorkflowExecutionRequest{
        Namespace: "my-namespace",
        WorkflowExecution: &commonpb.WorkflowExecution{
            WorkflowId: "my-workflow",
            RunId: runId,
        },
        Request: &updatepb.Request{
            Meta: &updatepb.Meta{UpdateId: "update-1"},
            Input: &updatepb.Input{Name: "myUpdate", Args: args},
        },
    })
    ```
  </Step>

  <Step title="Update admitted to registry">
    History service admits update to the registry. Update is now in-memory only.

    * No persistence write at this stage
    * Stored in `update.Registry`
    * Linked to workflow execution
  </Step>

  <Step title="Speculative workflow task created">
    A speculative (non-persisted) workflow task is created to ship the update to a worker.

    See [Workflow Lifecycle](/architecture/workflow-lifecycle) for details.
  </Step>

  <Step title="Worker receives update via message">
    Update is shipped to worker as a Message (not an Event).

    Worker can:

    * Accept the update (validation passed)
    * Reject the update (validation failed)
  </Step>

  <Step title="Worker responds with acceptance or rejection">
    **If accepted**: `WorkflowExecutionUpdateAcceptedEvent` written to history

    **If rejected**: Update disappears with no history trace
  </Step>

  <Step title="Update handler executes (if accepted)">
    Workflow code executes the update handler.

    Handler can:

    * Complete successfully with result
    * Fail with error
  </Step>

  <Step title="Update completed">
    `WorkflowExecutionUpdateCompletedEvent` written with outcome (success or failure).

    Client receives the result or error.
  </Step>
</Steps>

## Message Protocol

Updates use the [Message Protocol](/architecture/workflow-lifecycle) instead of Events:

* **Messages** - Arbitrary data shipped to worker outside history events
* **Commands** - Must produce events, so cannot be used for updates
* **Update request** - Shipped as `Message` to avoid events on rejection
* **Update outcome** - Cannot use Commands (would force event creation)

<Info>
  The Message Protocol was introduced specifically to support Update's "no event on reject" requirement.
</Info>

## Speculative Workflow Tasks

Updates rely on speculative workflow tasks:

* **Not persisted** in mutable state
* **Transient** - Exist only to ship the update
* **Converted** to normal task if update is accepted
* **Discarded** if update is rejected

<Accordion title="Why speculative tasks?">
  Normal workflow tasks must be persisted before being sent to workers. If an update is rejected, we cannot have any persisted state. Speculative tasks are created in-memory only and are either promoted to normal tasks (on accept) or discarded (on reject).
</Accordion>

## Update Validation

Workflows can validate updates before accepting:

```go theme={null}
// Worker-side validation example
func (w *Workflow) validateUpdate(ctx workflow.Context, args UpdateArgs) error {
    // Validate inputs
    if args.Amount < 0 {
        return fmt.Errorf("amount must be positive")
    }
    
    // Validate state
    if w.isCompleted {
        return fmt.Errorf("workflow already completed")
    }
    
    return nil // Accept
}

func (w *Workflow) handleUpdate(ctx workflow.Context, args UpdateArgs) (UpdateResult, error) {
    // Update handler executes after validation passes
    w.balance += args.Amount
    return UpdateResult{NewBalance: w.balance}, nil
}
```

## Update Events

### WorkflowExecutionUpdateAcceptedEvent

Written when update is accepted:

<ResponseField name="updateId" type="string">
  Unique identifier for the update
</ResponseField>

<ResponseField name="request" type="UpdateRequest">
  Original update request including input payload
</ResponseField>

<ResponseField name="acceptedRequestMessageId" type="string">
  Message ID from the workflow task that accepted it
</ResponseField>

### WorkflowExecutionUpdateCompletedEvent

Written when update completes:

<ResponseField name="updateId" type="string">
  Identifier matching the accepted event
</ResponseField>

<ResponseField name="outcome" type="Outcome">
  Success or failure result from update handler
</ResponseField>

<ResponseField name="meta" type="UpdateMeta">
  Metadata about the update execution
</ResponseField>

## In-Memory Queue

Updates use the in-memory queue for speculative tasks:

* **Purpose**: Schedule speculative workflow tasks without persistence
* **Location**: `service/history/queues/inmemory_queue.go`
* **Behavior**: Tasks exist only in memory until promoted or discarded

See [Workflow Lifecycle](/architecture/workflow-lifecycle) for implementation details.

## Effect Package

Update implementation uses the `effect` package for managing side effects:

* **Purpose**: Defer and batch side effects until commit
* **Location**: `service/history/workflow/effect/`
* **Usage**: Ensures update acceptance/rejection is atomic

See [Workflow Lifecycle](/architecture/workflow-lifecycle) for details on effect management.

## Best Practices

<AccordionGroup>
  <Accordion title="Keep validation fast" icon="gauge-high">
    Update validation should be quick since the client is blocked waiting.

    * Avoid expensive computations in validators
    * Don't call activities from validators
    * Return rejection quickly if validation fails
  </Accordion>

  <Accordion title="Use idempotent update IDs" icon="fingerprint">
    Provide idempotent update IDs to safely retry:

    * Use deterministic IDs (e.g., based on request data)
    * Server deduplicates updates with same ID
    * Enables safe retry on client timeout
  </Accordion>

  <Accordion title="Handle update failures gracefully" icon="shield">
    Update handlers can fail - design for this:

    * Return meaningful error messages
    * Distinguish validation failures from execution failures
    * Client receives failure in response
  </Accordion>

  <Accordion title="Don't overuse updates" icon="triangle-exclamation">
    Updates are powerful but complex:

    * Use Signals if you don't need return values
    * Use Queries if you don't need to modify state
    * Updates add overhead - use judiciously
  </Accordion>
</AccordionGroup>

## Monitoring

Key metrics for update operations:

* **update\_admitted\_total** - Total updates admitted
* **update\_accepted\_total** - Updates accepted by workflows
* **update\_rejected\_total** - Updates rejected by workflows
* **update\_completed\_total** - Updates completed successfully
* **update\_failed\_total** - Updates that failed during execution
* **update\_latency** - Time from admission to completion

## Limitations

<Warning>
  * **No update on closed workflows** - Cannot update completed/terminated workflows
  * **Limited concurrent updates** - Default limit of 10 in-flight updates per workflow
  * **No update history introspection** - Cannot list all updates sent to a workflow
  * **Speculative task overhead** - Each update creates a workflow task
</Warning>

## See Also

<CardGroup cols={2}>
  <Card title="Workflow Lifecycle" href="/architecture/workflow-lifecycle">
    Understand speculative tasks and message protocol
  </Card>

  <Card title="Event Sourcing" href="/architecture/event-sourcing">
    Learn how update events are stored
  </Card>
</CardGroup>
