Skip to content
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

http conn manager: Support Route Mutability #14904

Closed
mengmichael1 opened this issue Feb 2, 2021 · 6 comments
Closed

http conn manager: Support Route Mutability #14904

mengmichael1 opened this issue Feb 2, 2021 · 6 comments
Assignees
Labels

Comments

@mengmichael1
Copy link
Contributor

mengmichael1 commented Feb 2, 2021

Title: StreamFilter: Support Route Mutability

Description:
At Lyft we have a Http::StreamDecoderFilter that goes through rewriting the Host: header, clearing the route cache, and having the HTTP connection manager reevaluate the route selection -- just to update the routeEntry clusterName of a route (a Router::RouteConstSharedPtr). There is no support for route mutability.

Proposing two changes to enable a filter to directly mutate properties of a route, rather than having to go through the roundabout process of rewriting headers & clearing the route cache.

Proposal:

  1. Add a new setRoute(const Router::RouteConstSharedPtr route) method to the StreamFilter API (in StreamFilterCallbacks) that sets the current request’s route as the passed-in RouteConstSharedPtr argument.
  2. Add a new class called DelegatingRoute, which implements its base/parent class of Router:Route by delegating all method calls to the baseRoute that it wraps around. DelegatingRoute will take in a baseRoute (a RouteConstSharedPtr) in its constructor, and calls to Route class methods such as directResponseEntry and routeEntry will simply get delegated to the baseRoute.

Rationale for 2:
As part of enabling route mutability, the goal is to build a mechanism that enables developers to easily take an existing route, and create a new route that mutates specific properties (In our case, routeEntry, but another example can be tracingConfig ) while preserving all the rest of the properties/behavior of the existing route. We introduce the concept of a DelegatingRoute as this mechanism. An alternative approach, deep copying an existing route, is prohibitively expensive.

Usage:
Usage would be a filter calling setRoute(r) where r is a derived/child class of DelegatingRoute. In addition, DelegatingRoute will be useful in unit testing (will be used to test Lyft’s new filter modifying clusterName) for any changes related to modifying a route.

@mengmichael1 mengmichael1 added enhancement Feature requests. Not bugs or questions. triage Issue requires triage labels Feb 2, 2021
@mattklein123
Copy link
Member

Note I already discussed this with the Lyft team internally. +1 from me. This has been asked for previously, is easy to implement, and will allow filters to fully customize route selection easily. cc @alyssawilk @snowp for thoughts.

@mattklein123 mattklein123 added area/http help wanted Needs help! and removed enhancement Feature requests. Not bugs or questions. triage Issue requires triage labels Feb 2, 2021
@snowp
Copy link
Contributor

snowp commented Feb 2, 2021

In general very much in favor of this, just a few immediate thoughts:

I imagine this would not survive a clearRouteCache? Documenting this behavior would probably be sufficient, though I can imagine this causing some confusion whenever someone makes use of a filter that modifies the route, followed by another filter that modifies headers + clears the cache. This is similar to the limitations of Router::RouteConstSharedPtr route(const Router::RouteCallback& cb), so I think this is fine.

Would you also be adding a delegating RouteEntry? I would imagine you want to only override parts of the route entry.

I think another option would be to expose mutating functions on the Route/RouteEntry, allowing for it to be modified directly instead of having to decorate it with a wrapper object to override values. That said, the wrapper allows for more flexibility without code changes (we avoid changes for each thing on the route we want to change), so it seems like a good direction.

Overall I think this is good, this would have been very helpful for me in the past, where I've jumped through similar hoops to update the final route.

@alyssawilk
Copy link
Contributor

Definitely a fan of 1)
For 2) is the plan that every stream default to the delegate, and by default it gets the route's tracing config and route entry, but the same way you can setRoute you can setTracingConfig to override bits? I think this is fine, though I wonder about the pros and cons of doing this programatically, vs a route re-architecture where we refactor the monolithic entry into something with named components so having a clone isn't prohibitively expensive. Either way that's a much larger change and I think 2) is a fine workaround and possibly has some long term benefits that the rearchitecting wouldn't have.

@mengmichael1
Copy link
Contributor Author

mengmichael1 commented Feb 2, 2021

Thanks for the feedback everyone!

@mattklein123 Saw you added the "help wanted" tag, to clarify I'll be taking on this implementation work :)

@snowp Correct, this wouldn't survive a clearRouteCache in subsequent filters. But like you said, should be fine since Router::RouteConstSharedPtr route(const Router::RouteCallback& cb) has the same limitations.

Yes, the plan is to also add a DelegatingRouteEntry that wraps around an existing Router::RouteEntry*. And I overall like the idea of using a wrapper object to preserve the existing immutable characteristic of Route/RouteEntry (unsure how much rearchitecting would be needed for mutating functions).

@alyssawilk Yes that is exactly the plan for (2)! For now, my plan was just to enable overriding the route entry (as Snow pointed out, I'll be adding a DelegatingRouteEntry). As part of this change, do you think I should also include set methods for the rest of the Route class attributes? (e.g. setTracingConfig, setDecorator, setDirectResponseEntry, etc). I'm thinking I could leave it to others to add in the future if they find this delegating mechanism useful?

@mengmichael1 mengmichael1 changed the title StreamFilter: Support Route Mutability http conn manager: Support Route Mutability Apr 8, 2021
@mengmichael1
Copy link
Contributor Author

@mattklein123 @snowp With #15266 merged, can we close this issue now?

@mattklein123
Copy link
Member

Thank you!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

4 participants