Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

handle state machine deletion for state-based replication #7177

Merged
merged 7 commits into from
Feb 7, 2025

Conversation

hai719
Copy link
Contributor

@hai719 hai719 commented Jan 29, 2025

What changed?

Handle state machine deletion for state-based replication.

Why?

Deletion is needed as we want to provide support for more nexus operations.

How did you test it?

unit test.

Potential risks

Documentation

Is hotfix candidate?

@@ -4264,6 +4264,29 @@ func (ms *MutableStateImpl) AddWorkflowExecutionUpdateAdmittedEvent(request *upd
return event, nil
}

func (ms *MutableStateImpl) DeleteSubStateMachine(path *persistencespb.StateMachinePath) error {
incomingPath := []hsm.Key{}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
incomingPath := []hsm.Key{}
incomingPath := make([]hsm.Key, len(path))

And then you can just assign with the index.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

updated

ms.logDataInconsistency()
return nil
}
return root.DeleteChild(node.Key)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You'd need to find the parent of the node to delete the immediate child.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

updated

@@ -7265,41 +7288,8 @@ func (ms *MutableStateImpl) syncExecutionInfo(current *persistencespb.WorkflowEx
}

func (ms *MutableStateImpl) syncSubStateMachinesByType(incoming map[string]*persistencespb.StateMachineMap) error {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@yycptt do you see an issue with this? I assume that we always just want to do a full sync here.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hmm are we still using the TransitionCount field in StateMachineNode? If no, then I think this should work.

We can also remove the PopTask() logic in workflowStateReplicator.applySnapshot I think as we are no longer calling node.Sync which regenerates the tasks.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

when source cluster is generating snapshot, the TransitionCount is reset to 1.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

From the code, looks like TransitionCount is checked in ValidateNotTransitioned, and ValidateNotTransitioned is used only in components/dummy and hsmtest.

@bergundy can you confirm?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We don't use TransitionCount anymore. It's only used in unit tests.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PopTask() removed.

@@ -7265,41 +7288,8 @@ func (ms *MutableStateImpl) syncExecutionInfo(current *persistencespb.WorkflowEx
}

func (ms *MutableStateImpl) syncSubStateMachinesByType(incoming map[string]*persistencespb.StateMachineMap) error {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hmm are we still using the TransitionCount field in StateMachineNode? If no, then I think this should work.

We can also remove the PopTask() logic in workflowStateReplicator.applySnapshot I think as we are no longer calling node.Sync which regenerates the tasks.

@@ -7331,6 +7321,8 @@ func (ms *MutableStateImpl) applyTombstones(tombstoneBatches []*persistencespb.S
if _, ok := ms.pendingSignalInfoIDs[tombstone.GetSignalExternalInitiatedEventId()]; ok {
err = ms.DeletePendingSignal(tombstone.GetSignalExternalInitiatedEventId())
}
case *persistencespb.StateMachineTombstone_StateMachinePath:
err = ms.DeleteSubStateMachine(tombstone.GetStateMachinePath())
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

also need to TrimStateMachineTimers when nodes are being deleted.

I have a TODO in task_refresher.go about this (~L660). Probably need to find a way to trigger the trim only once.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We need to trim every time when we close a transaction, @justinp-tt is working on it.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

add a flag to track if subStateMachine is deleted.

return err
}
ms.logError(
fmt.Sprintf("unable to find path: %v in subStateMachine", incomingPath),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hmm I think this could happen? If the mutation being synced may have a start point older than the workflow's current versioned transition. So some tombstones have already been synced before.

well I guess I just can't prove that situation won't happen... 🤷‍♂️

It's just printing logs so no strong opinion.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

updated.

@bergundy
Copy link
Member

bergundy commented Feb 4, 2025

@hai719 note that you'll need to revert #7163 and uncomment this TODO:

// TODO(hai719): Enable this test once state based replication works with HSM node deletion.
for state based replication and deletion to work.

@hai719 hai719 marked this pull request as ready for review February 6, 2025 20:06
@hai719 hai719 requested a review from a team as a code owner February 6, 2025 20:06
@hai719
Copy link
Contributor Author

hai719 commented Feb 6, 2025

@hai719 note that you'll need to revert #7163 and uncomment this TODO:

// TODO(hai719): Enable this test once state based replication works with HSM node deletion.

for state based replication and deletion to work.

enabled node deletion for state based replication and enabled tests.

@@ -306,12 +306,5 @@ func findOperationNode(root *hsm.Node, event *historypb.HistoryEvent) (*hsm.Node
}

func maybeDeleteNode(node *hsm.Node) error {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can get rid of this function entirely, it's just confusing now.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

removed.

Comment on lines +7378 to +7379
ms.executionInfo.SubStateMachinesByType = incoming
ms.mustInitHSM()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just please make sure that we regenerate the relevant timers from mutable state and delete any timers for state machines that were deleted during the full sync.
The important thing to note here is that the state machine timer group has a "scheduled" flag that indicates that there's a corresponding task in the queue, we want to make sure we don't regenerate the already scheduled tasks.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

updated as discussed offline.

if err != nil {
return err
}
ms.subStateMachineDeleted = true
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't see this being reset anywhere.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

reset in cleanupTransaction()

@hai719 hai719 requested a review from bergundy February 7, 2025 00:16
@@ -36,10 +37,16 @@ import (
// AddNextStateMachineTimerTask generates a state machine timer task if the first deadline doesn't have a task scheduled
// yet.
func AddNextStateMachineTimerTask(ms MutableState) {
timers := ms.GetExecutionInfo().StateMachineTimers
// filter out empty timer groups
timers := util.FilterSlice(ms.GetExecutionInfo().StateMachineTimers, func(timerGroup *persistencespb.StateMachineTimerGroup) bool {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: I think you can use slices.DeleteFunc here but not critical.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

updated

@hai719 hai719 enabled auto-merge (squash) February 7, 2025 01:29
@hai719 hai719 merged commit 9a0114b into main Feb 7, 2025
50 checks passed
@hai719 hai719 deleted the hai719/node_deletion_for_state branch February 7, 2025 01:31
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants