fix: Fixed resolutions reaching BLOCKED_DEADLOCK when a Step's state is modified externally#631
Open
DrRebus wants to merge 1 commit into
Open
fix: Fixed resolutions reaching BLOCKED_DEADLOCK when a Step's state is modified externally#631DrRebus wants to merge 1 commit into
DrRebus wants to merge 1 commit into
Conversation
…is modified externally Signed-off-by: Ruben Tordjman <144785435+DrRebus@users.noreply.github.com>
DrRebus
commented
Apr 29, 2026
| } | ||
|
|
||
| { | ||
| // Making sure to prune steps whose dependencies were updated outside the engine (API, manually in DB, etc) |
Contributor
Author
There was a problem hiding this comment.
We can also perform proactive pruning in the API's handlers whenever a resolution or step is updated, but doing it here also covers updates made in the database directly.
rclsilver
approved these changes
Jun 10, 2026
There was a problem hiding this comment.
Pull request overview
This PR fixes a deadlock scenario where a resolution can incorrectly end up in BLOCKED_DEADLOCK after a step’s state is modified externally (e.g., via API/manual DB edit) by proactively pruning steps at resolution startup so that downstream steps with now-impossible dependency states are moved to PRUNE.
Changes:
- Add a proactive pruning pass in
initialize()before starting execution, to account for dependency/state changes done outside the engine.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Comment on lines
+364
to
+367
| stepsToCheck := map[string]bool{} | ||
| for stepName := range res.Steps { | ||
| stepsToCheck[stepName] = true | ||
| } |
Comment on lines
+362
to
+369
| { | ||
| // Making sure to prune steps whose dependencies were updated outside the engine (API, manually in DB, etc) | ||
| stepsToCheck := map[string]bool{} | ||
| for stepName := range res.Steps { | ||
| stepsToCheck[stepName] = true | ||
| } | ||
| pruneSteps(res, stepsToCheck) | ||
| } |
Comment on lines
+362
to
+369
| { | ||
| // Making sure to prune steps whose dependencies were updated outside the engine (API, manually in DB, etc) | ||
| stepsToCheck := map[string]bool{} | ||
| for stepName := range res.Steps { | ||
| stepsToCheck[stepName] = true | ||
| } | ||
| pruneSteps(res, stepsToCheck) | ||
| } |
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 kind of change does this PR introduce? (Bug fix, feature, docs update, ...)
Bug fix.
What is the current behavior? (You can also link to an open issue here)
Resolutions can end up in the
BLOCKED_DEADLOCKstate when one of their Steps is updated through the API because no pruning is performed.Let's consider a simple task with 3 steps :
Parent,Child1andChild2.Child1has the dependencyParent:DONE,Child2hasParent:CUSTOM_STATE(see attached picture). IfParenthas an issue and can't reach either theDONEorCUSTOM_STATEand we were to update its state manually to theDONEstate for example,Child1could be executed andChild2should reach thePRUNEstate. However, since no pruning is performed at this stage,Child2stays inTODOforever and the resolution becomesBLOCKED_DEADLOCKWhat is the new behavior (if this is a feature change)?
Proactive pruning is performed whenever a resolution is run.
Does this PR introduce a breaking change? (What changes might users need to make in their application due to this PR?)
Not that I am aware of.
Other information: