History Service
The History Service is the core of Temporal’s durable execution engine. It manages individual Workflow Executions, maintains their state, and drives them to completion by coordinating with the Matching Service and Worker processes.Overview
The History Service handles two main types of gRPC requests:- Requests from User Applications: Start, Cancel, Query, Update, Signal, Reset, etc.
- Requests from Workers: Completion of Workflow Tasks and Activity Tasks
For system architecture context, see the Architecture Overview
Core Responsibilities
When handling requests, the History Service:- Determines new History Events that the request implies and appends them to Workflow History
- Creates Transfer Tasks if Workflow or Activity Tasks should be added to Matching Service
- Creates Timer Tasks when the workflow is blocked on a timer or timeout
- Updates Mutable State to reflect the current state of the workflow execution
History Shards
Sharding Architecture
A single Temporal Cluster manages millions of concurrent Workflow Executions by partitioning them into History Shards:- The total number of shards is fixed at cluster creation and cannot be changed
- Each workflow execution is assigned to exactly one shard (based on workflow ID hash)
- Multiple History Service instances run in the cluster, each owning a subset of shards
- Shard ownership is coordinated via the Ringpop membership protocol
Shard Ownership
“Owning” a History Shard means:- Synchronously handling all incoming RPC requests for workflows in that shard
- Asynchronously processing background tasks (timers, transfers, visibility, replication)
- Maintaining in-memory metadata including:
RangeID: Monotonically increasing generation number for fencing- Queue states: Acknowledged/processed positions of each internal queue
Persistence Mapping
With Cassandra, History Shards map 1:1 to partitions of theexecutions table. Similar mappings exist for MySQL, PostgreSQL, and SQLite.
Workflow Execution Mutable State
What is Mutable State?
For every workflow execution, Temporal maintains a collection of data structures called Mutable State that summarizes:- Identities of in-progress activities
- Active timers and their expiration times
- Child workflow executions
- Pending signals and updates
- Current workflow task information
- Execution status and result
Why Cache Mutable State?
While this data could be recomputed from Workflow History Events, doing so would be slow. Therefore:- Mutable State is persisted alongside history events
- Recently accessed executions are cached in memory
- Cache improves latency for active workflows
Persistence Details
Due to Cassandra’s limited RDBMS support (the most important persistence backend), Mutable State is persisted in a single row with a layout similar to its in-memory representation.Workflow Execution History
Event Structure
Workflow Execution History is a linear sequence of History Events (or a branching topology for reset workflows):- Each event has an EventID (monotonically increasing)
- Some events carry payloads (e.g., activity results, signal data)
- Events are immutable once written
- Events are publicly exposed via API
Event Sourcing Property
The sequence of History Events alone is sufficient to recover:- All Mutable State information
- All tasks relating to the workflow execution
Event Types
Events represent state transitions in workflow execution:WorkflowExecutionStartedWorkflowTaskScheduled,WorkflowTaskStarted,WorkflowTaskCompletedActivityTaskScheduled,ActivityTaskStarted,ActivityTaskCompletedTimerStarted,TimerFiredWorkflowExecutionCompleted,WorkflowExecutionFailed- And many more…
temporal/api/enums/v1/event_type.proto for the complete list.
In Temporal, “event” refers to Workflow History Event, not event-driven architecture events.
RPC Handling
User Application Requests
Handlers for user application requests are defined inservice/history/api/:
StartWorkflow,SignalWorkflow,UpdateWorkflowCancelWorkflow,TerminateWorkflowQueryWorkflow,DescribeWorkflowResetWorkflow
Worker Completion Requests
Handlers for worker completion requests:RespondWorkflowTaskCompleted
- Contains a sequence of Commands:
StartTimer,ScheduleActivityTask,StartChildWorkflowExecution, etc. - See
temporal/api/enums/v1/command_type.proto
RespondActivityTaskCompleted
- Contains the result of the activity
RespondWorkflowTaskFailed,RespondActivityTaskFailed, etc.
Queue Processing
Queue Types
Each History Shard manages several internal task queues:- Transfer Queue: Immediate execution tasks
- Timer Queue: Scheduled execution tasks
- Visibility Queue: Update visibility store
- Replication Queue: Cross-cluster replication
- Archival Queue: Archive history to long-term storage
Queue Processor Architecture
When the History Service starts, for each owned shard:- A
QueueProcessorstarts for each queue type - Multiple
Readergoroutines read tasks from persistence - Tasks are submitted to a shared task execution framework
- Goroutine pool executes tasks across all shards
- Queue “ack levels” are periodically checkpointed
Transfer Queue
Transfer Tasks are available for immediate execution:- Enqueue Workflow Task in Matching Service
- Enqueue Activity Task in Matching Service
- Start Child Workflow Execution
- Cancel External Workflow Execution
- Signal External Workflow Execution
- Delete Workflow Execution
Timer Queue
Timer Tasks become available at their trigger time:- User Timer Timeout:
workflow.sleep()timer expires - Activity Timeout: Schedule-to-start, start-to-close, heartbeat timeouts
- Workflow Task Timeout: Workflow task not completed in time
- Workflow Timeout: Workflow execution timeout
- Delete History Event: Retention period expired
Visibility Queue
Visibility Tasks update workflow metadata in the visibility storage:StartWorkflowExecution: Record new workflowCloseWorkflowExecution: Record workflow completionUpsertWorkflowSearchAttributes: Update search attributes
State Transitions
State Transition Pattern
A workflow execution state transition follows this pattern: All state transitions use the same implementation pathway:- In-memory: Create new History Event(s), update Mutable State, create History Tasks
- Persistence: Append History Events to storage
- Atomically: Update Mutable State and add History Tasks in a database transaction
State Transition Call Sites
RPC from User Application:Consistency Guarantees
Temporal maintains strong consistency through:Database Transactions
Database Transactions
Mutable State and History Tasks are persisted atomically using database transactions, ensuring they are always consistent with each other.
History Event Validation
History Event Validation
Mutable State stores the identity of the latest History Event. An event is only “valid” if it’s reflected in Mutable State. On failure to persist, we reload from persistence.
Transactional Outbox Pattern
Transactional Outbox Pattern
Transfer Tasks written by a History Shard will eventually result in the required Workflow or Activity Task being created in Matching Service. This is the Transactional Outbox pattern.
Example: Simple Workflow Execution
Here’s how a simple workflow that calls an activity is processed:Additional Responsibilities
The History Service has many other responsibilities not covered in detail here:- Shard Membership and Ownership: Managing which service instance owns which shards
- Replication: Cross-cluster replication and conflict resolution
- Visibility: Updating visibility storage for workflow search
- Archival: Archiving histories to long-term storage
- Workflow Reset: Resetting workflow execution to a previous point
Further Reading
Workflow Lifecycle
Detailed sequence diagrams of workflow execution
Matching Service
How tasks are distributed to workers
Event Sourcing
How Temporal implements event sourcing
Architecture Overview
High-level system architecture