-
Notifications
You must be signed in to change notification settings - Fork 1.8k
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
Fix recursion issue on Skip #3524
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -133,13 +133,7 @@ func (t *ResolvedPipelineRunTask) checkParentsDone(facts *PipelineRunFacts) bool | |
return true | ||
} | ||
|
||
// Skip returns true if a PipelineTask will not be run because | ||
// (1) its When Expressions evaluated to false | ||
// (2) its Condition Checks failed | ||
// (3) its parent task was skipped | ||
// (4) Pipeline is in stopping state (one of the PipelineTasks failed) | ||
// Note that this means Skip returns false if a conditionCheck is in progress | ||
func (t *ResolvedPipelineRunTask) Skip(facts *PipelineRunFacts) bool { | ||
func (t *ResolvedPipelineRunTask) skip(facts *PipelineRunFacts) bool { | ||
if facts.isFinalTask(t.PipelineTask.Name) || t.IsStarted() { | ||
return false | ||
} | ||
|
@@ -151,6 +145,22 @@ func (t *ResolvedPipelineRunTask) Skip(facts *PipelineRunFacts) bool { | |
return false | ||
} | ||
|
||
// Skip returns true if a PipelineTask will not be run because | ||
// (1) its When Expressions evaluated to false | ||
// (2) its Condition Checks failed | ||
// (3) its parent task was skipped | ||
// (4) Pipeline is in stopping state (one of the PipelineTasks failed) | ||
// Note that this means Skip returns false if a conditionCheck is in progress | ||
func (t *ResolvedPipelineRunTask) Skip(facts *PipelineRunFacts) bool { | ||
if facts.SkipCache == nil { | ||
facts.SkipCache = make(map[string]bool) | ||
} | ||
if _, cached := facts.SkipCache[t.PipelineTask.Name]; !cached { | ||
facts.SkipCache[t.PipelineTask.Name] = t.skip(facts) // t.skip() is same as our existing t.Skip() | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Suggest removing the comment now that the original There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. fixed |
||
} | ||
return facts.SkipCache[t.PipelineTask.Name] | ||
} | ||
|
||
func (t *ResolvedPipelineRunTask) conditionsSkip() bool { | ||
if len(t.ResolvedConditionChecks) > 0 { | ||
if t.ResolvedConditionChecks.IsDone() && !t.ResolvedConditionChecks.IsSuccess() { | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -37,6 +37,16 @@ type PipelineRunFacts struct { | |
State PipelineRunState | ||
TasksGraph *dag.Graph | ||
FinalTasksGraph *dag.Graph | ||
|
||
// SkipCache is a hash of PipelineTask names that stores whether a task will be | ||
// executed or not, because it's either not reachable via the DAG due to the pipeline | ||
// state, or because it has failed conditions. | ||
// We cache this data along the state, because it's expensive to compute, it requires | ||
// traversing potentially the whole graph; this way it can built incrementally, when | ||
// needed, via the `Skip` method in pipelinerunresolution.go | ||
// The skip data is sensitive to changes in the state. The ResetSkippedCache method | ||
// can be used to clean the cache and force re-computation when needed. | ||
SkipCache map[string]bool | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. we might be able to instantiate this cache based on I will not block this PR for |
||
} | ||
|
||
// pipelineRunStatusCount holds the count of successful, failed, cancelled, skipped, and incomplete tasks | ||
|
@@ -53,6 +63,11 @@ type pipelineRunStatusCount struct { | |
Incomplete int | ||
} | ||
|
||
// ResetSkippedCache resets the skipped cache in the facts map | ||
func (facts *PipelineRunFacts) ResetSkippedCache() { | ||
facts.SkipCache = make(map[string]bool) | ||
} | ||
|
||
// ToMap returns a map that maps pipeline task name to the resolved pipeline run task | ||
func (state PipelineRunState) ToMap() map[string]*ResolvedPipelineRunTask { | ||
m := make(map[string]*ResolvedPipelineRunTask) | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this significantly reduces the call to
dag.visit
and makes it possible for the unit test in this PR to complete on average under five seconds. The mysterious dot notation indag.visit
is still unsolved though:pipeline/pkg/reconciler/pipeline/dag/dag.go
Line 145 in 747f4ba
Its creating a link between two nodes which are indirectly connected (
C.A
inA -> B -> C
) but where/how is this data being utilized is a mystery.