-
Notifications
You must be signed in to change notification settings - Fork 4.7k
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
Adding MultiActions for composite filters. WIP #26251
Conversation
CC @envoyproxy/api-shepherds: Your approval is needed for changes made to |
: public Matcher::ActionBase< | ||
envoy::extensions::filters::http::composite::v3::ExecuteFilterMultiAction> { | ||
public: | ||
explicit ExecuteFilterMultiAction(Http::FilterFactoryCb callbacks) |
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.
Here, the function arg should be a list of callbacks`?
Signed-off-by: Joseph Straceski <jstraceski@google.com>
3c642c3
to
6f7b26e
Compare
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.
Thanks, looks good, couple of questions.
@@ -12,6 +12,16 @@ namespace Composite { | |||
namespace { | |||
// Helper that returns `filter->func(args...)` if the filter is not null, returning `rval` | |||
// otherwise. | |||
template <class FilterPtrT, class FuncT, class RValT, class... Args> |
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'm wondering at the C++ code level why we need to distinguish single action vs. multiple actions with templates etc. Why not have the core implementation support multiple action, and when we instantiation the single action extension it sets N=1?
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.
When I added this originally I looked into supporting delegating to multiple filters, but found that in order to preserve the existing filter API behavior you need to manage pausing iteration which blows up the complexity of this. Maybe now with the FilterManager being extracted out of the HCM this is something we can do, though I suspect it will make this much more complicated than it is right now
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.
@htuch this had occurred to me when implementing the vectorized version of this class. I think that if we can define the type of behavior to expect when iterating over multiple filters, i.e. some default behavior. We can add upon that in the future and create more complex logic if necessary. Something I can discuss with @tyxia.
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.
Yeah. Not suggesting we do the full thing that @snowp points out, but what I'm suggesting is to simplify your existing implementation. You have some template and conditional logic on whether this is a single or multi action. Why not just have it always the second case with N=1?
@@ -37,3 +37,9 @@ message Composite { | |||
message ExecuteFilterAction { | |||
config.core.v3.TypedExtensionConfig typed_config = 1; | |||
} | |||
|
|||
|
|||
message ExecuteFilterMultiAction { |
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 feel we should have some better documentation here explaining what this is, why you would use it, how etc.
RValT delegateAllFilterActionOr(std::vector<FilterPtrT> filter_list, FuncT func, RValT rval, Args&&... args) { | ||
RValT value = rval; | ||
for (auto filter : filter_list) { | ||
value = ((*filter).*func)(std::forward<Args>(args)...); |
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.
How would this work if one of the intermediate filters rely on pausing filter iteration? Seems like we're going to return whatever the latest filter returns, which seems counter-intuitive
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 was testing locally and noticed this, would reverse order be preferable? I was thinking about possible alternatives to this, some sort of logic for chaining subsequent actions? Or alternatively, I think the best solution would maybe be to store the most recent status calls in the StreamFilterWrapper sub-filters and just return the last one.
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.
If you want this to work with any existing filter you'll end up having to maintain the existing behavior wrt filter control (pausing, resuming, etc), so I think you'll need to actually manage the filter start/stop/etc of each filter, possibly by reusing FilterManager
to manage an internal set of filters
If you are ok with not supporting all filters this could be less powerful and we could document the limitations, but that makes this less useful than it could be
cc @alyssawilk @mattklein123 since filter iteration is complicated
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.
Coming in late to this but why are we reimplementing filter manager logic in a filter? I'd lean towards reexamining the design here if that's the plan.
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.
@alyssawilk, we are attempting to implement a mechanism primarily to run multiple ext_proc filter calls per route, i.e. multiple actions per filter. I am relatively new to the envoy code base and was unaware of this in regards to the composite filter.
That makes sense though.
I'll look into if this is possible through leveraging the FilterManager
but another solution may be to come up with a different way to call multiple ext_proc filters.
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.
Talked to Tianyu about this yesterday and I'm happy to whiteboard data plane options/complexity with anyone else interested. As usual I'll defer to Harvey/Adi if we go the control plane route :-)
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.
The most interesting option that I don't fully understand is "dynamic HTTP filter chains", where somehow we augment the HTTP filter chain instantiation with per-route configuration. @alyssawilk do you have links or a dump of history on this one?
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.
alas I don't have context on that one. I will say being able to enable and disable filters per route, or do custom filter chains per route seems entirely reasonable and if Envoy currently isn't flexible enough to do that in some dimension I'd be interested in making sure we fix that. I just think there's easier ways than having layered filter managers :-)
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.
Here #14722 and this doc https://docs.google.com/document/d/1dOa_v1eMA4F61f0jdFkxtbcO-_TYD76oMfGoY7nzZhk/edit#heading=h.9v2rpr8krgni might be able to provide some context.
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.
There has been asks for this for a while though I don't think we ever landed on a robust solution for it since there are a bunch of edge cases to consider, like what happens if the route changes mid-filter
Composite filters were an attempt at solving the "optional/branching filter" idea, with a focus on being deliverable via ECDS for a single filter. The idea was to let a separate system run an ECDS server and inject logic into the filter chain (at a pre-specified position in the filter chain) and deliver the matching requirement independent of other configuration, hence bundling the matching + filter config into something ECDS could deliver.
If we wanted the match component to live in the route configuration, I think we could get something working relatively easily by making use of https://www.envoyproxy.io/docs/envoy/latest/api-v3/extensions/filters/common/matcher/action/v3/skip_action.proto#envoy-v3-api-msg-extensions-filters-common-matcher-action-v3-skipfilter and having it read the decision from the per filter configuration or metadata from the route action. You could imagine configuring a sequence of ext_proc filters with something like
skip D unless route.metadata == "doTheThing"
skip E unless route.metadata == "doTheThing"
skip F unless route.metadata == "doTheThing"
@@ -12,6 +12,16 @@ namespace Composite { | |||
namespace { | |||
// Helper that returns `filter->func(args...)` if the filter is not null, returning `rval` | |||
// otherwise. | |||
template <class FilterPtrT, class FuncT, class RValT, class... Args> |
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.
When I added this originally I looked into supporting delegating to multiple filters, but found that in order to preserve the existing filter API behavior you need to manage pausing iteration which blows up the complexity of this. Maybe now with the FilterManager being extracted out of the HCM this is something we can do, though I suspect it will make this much more complicated than it is right now
/assign @tyxia |
Thank you @htuch and @snowp for early feedback! This is still WIP and we will add more details and address the comments soon. @jstraceski , good progress since yesterday's sync! Let's fix the format issue to get CI/CD running. I will send some command to you offline. btw, you can add WIP in the PR title so people will notice it is Work In Progress. |
fa4c1e0
to
6f7b26e
Compare
…scriptions. Signed-off-by: Joseph Straceski <jstraceski@google.com>
Signed-off-by: Joseph Straceski <jstraceski@google.com>
Signed-off-by: Joseph Straceski <jstraceski@google.com>
This pull request has been automatically marked as stale because it has not had activity in the last 30 days. It will be closed in 7 days if no further activity occurs. Please feel free to give a status update now, ping for review, or re-open when it's ready. Thank you for your contributions! |
@jstraceski @tyxia should we close this out in favor of the current approach you folks are taking to composition? |
Yes, we will not proceed with this approach for our project at this moment. The potential value of this PR is 1) allow multi-action/filters that doesn't need filter state management (like setResponseCode Filter). The value of this is limited and we need a big warning in the proto. 2) The setup PR for potential future multi-action that requires inner filter chain management. |
Commit Message: Adding a Multi Action Execution action to the composite filter.
Additional Description: Executes multiple actions as one route path in the filter.
Risk Level: n/a
Testing: test/extensions/filters/http/composite/composite_filter_integration_test.cc
Docs Changes: TBD
Release Notes: TBD
Platform Specific Features: N/A