-
Notifications
You must be signed in to change notification settings - Fork 219
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
TEP-0059: Skipping Strategies #407
Conversation
700ec7e
to
83cd6e1
Compare
teps/0059-skip-guarded-task-only.md
Outdated
- name: task | ||
``` | ||
|
||
However, it won't be clear that the skipping policies are related to `WhenExpressions` specifically. |
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 alternative can be further refined to align well with TEP-0050.
But, I dont see this as a con, in the entirety, continue on error
be it a process failure or skipped due to when
expressions.
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 alternative can be further refined to align well with TEP-0050.
please share any ideas you have to refine this alternative 😀
But, I dont see this as a con, in the entirety,
continue on error
be it a process failure or skipped due towhen
expressions.
I don't think we'd want to refer to skipping of a task as an error (skipping doesn't cause to pipeline failure)
It'll be more extensible and scalable to pass in the individual execution policies as a list instead of providing execution policies that are combinations of other execution policies, what do you think?
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.
@vdemeester, @sbwsg, @bobcatfish, @afrittoli I'd appreciate your feedback on this alternative as well
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.
I do like the locality of scope
to when
. Is there a risk here that we have collisions in the meaning given by scope
and any meaning given by changes from TEP-0050? For example, are we going to end up in a situation where when.scope
could be branch
but TEP-0050 has introduced a field that circumvents this scope
? And then I guess a follow-up question would be: does this potential conflict of meaning matter?
If we introduce multiple fields that can interact in complex ways like this then we should probably try and get a handle on what those interactions will be and decide if there are design ramifications we can deal with now, or if we'll disallow them entirely through validation, or simply document them, or ... something else.
I went over and re-read TEP-0050 again but because it's at proposal stage atm I'm not totally clear how the concrete implementation there will shake out wrt this feature.
Apologies if I've misunderstood the overlap here!
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.
I do like the locality of
scope
towhen
. Is there a risk here that we have collisions in the meaning given byscope
and any meaning given by changes from TEP-0050? For example, are we going to end up in a situation wherewhen.scope
could bebranch
but TEP-0050 has introduced a field that circumvents thisscope
? And then I guess a follow-up question would be: does this potential conflict of meaning matter?
TEP-0050 is about ignoring Task
failures only (does not include Task
skipping) so I believe that it won't introduce a field that does the same thing as scope
or circumvents scope
If we introduce multiple fields that can interact in complex ways like this then we should probably try and get a handle on what those interactions will be and decide if there are design ramifications we can deal with now, or if we'll disallow them entirely through validation, or simply document them, or ... something else.
If we go forward with scope
under when
, we won't need to add a continueOnSkip
execution policy
Added this alternative because it provides an easily extensible way for users to specify execution policies
to define workflow behavior for each PipelineTask
in one place -- and it'll be well aligned with TEP-0050 which would only add ignoreFailure
execution policy
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.
I went over and re-read TEP-0050 again but because it's at proposal stage atm I'm not totally clear how the concrete implementation there will shake out wrt this feature.
Yup, its a long overdue, hoping to have the proposal in by end of this week 🤞
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.
Ahh OK I think I understand better now - it's not so much whether there's going to be a conflict in functionality but whether consolidating these two concepts under a single section (executionPolicies
) would make sense.
Edit: I made a long rambly post here but in summary I personally prefer when.scope
because of how close it is to the expressions
.
executionPolicies
seems to me like a more general statement on the intended behaviour of the PipelineTask. And here we're dealing very directly with the outcome of a conditional. Putting this under executionPolicies
would be kind of like having an ifElsePolicies
in a programming language which changes the behaviour of an if
statement depending on those policies. From my pov conditionals should be a relatively known quantity - it would be much more difficult to reason about complex bits of code if that were configurable elsewhere. We're not writing a programming language but I do wonder if a similar effect would happen here?
If we go forward with scope under when, we won't need to add a continueOnSkip execution policy
The lingering question on my mind is whether the skips we're discussing here will always be tied to when
. Will there ever come a time when continueOnSkip
makes sense for other scenarios? This is probably not something we can answer right now but I feel like if it does happen we can always introduce continueOnSkip
with semantics that make sense at that time. In other words, maybe one day we consolidate when.scope
with a continueOnSkip
policy, if it makes sense to do so.
All of this to say: I like how closely tied the scope
is to the expressions
and I'm uncertain whether a more general skip policy should apply to the outcome of when
.
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.
@sbwsg you make strong points about the options for an if statement should be relatively known, so should not be defined elsewhere, will include that in the tep as well! (your post wasn't rambly, reading your thought process was helpful! 😁)
/assign |
/assign @sbwsg |
teps/0059-skip-guarded-task-only.md
Outdated
values: [ 'bar' ] | ||
``` | ||
|
||
To enable users to smoothly transition from the old syntax to the new syntax, we will initially support both sytanxes. Then we will deprecate the old syntax and support the new syntax only as we go towards v1 API. |
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 means we will provide a default for scope
— which will be Branch
in order to not break backward compatibility, right ?
If so, any reason for, at some point (in v1) removing the default value ?
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.
@vdemeester no no, that means that we'll initially support both the current syntax and the proposed syntax
current syntax:
when:
- input: 'foo'
operator: in
values: [ 'bar' ]
proposed syntax:
when:
scope: Task / Branch
expressions:
- input: 'foo'
operator: in
values: [ 'bar' ]
then only take the proposed syntax into v1
the proposed syntax would not provide a default for scope
, we'll require users to specify it because they have different expectation/intuition for the default behavior (#388) so being explicit about it ensures no one is surprised
I'd argue that this does not break backwards compatibility because the current syntax would continue working as is for a while until we stop supporting it later, what do you think?
/cc @bobcatfish
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.
oh I can't read properly it seems 😛
Yes it makes sense to me now 😉
teps/0059-skip-guarded-task-only.md
Outdated
values: [ 'bar' ] | ||
``` | ||
|
||
To provide the flexibility to skip a guarded `Task` when its `WhenExpressions` evaluate to `False` while unblocking the execution of its dependent `Tasks`, we propose changing the `when` field from a list to a dictionary and adding `scope` and `expressions` fields under the `when` field. |
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.
Would it be possible to include a snippet of how the PipelineTask or WhenExpressions struct will look in order to support these two shapes? I'm trying to wrap my head around it but don't fully grasp how the dual format can be supported in code.
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.
To support both shapes under when
, we'd detect whether it's a list or dictionary in UnmarshalJSON
that implements the json.Unmarshaller
interface, using the first character (it's ugly but didn't find another way)
We do the same thing in Parameters
to detect whether the type of the value is a String
or Array
:
https://github.com/tektoncd/pipeline/blob/879ba4f65732808a0614d76d5993af0bac736009/pkg/apis/pipeline/v1beta1/param_types.go#L98-L118
Kubernetes does the same thing in IntOrString
to detect whether the type is Int
or String
:
https://github.com/kubernetes/apimachinery/blob/8daf28983e6ecf28bd8271925ee135c1179ad13a/pkg/util/intstr/intstr.go#L80-L99
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.
Oh, awesome, thanks @jerop! I remember us talking about this before as well; sorry I'd completely forgotten about this approach :D
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.
no worries, I can add this detail in the proposal so other reviewers consider it too
teps/0059-skip-guarded-task-only.md
Outdated
- name: task | ||
``` | ||
|
||
However, it won't be clear that the skipping policies are related to `WhenExpressions` specifically. |
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.
I do like the locality of scope
to when
. Is there a risk here that we have collisions in the meaning given by scope
and any meaning given by changes from TEP-0050? For example, are we going to end up in a situation where when.scope
could be branch
but TEP-0050 has introduced a field that circumvents this scope
? And then I guess a follow-up question would be: does this potential conflict of meaning matter?
If we introduce multiple fields that can interact in complex ways like this then we should probably try and get a handle on what those interactions will be and decide if there are design ramifications we can deal with now, or if we'll disallow them entirely through validation, or simply document them, or ... something else.
I went over and re-read TEP-0050 again but because it's at proposal stage atm I'm not totally clear how the concrete implementation there will shake out wrt this feature.
Apologies if I've misunderstood the overlap here!
5ed6e7d
to
ecab855
Compare
/approve |
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 looks like a solid proposal to me, thank you!
Just a note about the deprecation plan / update path.
teps/0059-skip-guarded-task-only.md
Outdated
scope: Task / Branch | ||
expressions: | ||
- input: 'foo' | ||
operator: in | ||
values: [ 'bar' ] |
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.
Any reason for having the scope
at root level and not associated to individual expressions?
This looks fine to me, it keeps things simpler - but I was wondering if there had been any special reasoning about that already.
I think one of the reasons that is not straight forward to express the behaviour of conditions, is because we don't explicitly express / name branches in the pipeline, they're derived from dependencies. Having the scope attached to a pipeline task seems like a good compromise.
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.
Any reason for having the
scope
at root level and not associated to individual expressions?
This looks fine to me, it keeps things simpler - but I was wondering if there had been any special reasoning about that already.
interesting 🤔
we haven't considered this idea yet, will think more about it
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.
After watching the API WG recording, I wanted to clarify I didn't mean to block the TEP on this question :)
It was just not clear to me why the scope was always attached to the list of conditions.
I've been thinking about a few use cases and as long as there is only one branch under the guarded task, it's possible to do translate this:
A -> B (Cond1@task, Cond2@branch) -> C -> D
into:
A -> B (Cond1@task) -> C (Cond2@branch) -> D
If there is more than one branch after B, it is still possible to do the translation, but Cond2
needs to be repeated on the top of each branch. This feels like a reasonable compromise in favour of having a more simple syntax and implementation. Also the proposed syntax still allows for future developments and adding more granularity in future if we decide to.
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.
wasn't blocked on the question, it was more that i wanted us to consider how the proposed solution would extend to support this scenario in the future so was asking if folks in the API working group had use cases to help in this design
thanks for the follow up @afrittoli!
teps/0059-skip-guarded-task-only.md
Outdated
behavior or add a feature that may replace and deprecate a current one. | ||
--> | ||
|
||
To enable users to smoothly transition from the old syntax to the new syntax, we will initially support both sytanxes. Then we will deprecate the old syntax and support the new syntax only as we go towards v1 API. |
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.
I think it would be good to make a more detailed plan about when we need to deprecate the old syntax.
Would the new syntax enter the API as alpha? If so what would be the plan to move to beta and deprecate the old syntax?
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.
will review the feature gates and add more details here
teps/0059-skip-guarded-task-only.md
Outdated
|
||
```yaml | ||
when: | ||
scope: Task |
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.
Is there any default value to scope
here? Or the users are forced to specify either Task
or Branch
?
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.
that's correct - we won't provide a default for scope, we'll require users to specify it because they have different expectation/intuition for the default behavior (#388) so being explicit about it ensures no one is surprised
825297d
to
350ab96
Compare
I am still trying to understand the proposal here and going back to the same example we had discussed in the How does this proposal address
My overall concern is similar to the comment on previous PR. This proposal is great but has two downsides:
Piggybacking on @skaegi's example: 😜
With scoped when expressions:
|
thanks for the review @pritidesai!
yes yes, if the
it seems to me that pipeline authors have to migrate their pipelines either way to get this feature, at least add one field (two fields in this proposal) -- is there any way we can avoid this?
the first syntax doesn't provide the flexibility to choose whether to skip the task only or the whole branch (it assumes that it guards the task only) while the second provides the flexibility, but agreed that verbosity is growing and happy to discuss any ideas to make this less verbose another difference is the first one will require us to add an expression language to the API -- we're experimenting with supporting CEL through Custom Tasks without adding it directly to the API this is one reason not specify |
yup definitely. We are trying to expand the scope of |
How can we figure out what the right balance of verbosity, clarity and features are on this one? It seems like we'll make trade-offs along one of those axes no matter which design we move ahead with. If an area of the product is complex (and I think all the nuances around conditional execution show that it is) then making it a bit verbose seems like an acceptable trade-off (to me) so long as the purpose is clear and users have the options they need. |
This is indirectly modifying the meaning of
Now, in the following example, when
|
Bringing my comment over from today's API WG for any follow-up discussion: As much as possible I think we should keep the focus on use-cases. If we can't articulate a use-case for a particular shape of graph then it seems much more difficult to make a "value judgement" on whether we should adapt the design or not. Of course if we can capture a use-case then it becomes a lot easier to decide if we want to support it and how the design could adapt to do so. Maybe a way to resolve this would be to figure out if the tools that we do provide ( |
Thank you all for the great discussion in the API WG this morning. I will try to voice my concerns and suggestions one more time 😉 Please feel free to ignore them 🤣
Down the line, we introduced We discovered Now, we are looking for a way to skip only the task which has My biggest concern is asking the users to update their pipelines to the new syntax even if there is no scheduling changes needed. Now:
After 9 releases:
Now, since the users are required to change their pipelines, we have an opportunity to design it such that it's easier to adapt and fits more use cases. Instead of paying the |
Thanks @pritidesai.
I want to deploy my application when there is a PR. If there is a change to the docker file I will build it, if not I want to skip the build and deploy anyways. I also have a github page were I list all built images, and I don't want to update that if there is no new image. Some thoughts from this example. This is a perfectly valid use case, and I think we can handle it very nicely if we fully embrace Tekton's declarative model with inputs (params) and outputs (results). (C) will publish an image sha as a result. If (C) is skipped, (D) will not run because it has a dependency of the result from (C). (E) also takes the result from (C) as input, but it takes a param input as default value for that result (this feature is not available yet). This means that if (C) does not run, (E) and still run. If we take this a step further, one could argue that task scope is all we need really. Branch scope can be achieved by creating dependencies between tasks, that are not satisfied if a task is skipped. This approach would force task author to make their tasks more explicit about their inputs and outputs, but it might hinder adoption and re-usability of tasks. Being able to through a So perhaps having |
350ab96
to
a30015d
Compare
f1c4df4
to
48d8477
Compare
thank you @pritidesai, @sbwsg, @afrittoli, @bobcatfish, @vdemeester for the discussions here and in the api wg group! 🙇🏾 changing default scope of i'm still updating the proposed solution in the tep but thought to share for your early feedback as I fill in the other parts :) |
85a6383
to
30ea879
Compare
the tep is ready for reviews, please take a look when you can 😀 |
I think we had a much better path for user migration with the Scoped WhenExpressions Alternative. With the proposal now there may be users who are completely surprised in 9 months when we switch the scope of /approve |
[APPROVALNOTIFIER] This PR is APPROVED This pull-request has been approved by: sbwsg The full list of commands accepted by this bot can be found here. The pull request process is described here
Needs approval from an approver in each of these files:
Approvers can indicate their approval by writing |
30ea879
to
e574135
Compare
thanks for the review @sbwsg!
will over-communicate during the migration in slack, email and working group meetings (just added this to the migration strategy in the TEP) - the way you did it for HOME & workingDir will be a great example 😁 |
e574135
to
f1c3b5c
Compare
thanks a bunch @jerop for all the hard work, will review the changes next week 🙏 |
In tektoncd#388, we added the problem statement for [TEP-0059: Skipping Strategies](https://github.com/tektoncd/community/blob/main/teps/0059-skip-guarded-task-only.md) that addresses skipping strategies to give users the flexibility to skip a single guarded `Task` only and unblock execution of its dependent `Tasks`. In this change, we add the proposal and discuss alternatives for solving that problem. Today, `WhenExpressions` are specified within `Tasks`, but they guard the `Task` and its dependent `Tasks`. To provide flexible skipping strategies, we propose changing the scope of `WhenExpressions` from guarding a `Task` and its dependent `Tasks` to guarding the `Task` only. If a user wants to guard a `Task` and its dependent `Tasks`, they can: 1. cascade the `WhenExpressions` to the dependent `Tasks` 2. compose the `Task` and its dependent `Tasks` as a sub-`Pipeline` that's guarded and executed together using `Pipelines` in `Pipelines` ```
f1c3b5c
to
b57cd1e
Compare
- after 9 more months, we'll remove the feature flag and `WhenExpressions` will be scoped to guard a `Task` only going | ||
forward | ||
|
||
We will over-communicate during the migration in Slack, email and working group meetings. |
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.
🚀 yup it will be essential to over communicate here 👎
thanks a bunch @jerop for the patience, appreciate all your efforts fleshing out the design ❤️ /lgtm |
- can be set to `set-when-expressions-scope-to-task` : `true` to guard a `Task` only | ||
- after 9 months, we'll flip the feature flag and default to `set-when-expressions-scope-to-task` : `true` | ||
- after 9 more months, we'll remove the feature flag and `WhenExpressions` will be scoped to guard a `Task` only going | ||
forward |
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.
hey @jerop i have a late request - im wondering how we want to handle this when we do the v1 release? the 9 months requirement really only applies to the beta types themselves, so with v1 we have a chance to flip the behavior:
- but it would be weird to have beta + v1 behave differently by default
- BUT it would be even weirder to do the v1 release with default behavior we already know we want to change
basically im hoping we can plan to release v1 with the preferred default 🙏 and wondering what your thoughts are (might make sense to add to the TEP also)
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.
hey @bobcatfish 👋🏾
wrote that assuming that in 9 months when we switch to guarding task by default, we'd have not yet released v1 -- but happy to adjust the timeline if we think we'll release v1 sooner
looks that v1 is still a ways off - tektoncd/pipeline#3548 - what do you think @vdemeester?
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.
updates made in #481, thanks @bobcatfish 😁
In #388, we added the problem statement for TEP-0059: Skipping Strategies that addresses skipping strategies to give users the flexibility to skip a single guarded
Task
only and unblock execution of its dependentTasks
.In this change, we add the proposal and discuss alternatives for solving that problem.
Today,
WhenExpressions
are specified withinTasks
but they guard theTask
and its dependentTasks
.To provide flexible skipping strategies, we propose changing the scope of
WhenExpressions
from guarding aTask
and its dependent
Tasks
to guarding theTask
only.If a user wants to guard a
Task
and its dependentTasks
, they can:WhenExpressions
to the dependentTasks
Task
and its dependentTasks
as a sub-Pipeline
that's guarded and executed together usingPipelines
inPipelines
/kind tep