-
Notifications
You must be signed in to change notification settings - Fork 343
decide the future of tower::filter #502
Copy link
Copy link
Closed
Labels
A-filterArea: The tower "filter" middlewareArea: The tower "filter" middlewareA-new-middlewareArea: new middleware proposalsArea: new middleware proposalsA-utilArea: The tower "util" moduleArea: The tower "util" moduleC-cleanupCategory: PRs that clean code up or issues documenting cleanup.Category: PRs that clean code up or issues documenting cleanup.C-feature-requestCategory: A feature request, i.e: not implemented / a PR.Category: A feature request, i.e: not implemented / a PR.C-musingCategory: musings about a better worldCategory: musings about a better worldI-needs-decisionIssues in need of decision.Issues in need of decision.P-highHigh priorityHigh priorityT-middlewareTopic: middlewareTopic: middlewarerelnotesMarks issues that should be documented in the release notes of the next release.Marks issues that should be documented in the release notes of the next release.
Milestone
Description
Metadata
Metadata
Assignees
Labels
A-filterArea: The tower "filter" middlewareArea: The tower "filter" middlewareA-new-middlewareArea: new middleware proposalsArea: new middleware proposalsA-utilArea: The tower "util" moduleArea: The tower "util" moduleC-cleanupCategory: PRs that clean code up or issues documenting cleanup.Category: PRs that clean code up or issues documenting cleanup.C-feature-requestCategory: A feature request, i.e: not implemented / a PR.Category: A feature request, i.e: not implemented / a PR.C-musingCategory: musings about a better worldCategory: musings about a better worldI-needs-decisionIssues in need of decision.Issues in need of decision.P-highHigh priorityHigh priorityT-middlewareTopic: middlewareTopic: middlewarerelnotesMarks issues that should be documented in the release notes of the next release.Marks issues that should be documented in the release notes of the next release.
Motivation
It was pointed out that there is currently some overlap between the
try_withServicecombinator andtower::filtermiddleware (see #499 (comment)).try_withsynchronously maps from aRequest->Result<DifferentRequest, Error>, whiletower::filterasynchronously maps from a&Requestto aResult<(), Error>. The key differences are:try_withtakes a request by value, and allows the predicate to return a different request valuetry_withalso permits changing the type of the requesttry_withis synchronous, whiletower::filteris asynchronoustower::filterhas aPredicatetrait, which can be implemented by more than just functions. For example, a struct with aHashSetcould implementPredicateby failing requests that match the values in the hashset.It definitely seems like there's demand for both synchronous and asynchronous request filtering. However, the APIs we have currently differ pretty significantly. It would be nice to make them more consistent with each other.
As an aside,
tower::filterdoes not seem all that widely used.Meanwhile,
linkerd2-proxydefines its ownRequestFiltermiddleware, using a predicate trait that's essentially in betweentower::filterandServiceExt::try_with:try_withtry_withFn, liketower::filtertower::filter("filtering" rather than "with"/"map")Proposal
I think we should try to unify these APIs into something with a more consistent interface. I suggest the following:
Requesttypes by value rather than by reference, and allow returning a new request typeIt's theoretically possible to have one API for both sync and async filtering, but this would require a trait like
IntoFuturethat can be implemented by bothFuture<Output = Result<T, E>andResult<T, E>. A predicate trait could return something implementing that trait, andResultcould have an impl that turns itself into a ready future. This would let us have one API for both sync and async predicates. However, it introduces some complexity in the type signatures, and requires a slight added overhead (polling the immediately ready future when the predicate is synchronous). The added complexity of using anIntoFuture-like trait might be less of an issue when the standard library stabilizesIntoFuture...On the other hand, we could have separate sync and async filter APIs. The main disadvantage of that approach is that we'd then need to bikeshed a consistent naming scheme that makes both the distinction and the similarity similar. Historically, we've not been great at naming things efficiently ;)
cc @LucioFranco @seanmonstar @olix0r @hlb8122 --- what do you all think?
https://github.com/linkerd/linkerd2-proxy/blob/main/linkerd/stack/src/request_filter.rs