Recover orphaned child workflows after force failover - #11388
Open
jiechenz wants to merge 2 commits into
Open
Conversation
Allow a parent to mark an open child from a losing initiation as zombie and create its replacement atomically when the reuse policy permits. Validate ownership and initiation metadata under the child lock while preserving normal deduplication for accepted children.
There was a problem hiding this comment.
Pull request overview
Enables a guarded recovery path for “orphaned child” workflow ID collisions after force failover by optionally zombifying the conflicting child (after validating parent ownership/initiations under the child lock) and atomically creating a replacement child run.
Changes:
- Added a namespace-scoped dynamic config
EnableOrphanedChildWorkflowReplacement(default disabled) and wired it into History service config. - Extended History StartWorkflowExecution internal request with
zombify_conflicting_childand implemented atomic zombify + replace logic in duplicate workflow ID resolution. - Added unit + functional coverage, including an NDC reproduction suite for force-failover orphan scenarios.
Reviewed changes
Copilot reviewed 9 out of 10 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
tests/ndc/child_workflow_force_failover_test.go |
New functional NDC test suite reproducing and validating orphaned-child replacement behavior across multiple child-history states. |
service/history/transfer_queue_active_task_executor.go |
Adds decision logic for when to request orphaned-child zombify on child-start conflicts; refactors child start call plumbing. |
service/history/transfer_queue_active_task_executor_test.go |
Adds unit coverage for the zombify eligibility gate (canZombifyConflictingChild). |
service/history/configs/config.go |
Adds/wires the new namespace-scoped dynamic config into History service config. |
service/history/api/workflow_id_dedup.go |
Introduces ZombifyConflictingChildAction with validation under the conflicting child lock and state transition to zombie. |
service/history/api/workflow_id_dedup_test.go |
Adds unit tests for the zombify action validation and state transition behavior. |
service/history/api/startworkflow/api.go |
Routes eligible duplicate-start conflicts to zombify action based on request flag/policy/state. |
proto/internal/temporal/server/api/historyservice/v1/request_response.proto |
Adds zombify_conflicting_child to internal StartWorkflowExecutionRequest. |
common/dynamicconfig/constants.go |
Defines the new dynamic config key and documentation. |
api/historyservice/v1/request_response.pb.go |
Regenerated protobuf output for the new request field. |
Files not reviewed (1)
- api/historyservice/v1/request_response.pb.go: Generated file
Comment on lines
+1217
to
+1222
| for initiatedEventID, pendingChild := range mutableState.GetPendingChildExecutionInfos() { | ||
| if initiatedEventID != childInfo.GetInitiatedEventId() && | ||
| pendingChild.GetStartedWorkflowId() == childInfo.GetStartedWorkflowId() { | ||
| return false | ||
| } | ||
| } |
Contributor
Author
There was a problem hiding this comment.
Not valid, different target NS feature is disabled. Parent and child can only live in the same NS.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What changed?
Allow a parent to mark an open child from a losing initiation as zombie and create its replacement atomically when the reuse policy permits.
Validate ownership and initiation metadata under the child lock while preserving normal deduplication for accepted children.
EnableOrphanedChildWorkflowReplacement, disabled by default.Why?
After a force failover, the new active cluster may accept a parent branch that does not contain the initiation responsible for an already-replicated child. Retrying the child start then fails with a workflow ID conflict, leaving the parent unable to make progress.
The conflicting child cannot safely be relinked because it belongs to a losing initiation. Marking it zombie prevents it from making progress on the new active cluster, while atomically creating a replacement lets the accepted parent branch continue.
How did you test it?
Potential risks
The losing child remains in zombie state until replication catches it up or closes it.