Files
tasks/service/history/workflow/mutable_state_rebuilder.go
Yichao YangandGitHub 03a8fcf76d Avoid event loading for start child task refresh (#7977)
## What changed?
- Avoid event loading for start child task refresh

## Why?
- The information needed is already available from mutable state,
loading event is unnecessary.
- We may need to generate start child task for lots of child workflows
when refreshing workflow tasks, loading event for each event will cause
the operation to timeout.

## How did you test it?
- [x] built
- [ ] run locally and tested manually
- [x] covered by existing tests
- [ ] added new unit test(s)
- [ ] added new functional test(s)

## Risks
- If we ever have an old temporal version where target namespace
information is stored only in events but not in mutable state, then this
change will break task refresh for workflows created by that old version
(and the refreshed task will try to start child in the parent
namespace). From git history, there's no such version.
2025-07-01 14:38:42 -07:00

747 lines
21 KiB
Go

// Code generated: TODO put <- here to avoid linter, this file need to be rewritten
//go:generate mockgen -package $GOPACKAGE -source $GOFILE -destination mutable_state_rebuilder_mock.go
package workflow
import (
"context"
"github.com/pborman/uuid"
commonpb "go.temporal.io/api/common/v1"
enumspb "go.temporal.io/api/enums/v1"
historypb "go.temporal.io/api/history/v1"
"go.temporal.io/api/serviceerror"
enumsspb "go.temporal.io/server/api/enums/v1"
"go.temporal.io/server/common/cluster"
"go.temporal.io/server/common/log"
"go.temporal.io/server/common/namespace"
"go.temporal.io/server/common/persistence/versionhistory"
"go.temporal.io/server/common/primitives/timestamp"
"go.temporal.io/server/service/history/historybuilder"
historyi "go.temporal.io/server/service/history/interfaces"
)
type (
MutableStateRebuilder interface {
ApplyEvents(
ctx context.Context,
namespaceID namespace.ID,
requestID string,
execution *commonpb.WorkflowExecution,
history [][]*historypb.HistoryEvent,
newRunHistory []*historypb.HistoryEvent,
newRunID string,
) (historyi.MutableState, error)
}
MutableStateRebuilderImpl struct {
shard historyi.ShardContext
clusterMetadata cluster.Metadata
namespaceRegistry namespace.Registry
logger log.Logger
mutableState historyi.MutableState
}
)
const (
// ErrMessageHistorySizeZero indicate that history is empty
ErrMessageHistorySizeZero = "encounter history size being zero"
)
var _ MutableStateRebuilder = (*MutableStateRebuilderImpl)(nil)
func NewMutableStateRebuilder(
shard historyi.ShardContext,
logger log.Logger,
mutableState historyi.MutableState,
) *MutableStateRebuilderImpl {
return &MutableStateRebuilderImpl{
shard: shard,
clusterMetadata: shard.GetClusterMetadata(),
namespaceRegistry: shard.GetNamespaceRegistry(),
logger: logger,
mutableState: mutableState,
}
}
func (b *MutableStateRebuilderImpl) ApplyEvents(
ctx context.Context,
namespaceID namespace.ID,
requestID string,
execution *commonpb.WorkflowExecution,
history [][]*historypb.HistoryEvent,
newRunHistory []*historypb.HistoryEvent,
newRunID string,
) (historyi.MutableState, error) {
for i := 0; i < len(history)-1; i++ {
_, err := b.applyEvents(ctx, namespaceID, requestID, execution, history[i], nil, "")
if err != nil {
return nil, err
}
}
newMutableState, err := b.applyEvents(ctx, namespaceID, requestID, execution, history[len(history)-1], newRunHistory, newRunID)
if err != nil {
return nil, err
}
// TODO: There doesn't seem to be a good reason to generate tasks here since they'll be generated eventually when we
// close the transaction.
// Previously this comment was here: must generate the activity timer / user timer at the very end
taskGenerator := taskGeneratorProvider.NewTaskGenerator(b.shard, b.mutableState)
if err := taskGenerator.GenerateActivityTimerTasks(); err != nil {
return nil, err
}
if err := taskGenerator.GenerateUserTimerTasks(); err != nil {
return nil, err
}
b.mutableState.SetHistoryBuilder(historybuilder.NewImmutable(history...))
return newMutableState, nil
}
func (b *MutableStateRebuilderImpl) applyEvents(
ctx context.Context,
namespaceID namespace.ID,
requestID string,
execution *commonpb.WorkflowExecution,
history []*historypb.HistoryEvent,
newRunHistory []*historypb.HistoryEvent,
newRunID string,
) (historyi.MutableState, error) {
if len(history) == 0 {
return nil, serviceerror.NewInternal(ErrMessageHistorySizeZero)
}
firstEvent := history[0]
lastEvent := history[len(history)-1]
taskGenerator := taskGeneratorProvider.NewTaskGenerator(b.shard, b.mutableState)
// Need to clear the sticky task queue because workflow turned to passive.
b.mutableState.ClearStickyTaskQueue()
executionInfo := b.mutableState.GetExecutionInfo()
executionInfo.LastFirstEventId = firstEvent.GetEventId()
// NOTE: stateRebuilder is also being used in the active side
if err := b.mutableState.UpdateCurrentVersion(lastEvent.GetVersion(), true); err != nil {
return nil, err
}
versionHistories := executionInfo.GetVersionHistories()
versionHistory, err := versionhistory.GetCurrentVersionHistory(versionHistories)
if err != nil {
return nil, err
}
if err := versionhistory.AddOrUpdateVersionHistoryItem(versionHistory, versionhistory.NewVersionHistoryItem(
lastEvent.GetEventId(),
lastEvent.GetVersion(),
)); err != nil {
return nil, err
}
executionInfo.LastRunningClock = lastEvent.GetTaskId()
for _, event := range history {
switch event.GetEventType() {
case enumspb.EVENT_TYPE_WORKFLOW_EXECUTION_STARTED:
attributes := event.GetWorkflowExecutionStartedEventAttributes()
// TODO (alex): ParentWorkflowNamespaceId is back filled. Backward compatibility: old event doesn't have ParentNamespaceId set.
if attributes.GetParentWorkflowNamespaceId() == "" && attributes.GetParentWorkflowNamespace() != "" {
parentNamespaceEntry, err := b.namespaceRegistry.GetNamespace(namespace.Name(attributes.GetParentWorkflowNamespace()))
if err != nil {
return nil, err
}
attributes.ParentWorkflowNamespaceId = parentNamespaceEntry.ID().String()
}
if err := b.mutableState.ApplyWorkflowExecutionStartedEvent(
nil, // shard clock is local to cluster
execution,
requestID,
event,
); err != nil {
return nil, err
}
if err := taskGenerator.GenerateRecordWorkflowStartedTasks(
event,
); err != nil {
return nil, err
}
var err error
executionInfo.WorkflowExecutionTimerTaskStatus, err = taskGenerator.GenerateWorkflowStartTasks(
event,
)
if err != nil {
return nil, err
}
if timestamp.DurationValue(attributes.GetFirstWorkflowTaskBackoff()) > 0 {
if err := taskGenerator.GenerateDelayedWorkflowTasks(
event,
); err != nil {
return nil, err
}
}
if err := b.mutableState.SetHistoryTree(
executionInfo.WorkflowExecutionTimeout,
executionInfo.WorkflowRunTimeout,
execution.GetRunId(),
); err != nil {
return nil, err
}
case enumspb.EVENT_TYPE_WORKFLOW_TASK_SCHEDULED:
attributes := event.GetWorkflowTaskScheduledEventAttributes()
// use event.GetEventTime() as WorkflowTaskOriginalScheduledTimestamp, because the heartbeat is not happening here.
workflowTask, err := b.mutableState.ApplyWorkflowTaskScheduledEvent(
event.GetVersion(),
event.GetEventId(),
attributes.TaskQueue,
attributes.GetStartToCloseTimeout(),
attributes.GetAttempt(),
event.GetEventTime(),
event.GetEventTime(),
enumsspb.WORKFLOW_TASK_TYPE_NORMAL, // speculative workflow tasks are not replicated.
)
if err != nil {
return nil, err
}
// since we do not use stickiness on the standby side
// there shall be no workflowTask schedule to start timeout
// NOTE: at the beginning of the loop, stickyness is cleared
if err := taskGenerator.GenerateScheduleWorkflowTaskTasks(
workflowTask.ScheduledEventID,
); err != nil {
return nil, err
}
case enumspb.EVENT_TYPE_WORKFLOW_TASK_STARTED:
attributes := event.GetWorkflowTaskStartedEventAttributes()
workflowTask, err := b.mutableState.ApplyWorkflowTaskStartedEvent(
nil,
event.GetVersion(),
attributes.GetScheduledEventId(),
event.GetEventId(),
attributes.GetRequestId(),
timestamp.TimeValue(event.GetEventTime()),
attributes.GetSuggestContinueAsNew(),
attributes.GetHistorySizeBytes(),
attributes.GetWorkerVersion(),
attributes.GetBuildIdRedirectCounter(),
)
if err != nil {
return nil, err
}
if err := taskGenerator.GenerateStartWorkflowTaskTasks(
workflowTask.ScheduledEventID,
); err != nil {
return nil, err
}
case enumspb.EVENT_TYPE_WORKFLOW_TASK_COMPLETED:
if err := b.mutableState.ApplyWorkflowTaskCompletedEvent(
event,
); err != nil {
return nil, err
}
case enumspb.EVENT_TYPE_WORKFLOW_TASK_TIMED_OUT:
if err := b.mutableState.ApplyWorkflowTaskTimedOutEvent(
event.GetWorkflowTaskTimedOutEventAttributes().GetTimeoutType(),
); err != nil {
return nil, err
}
// this is for transient workflowTask
workflowTask, err := b.mutableState.ApplyTransientWorkflowTaskScheduled()
if err != nil {
return nil, err
}
if workflowTask != nil {
// since we do not use stickiness on the standby side
// there shall be no workflowTask schedule to start timeout
// NOTE: at the beginning of the loop, stickyness is cleared
if err := taskGenerator.GenerateScheduleWorkflowTaskTasks(
workflowTask.ScheduledEventID,
); err != nil {
return nil, err
}
}
case enumspb.EVENT_TYPE_WORKFLOW_TASK_FAILED:
if err := b.mutableState.ApplyWorkflowTaskFailedEvent(); err != nil {
return nil, err
}
// this is for transient workflowTask
workflowTask, err := b.mutableState.ApplyTransientWorkflowTaskScheduled()
if err != nil {
return nil, err
}
if workflowTask != nil {
// since we do not use stickiness on the standby side
// there shall be no workflowTask schedule to start timeout
// NOTE: at the beginning of the loop, stickyness is cleared
if err := taskGenerator.GenerateScheduleWorkflowTaskTasks(
workflowTask.ScheduledEventID,
); err != nil {
return nil, err
}
}
case enumspb.EVENT_TYPE_ACTIVITY_TASK_SCHEDULED:
if _, err := b.mutableState.ApplyActivityTaskScheduledEvent(
firstEvent.GetEventId(),
event,
); err != nil {
return nil, err
}
if err := taskGenerator.GenerateActivityTasks(
event.GetEventId(),
); err != nil {
return nil, err
}
case enumspb.EVENT_TYPE_ACTIVITY_TASK_STARTED:
if err := b.mutableState.ApplyActivityTaskStartedEvent(
event,
); err != nil {
return nil, err
}
case enumspb.EVENT_TYPE_ACTIVITY_TASK_COMPLETED:
if err := b.mutableState.ApplyActivityTaskCompletedEvent(
event,
); err != nil {
return nil, err
}
case enumspb.EVENT_TYPE_ACTIVITY_TASK_FAILED:
if err := b.mutableState.ApplyActivityTaskFailedEvent(
event,
); err != nil {
return nil, err
}
case enumspb.EVENT_TYPE_ACTIVITY_TASK_TIMED_OUT:
if err := b.mutableState.ApplyActivityTaskTimedOutEvent(
event,
); err != nil {
return nil, err
}
case enumspb.EVENT_TYPE_ACTIVITY_TASK_CANCEL_REQUESTED:
if err := b.mutableState.ApplyActivityTaskCancelRequestedEvent(
event,
); err != nil {
return nil, err
}
case enumspb.EVENT_TYPE_ACTIVITY_TASK_CANCELED:
if err := b.mutableState.ApplyActivityTaskCanceledEvent(
event,
); err != nil {
return nil, err
}
case enumspb.EVENT_TYPE_TIMER_STARTED:
if _, err := b.mutableState.ApplyTimerStartedEvent(
event,
); err != nil {
return nil, err
}
case enumspb.EVENT_TYPE_TIMER_FIRED:
if err := b.mutableState.ApplyTimerFiredEvent(
event,
); err != nil {
return nil, err
}
case enumspb.EVENT_TYPE_TIMER_CANCELED:
if err := b.mutableState.ApplyTimerCanceledEvent(
event,
); err != nil {
return nil, err
}
case enumspb.EVENT_TYPE_START_CHILD_WORKFLOW_EXECUTION_INITIATED:
if _, err := b.mutableState.ApplyStartChildWorkflowExecutionInitiatedEvent(
firstEvent.GetEventId(),
event,
); err != nil {
return nil, err
}
if err := taskGenerator.GenerateChildWorkflowTasks(
event.GetEventId(),
); err != nil {
return nil, err
}
case enumspb.EVENT_TYPE_START_CHILD_WORKFLOW_EXECUTION_FAILED:
if err := b.mutableState.ApplyStartChildWorkflowExecutionFailedEvent(
event,
); err != nil {
return nil, err
}
case enumspb.EVENT_TYPE_CHILD_WORKFLOW_EXECUTION_STARTED:
if err := b.mutableState.ApplyChildWorkflowExecutionStartedEvent(
event,
nil, // shard clock is local to cluster
); err != nil {
return nil, err
}
case enumspb.EVENT_TYPE_CHILD_WORKFLOW_EXECUTION_COMPLETED:
if err := b.mutableState.ApplyChildWorkflowExecutionCompletedEvent(
event,
); err != nil {
return nil, err
}
case enumspb.EVENT_TYPE_CHILD_WORKFLOW_EXECUTION_FAILED:
if err := b.mutableState.ApplyChildWorkflowExecutionFailedEvent(
event,
); err != nil {
return nil, err
}
case enumspb.EVENT_TYPE_CHILD_WORKFLOW_EXECUTION_CANCELED:
if err := b.mutableState.ApplyChildWorkflowExecutionCanceledEvent(
event,
); err != nil {
return nil, err
}
case enumspb.EVENT_TYPE_CHILD_WORKFLOW_EXECUTION_TIMED_OUT:
if err := b.mutableState.ApplyChildWorkflowExecutionTimedOutEvent(
event,
); err != nil {
return nil, err
}
case enumspb.EVENT_TYPE_CHILD_WORKFLOW_EXECUTION_TERMINATED:
if err := b.mutableState.ApplyChildWorkflowExecutionTerminatedEvent(
event,
); err != nil {
return nil, err
}
case enumspb.EVENT_TYPE_REQUEST_CANCEL_EXTERNAL_WORKFLOW_EXECUTION_INITIATED:
if _, err := b.mutableState.ApplyRequestCancelExternalWorkflowExecutionInitiatedEvent(
firstEvent.GetEventId(),
event,
// create a new request ID which is used by transfer queue processor
// if namespace is failed over at this point
uuid.New(),
); err != nil {
return nil, err
}
if err := taskGenerator.GenerateRequestCancelExternalTasks(
event,
); err != nil {
return nil, err
}
case enumspb.EVENT_TYPE_REQUEST_CANCEL_EXTERNAL_WORKFLOW_EXECUTION_FAILED:
if err := b.mutableState.ApplyRequestCancelExternalWorkflowExecutionFailedEvent(
event,
); err != nil {
return nil, err
}
case enumspb.EVENT_TYPE_EXTERNAL_WORKFLOW_EXECUTION_CANCEL_REQUESTED:
if err := b.mutableState.ApplyExternalWorkflowExecutionCancelRequested(
event,
); err != nil {
return nil, err
}
case enumspb.EVENT_TYPE_SIGNAL_EXTERNAL_WORKFLOW_EXECUTION_INITIATED:
// Create a new request ID which is used by transfer queue processor if namespace is failed over at this point
signalRequestID := uuid.New()
if _, err := b.mutableState.ApplySignalExternalWorkflowExecutionInitiatedEvent(
firstEvent.GetEventId(),
event,
signalRequestID,
); err != nil {
return nil, err
}
if err := taskGenerator.GenerateSignalExternalTasks(
event,
); err != nil {
return nil, err
}
case enumspb.EVENT_TYPE_SIGNAL_EXTERNAL_WORKFLOW_EXECUTION_FAILED:
if err := b.mutableState.ApplySignalExternalWorkflowExecutionFailedEvent(
event,
); err != nil {
return nil, err
}
case enumspb.EVENT_TYPE_EXTERNAL_WORKFLOW_EXECUTION_SIGNALED:
if err := b.mutableState.ApplyExternalWorkflowExecutionSignaled(
event,
); err != nil {
return nil, err
}
case enumspb.EVENT_TYPE_MARKER_RECORDED:
// No mutable state action is needed
case enumspb.EVENT_TYPE_WORKFLOW_EXECUTION_SIGNALED:
if err := b.mutableState.ApplyWorkflowExecutionSignaled(
event,
); err != nil {
return nil, err
}
case enumspb.EVENT_TYPE_WORKFLOW_EXECUTION_CANCEL_REQUESTED:
if err := b.mutableState.ApplyWorkflowExecutionCancelRequestedEvent(
event,
); err != nil {
return nil, err
}
case enumspb.EVENT_TYPE_UPSERT_WORKFLOW_SEARCH_ATTRIBUTES:
b.mutableState.ApplyUpsertWorkflowSearchAttributesEvent(event)
if err := taskGenerator.GenerateUpsertVisibilityTask(); err != nil {
return nil, err
}
case enumspb.EVENT_TYPE_WORKFLOW_PROPERTIES_MODIFIED:
b.mutableState.ApplyWorkflowPropertiesModifiedEvent(event)
if err := taskGenerator.GenerateUpsertVisibilityTask(); err != nil {
return nil, err
}
case enumspb.EVENT_TYPE_WORKFLOW_EXECUTION_COMPLETED:
if err := b.mutableState.ApplyWorkflowExecutionCompletedEvent(
firstEvent.GetEventId(),
event,
); err != nil {
return nil, err
}
if err := taskGenerator.GenerateWorkflowCloseTasks(
event.GetEventTime().AsTime(),
false,
); err != nil {
return nil, err
}
case enumspb.EVENT_TYPE_WORKFLOW_EXECUTION_FAILED:
if err := b.mutableState.ApplyWorkflowExecutionFailedEvent(
firstEvent.GetEventId(),
event,
); err != nil {
return nil, err
}
if err := taskGenerator.GenerateWorkflowCloseTasks(
event.GetEventTime().AsTime(),
false,
); err != nil {
return nil, err
}
case enumspb.EVENT_TYPE_WORKFLOW_EXECUTION_TIMED_OUT:
if err := b.mutableState.ApplyWorkflowExecutionTimedoutEvent(
firstEvent.GetEventId(),
event,
); err != nil {
return nil, err
}
if err := taskGenerator.GenerateWorkflowCloseTasks(
event.GetEventTime().AsTime(),
false,
); err != nil {
return nil, err
}
case enumspb.EVENT_TYPE_WORKFLOW_EXECUTION_CANCELED:
if err := b.mutableState.ApplyWorkflowExecutionCanceledEvent(
firstEvent.GetEventId(),
event,
); err != nil {
return nil, err
}
if err := taskGenerator.GenerateWorkflowCloseTasks(
event.GetEventTime().AsTime(),
false,
); err != nil {
return nil, err
}
case enumspb.EVENT_TYPE_WORKFLOW_EXECUTION_TERMINATED:
if err := b.mutableState.ApplyWorkflowExecutionTerminatedEvent(
firstEvent.GetEventId(),
event,
); err != nil {
return nil, err
}
if err := taskGenerator.GenerateWorkflowCloseTasks(
event.GetEventTime().AsTime(),
false,
); err != nil {
return nil, err
}
case enumspb.EVENT_TYPE_WORKFLOW_EXECUTION_CONTINUED_AS_NEW:
// This is for backward compatibility, old replication tasks generated for continuedAsNew case
// doesn't have newRunID field set. In that case, we need to get newRunID from the last event.
continuedAsNewRunID := event.GetWorkflowExecutionContinuedAsNewEventAttributes().GetNewExecutionRunId()
if newRunID == "" {
newRunID = continuedAsNewRunID
} else if newRunID != continuedAsNewRunID {
return nil, serviceerror.NewInternalf(
"ApplyEvents encounted newRunID mismatch for continuedAsNew event, task newRunID: %v, event newRunID: %v",
newRunID,
continuedAsNewRunID,
)
}
if err := b.mutableState.ApplyWorkflowExecutionContinuedAsNewEvent(
firstEvent.GetEventId(),
event,
); err != nil {
return nil, err
}
if err := taskGenerator.GenerateWorkflowCloseTasks(
event.GetEventTime().AsTime(),
false,
); err != nil {
return nil, err
}
case enumspb.EVENT_TYPE_WORKFLOW_EXECUTION_UPDATE_ADMITTED:
if err := b.mutableState.ApplyWorkflowExecutionUpdateAdmittedEvent(event, firstEvent.GetEventId()); err != nil {
return nil, err
}
case enumspb.EVENT_TYPE_WORKFLOW_EXECUTION_UPDATE_ACCEPTED:
if err := b.mutableState.ApplyWorkflowExecutionUpdateAcceptedEvent(event); err != nil {
return nil, err
}
case enumspb.EVENT_TYPE_WORKFLOW_EXECUTION_UPDATE_COMPLETED:
if err := b.mutableState.ApplyWorkflowExecutionUpdateCompletedEvent(event, firstEvent.GetEventId()); err != nil {
return nil, err
}
case enumspb.EVENT_TYPE_ACTIVITY_PROPERTIES_MODIFIED_EXTERNALLY,
enumspb.EVENT_TYPE_WORKFLOW_PROPERTIES_MODIFIED_EXTERNALLY:
return nil, serviceerror.NewUnimplemented("Workflow/activity property modification not implemented")
case enumspb.EVENT_TYPE_WORKFLOW_EXECUTION_OPTIONS_UPDATED:
if err := b.mutableState.ApplyWorkflowExecutionOptionsUpdatedEvent(event); err != nil {
return nil, err
}
default:
def, ok := b.shard.StateMachineRegistry().EventDefinition(event.GetEventType())
if !ok {
return nil, serviceerror.NewInvalidArgumentf("Unknown event type: %v", event.GetEventType())
}
if err := def.Apply(b.mutableState.HSM(), event); err != nil {
return nil, err
}
}
}
// The length of newRunHistory can be zero in resend case
if len(newRunHistory) == 0 {
return nil, nil
}
if b.mutableState.GetExecutionState().Status == enumspb.WORKFLOW_EXECUTION_STATUS_RUNNING {
return nil, serviceerror.NewInternal("Cannot apply events for new run when current run is still running")
}
return b.applyNewRunHistory(
ctx,
namespaceID,
&commonpb.WorkflowExecution{
WorkflowId: execution.WorkflowId,
RunId: newRunID,
},
newRunHistory,
)
}
func (b *MutableStateRebuilderImpl) applyNewRunHistory(
ctx context.Context,
namespaceID namespace.ID,
newExecution *commonpb.WorkflowExecution,
newRunHistory []*historypb.HistoryEvent,
) (historyi.MutableState, error) {
// TODO: replication task should contain enough information to determine whether the new run is part of the same chain
// and not relying on a specific event type to make that decision
sameWorkflowChain := false
newRunFirstEvent := newRunHistory[0]
if newRunFirstEvent.GetEventType() == enumspb.EVENT_TYPE_WORKFLOW_EXECUTION_STARTED {
newRunFirstRunID := newRunFirstEvent.GetWorkflowExecutionStartedEventAttributes().FirstExecutionRunId
sameWorkflowChain = newRunFirstRunID == b.mutableState.GetExecutionInfo().FirstExecutionRunId
}
var err error
var newRunMutableState historyi.MutableState
if sameWorkflowChain {
newRunMutableState, err = NewMutableStateInChain(
b.shard,
b.shard.GetEventsCache(),
b.logger,
b.mutableState.GetNamespaceEntry(),
newExecution.WorkflowId,
newExecution.RunId,
timestamp.TimeValue(newRunHistory[0].GetEventTime()),
b.mutableState,
)
if err != nil {
return nil, err
}
} else {
newRunMutableState = NewMutableState(
b.shard,
b.shard.GetEventsCache(),
b.logger,
b.mutableState.GetNamespaceEntry(),
newExecution.WorkflowId,
newExecution.RunId,
timestamp.TimeValue(newRunHistory[0].GetEventTime()),
)
}
newRunStateBuilder := NewMutableStateRebuilder(b.shard, b.logger, newRunMutableState)
_, err = newRunStateBuilder.ApplyEvents(
ctx,
namespaceID,
uuid.New(),
newExecution,
[][]*historypb.HistoryEvent{newRunHistory},
nil,
"",
)
if err != nil {
return nil, err
}
return newRunMutableState, nil
}