575 Commits

Author SHA1 Message Date
David Pedersen
7d3443e6f0
Re-export layer_fn and LayerFn from tower (#516)
Co-authored-by: Lucio Franco <luciofranco14@gmail.com>
2021-01-11 11:56:26 -05:00
David Pedersen
d25589d3a6
Fix all the docs links (#515)
* Fix docs links

* Add `#![deny(broken_intra_doc_links)]` to all crates

Co-authored-by: Eliza Weisman <eliza@buoyant.io>
2021-01-11 11:44:50 -05:00
Lucio Franco
b4d3844693
Fix Semaphore to be Sync (#518) 2021-01-11 11:37:29 -05:00
Eliza Weisman
b447771855
tower: prepare to release 0.4.1 (#514)
* tower: prepare to release 0.4.1

This branch updates the tower-layer dependency to 0.3.1 and prepares a
new release of `tower`. This should fix the broken re-exports of
`layer_fn` and get us a successful docs.rs build.

Signed-off-by: Eliza Weisman <eliza@buoyant.io>
tower-0.4.1
2021-01-07 15:26:59 -08:00
Eliza Weisman
44ad621c56
layer: prepare to release v0.3.1 (#513)
* layer: prepare to release v0.3.1

Signed-off-by: Eliza Weisman <eliza@buoyant.io>

* whitespace
tower-layer-0.3.1
2021-01-07 15:05:45 -08:00
Eliza Weisman
ca685ae943
test: update tower-test to v0.4 (#512)
Signed-off-by: Eliza Weisman <eliza@buoyant.io>
tower-0.4.0
2021-01-07 14:33:55 -08:00
Eliza Weisman
992702fd20
prepare Tower 0.4 for release (#511)
This branch updates the changelogs and version numbers for Tower 0.4.

* update changelog for 0.4
* add changelog blurb
* update version to 0.4

Signed-off-by: Eliza Weisman <eliza@buoyant.io>
2021-01-07 13:35:05 -08:00
David Pedersen
bebe677074
steer: Add more true to life example for Steer docs (#506)
I think `Steer` is looking pretty useful. I have use case where want
some requests (such as `GET /metrics`) to go to one service and other
requests to some other service. I imagine this is quite a common use
case for `Steer` so I figure the example in the docs would be more
helpful if it showed how to accomplish something like that.

In general I think tower's docs could be better at explaining how to
combine all the different pieces to solve real problems. Hopefully this
might help a bit wrt `Steer`.

Co-authored-by: Eliza Weisman <eliza@buoyant.io>
2021-01-06 15:54:50 -08:00
Harry Barber
f171390703
util: Add and_then combinator (#485)
## Motivation

https://docs.rs/futures/0.3.8/futures/future/trait.TryFutureExt.html#method.and_then is a useful method on futures. Perhaps it'd be nice to replicate this for the `ServiceExt` API.

Co-authored-by: Harry Barber <harry.barber@disneystreaming.com>
Co-authored-by: Eliza Weisman <eliza@buoyant.io>
2021-01-06 15:08:05 -08:00
Eliza Weisman
3b7c91ed58
make all combinator futures opaque (#509)
* make all combinator futures opaque

For stability reasons, we probably don't want to expose future
combinator types from the `futures_util` crate in public APIs. If we
were to change which combinators are used to implement these futures, or
if `futures_util` made breaking changes, this could cause API breakage.

This branch wraps all publicly exposed `futures_util` types in the
`opaque_future!` macro added in #508, to wrap them in newtypes that hide
their internal details. This way, we can change these futures' internals
whenever we like.

Signed-off-by: Eliza Weisman <eliza@buoyant.io>
2021-01-06 15:06:31 -08:00
Eliza Weisman
2a7d47adda
rewrite tower::filter (#508)
## Motivation

It was pointed out that there is currently some overlap between the
`try_with` `Service` combinator and `tower::filter` middleware (see https://github.com/tower-rs/tower/pull/499#discussion_r549522471 ).
`try_with` synchronously maps from a `Request` ->
`Result<DifferentRequest, Error>`, while `tower::filter`
_asynchronously_ maps from a `&Request` to a `Result<(), Error>`. The
key differences are: - `try_with` takes a request by value, and allows
the predicate to return a *different* request value - `try_with` also
permits changing the _type_ of the request - `try_with` is synchronous,
while `tower::filter` is asynchronous - `tower::filter` has a
`Predicate` trait, which can be implemented by more than just functions.
For example, a struct with a `HashSet` could implement `Predicate` by
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::filter` [does not seem all that widely used][1].


Meanwhile, `linkerd2-proxy` defines its own `RequestFilter` middleware,
using a [predicate trait][2] that's essentially in between `tower::filter` and
`ServiceExt::try_with`: - it's synchronous, like `try_with` - it allows
modifying the type of the request, like `try_with` - it uses a trait for
predicates, rather than a `Fn`, like `tower::filter` - it uses a similar
naming scheme to `tower::filter` ("filtering" rather than "with"/"map").

[1]: https://github.com/search?l=&p=1&q=%22tower%3A%3Afilter%22+extension%3Ars&ref=advsearch&type=Code
[2]: 24bee8cbc5/linkerd/stack/src/request_filter.rs (L8-L12)

## Solution

This branch rewrites `tower::filter` to make the following changes:

* Predicates are synchronous by default. A separate `AsyncFilter` type
  and an `AsyncPredicate` trait are available for predicates returning
  futures.
* Predicates may now return a new `Request` type, allowing `Filter` and
  `AsyncFilter` to subsume `try_map_request`.
* Predicates may now return any error type, and errors are now converted
  into `BoxError`s.

Closes #502

Signed-off-by: Eliza Weisman <eliza@buoyant.io>
2021-01-06 12:18:20 -08:00
David Pedersen
b7a7c280ee
util: Remove ServiceExt::ready (#507) 2021-01-05 10:12:36 -08:00
David Pedersen
3bdaae9284
Fix clippy warnings (#505)
Thought I might as well fix the clippy warnings. Feel free to 
close this if you don't want the git churn.
2021-01-04 14:49:05 -08:00
Eliza Weisman
fdd66e5305
docs pass (#490)
This branch makes the following changes:

* New `lib.rs` docs for `tower`, which should hopefully provide a
  better explanation of Tower's core abstractions & their
  relationships
* Nicer docs for `ServiceBuilder`
* Added `#[doc(cfg(...))]` attributes for feature flagged APIs
* Example improvements
* Fixing a bunch of broken intra-rustdoc links

Signed-off-by: Eliza Weisman <eliza@buoyant.io>
2021-01-04 13:52:23 -08:00
Eliza Weisman
bef0ade3cb
util: Add then combinator (#500)
Currently, `ServiceExt` and `ServiceBuilder` provide combinators for
mapping successful responses to other responses, and mapping errors to
other errors, but don't provide a way to map between `Ok` and `Err`
results.

For completeness, this branch adds a new `then` combinator, which takes
a function from `Result` to `Result` and applies it when the service's
future completes. This can be used for recovering from some errors or
for rejecting some `Ok` responses. It can also be used for behaviors
that should be run when a service's future completes regardless of
whether it completed successfully or not.

Depends on #499
2021-01-04 11:59:24 -08:00
David Pedersen
d0fde833b1
builder: Make ServiceBuilder::service take self by reference (#504)
* Make `ServiceBuilder::service` take `self` by reference

Fixes #501

* Fix clippy warning

* Update changelog
2021-01-04 11:53:32 -08:00
Eliza Weisman
878b10f57d
util: unify and rename combinators (#499)
Currently, the `ServiceExt` trait has `with` and `try_with` methods for
composing a `Service` with functions that modify the request type, and
`map_err` and `map_ok` methods for composing a service with functions
that modify the response type. Meanwhile, `ServiceBuilder` has
`map_request` for composing a service with a request mapping function,
and `map_response` for composing a service with a response-mapping
function. These combinators are very similar in purpose, but are
implemented using different middleware types that essentially duplicate
the same behavior.

Before releasing 0.4, we should probably unify these APIs. In
particular, it would be good to de-duplicate the middleware service
types, and to unify the naming.

This commit makes the following changes:
- Rename the `ServiceExt::with` and `ServiceExt::try_with` combinators
  to `map_request` and `try_map_request`
  - Rename the `ServiceExt::map_ok` combinator to `map_response`
- Unify the `ServiceBuilder::map_request` and `ServiceExt::map_request`
  combinators to use the same `Service` type
- Unify the `ServiceBuilder::map_response` and
  `ServiceExt::map_response` combinators to use the same `Service` type
- Unify the `ServiceBuilder::map_err` and `ServiceExt::map_err`
  combinators to use the same `Service` type
- Only take `FnOnce + Clone` when in response/err combinators, which
  require cloning into the future type. `MapRequest` and `TryMapRequest`
  now take `FnMut(Request)`s and don't clone them every time they're
  called
- Reexport future types for combinators where it makes sense.
- Add a `try_map_request` method to `ServiceBuilder`

Closes #498

Signed-off-by: Eliza Weisman <eliza@buoyant.io>
2021-01-04 10:27:05 -08:00
David Pedersen
0100800dda
Add MakeService::into_service and MakeService::as_service (#492)
Resolves #253

Adds `MakeService::into_service` and `MakeService::as_service` which
converts `MakeService`s into `Service`s. `into_service` consumes `self`
and `as_service` borrows `self` mutably.
2020-12-29 15:45:43 -08:00
Oliver Gould
6be2ff68dd
util: Add BoxService layer helpers (#503)
This change adds `BoxService::layer` and `UnsyncBoxService::layer`
helpers to provide a convenience helper for boxing services in layered
stacks.

Co-authored-by: Eliza Weisman <eliza@buoyant.io>
2020-12-29 15:18:22 -08:00
David Pedersen
0ede7c335e
util: Add FutureService (#495)
Resolves #264 

This branch adds `FutureService` to `tower::util`, which implements
`Service` for `Future<Output = impl Service>`. Before the future has
completed, `poll_ready` on `FutureService` will drive it to completion,
returning `Ready` only once the future has completed. Subsequent calls
will poll the service returned by the future.

See https://github.com/tower-rs/tower/issues/264#issuecomment-751400523

Based on
1be301f2b0/linkerd/stack/src/future_service.rs

Co-authored-by: Daiki Mizukami <tesaguriguma@gmail.com>
Co-authored-by: Eliza Weisman <eliza@buoyant.io>
2020-12-29 10:44:12 -08:00
David Pedersen
f76fe9f38f
util: add layer_fn (#491)
Resolves #267

I went with `layer_fn` over `layer::from_fn` because changing
`service_fn` would be a breaking change. But I don't mind changing it if
you think thats more appropriate 😊 

Co-authored-by: Eliza Weisman <eliza@buoyant.io>
2020-12-29 10:33:31 -08:00
George Hahn
704bfa819e
layer: fix+improve doc links (#487)
- Fixes a link to the `Service` trait on the `tower_layer` module page.
  ([current page](https://docs.rs/tower-layer/0.3.0/tower_layer/index.html))
- Adds a link to `Service` on the `Layer` trait page.
  ([current page](https://docs.rs/tower-layer/0.3.0/tower_layer/trait.Layer.html))

These changes use old style links - intra-rustdoc links won't work
here because `tower`/`tower_service` aren't referenced by this crate.
2020-12-28 15:07:01 -08:00
Oliver Gould
ff85e3ade8
buffer: Add Clone + Copy impls for BufferLayer (#493)
It's generally the case that layers need to be shareable. There's no
reason that `BufferLayer` should not implement both `Clone` and `Copy`.

This change adds manual `Clone` and `Copy` implementations for
`BufferLayer`.
2020-12-28 13:09:05 -08:00
Oliver Gould
4f65e3017b
balance: Remove MakeBalance::from_rng (#497)
`MakeBalance`'s use of `SmallRng` is problematic: since it clones the
`SmallRng` between `Balance` instances, each instance will have the same
state and produce an identical sequence of values. This probably isn't
_dangerous_, though it is certainly unexpected.

This change removes the `MakeBalance::from_rng` and
`MakeBalanceLayer::from_rng` helpers. The `MakeBalance` service now uses
the default RNG via `Balance::new`. `Balance::new` now creates its
`SmallRng` from the `thread_rng` instead of the default entropy source,
as the default entropy source may use the slower `getrandom`. From the
[`rand` docs][from_entropy]:

> In case the overhead of using getrandom to seed many PRNGs is an
> issue, one may prefer to seed from a local PRNG, e.g.
> from_rng(thread_rng()).unwrap().

Finally, this change updates the balnancer to the most recent version of
`rand`, v0.8.0.

[from_entropy]: https://docs.rs/rand/0.8.0/rand/trait.SeedableRng.html#method.from_entropy
2020-12-28 12:41:35 -08:00
Eliza Weisman
45974d018d
update to Tokio 1.0 (#489)
This branch updates Tower to depend on Tokio v1.0. In particular, the
following changes were necessary:

* `tokio::sync::Semaphore` now has a `close` operation, so permit
  acquisition is fallible. Our uses of the semaphore are updated to
  handle this. Also, this allows removing the janky homemade
  implementation of closing semaphores by adding a big pile of
  permits!

* `tokio::sync`'s channels are no longer `Stream`s. This necessitated a
  few changes:
  - Replacing a few explicit `poll_next` calls with `poll_recv`
  - Updating some tests that used `mpsc::Receiver` as a `Stream` to add
    a wrapper type that makes it a `Stream`
  - Updating `CallAll`'s examples (I changed it to just use a
    `futures::channel` MPSC)

* `tokio::time::Sleep` is no longer `Unpin`. Therefore, the rate-limit
  `Service` needs to `Box::pin` it. To avoid the overhead of
  allocating/deallocating `Box`es every time the rate limit is
  exhausted, I moved the `Sleep` out of the `State` enum and onto the
  `Service` struct, and changed the code to `reset` it every time the
  service is rate-limited. This way, we only allocate the box once when
  the service is created.

There should be no actual changes in functionality.

Signed-off-by: Eliza Weisman <eliza@buoyant.io>
2020-12-23 11:59:54 -08:00
Eliza Weisman
124816a40e
ci: install cargo hack from GitHub release binary (#486)
CI is currently busted due to [issues with caching `cargo-hack`][1].
Currently, we cache the `cargo-hack` executable to speed up builds by
avoiding the overhead of compiling it from source in every build.

Recently, `cargo-hack` has started publishing binaries on GitHub
Releases. Rather than compiling it on CI and caching it, we can just
download the binary instead. This ought to fix the build.

See also taiki-e/cargo-hack#89 and taiki-e/cargo-hack#91.

[1]: https://github.com/tower-rs/tower/runs/1425940763
2020-12-23 11:49:46 -08:00
Alice Ryhl
3a8d31c60f
fix typo (#482) 2020-11-27 14:49:38 -05:00
Henry de Valence
d4d1c67c6a
hedge: use auto-resizing histograms (#484)
The previous code used a fixed-size histogram with an upper bound of 10_000 ms
(10s).  This meant that the `Hedge` middleware would display errors when used
with services that take longer than 10s to complete a response.  Instead, use a
constructor that produces an auto-resizing histogram.  In the future, if the
auto-resizing behavior is an issue, Tower could add a second constructor for
the Hedge middleware that allows specifying bounds, but for now this change is
transparent and avoids spurious errors.
2020-11-19 10:04:49 -08:00
Harry Barber
5e1e077448 Add clones to combinators 2020-11-05 15:18:43 -08:00
Eliza Weisman
450fa3d2be
spawn_ready: put back poll_closed (#481)
Tokio put this method back in 0.3.2, so we can use it again.

Closes #478
2020-10-28 15:15:56 -04:00
Eliza Weisman
43c44922af
buffer: wake tasks waiting for channel capacity when terminating (#480) 2020-10-28 11:41:11 -04:00
Eliza Weisman
069c9085b1
tests: print traces from tests (#479) 2020-10-28 11:40:27 -04:00
Eliza Weisman
ddc64e8d4d
update to Tokio 0.3 (#476)
This branch updates Tower to Tokio 0.3.

Unlike  #474, this branch uses Tokio 0.3's synchronization primitives,
rather than continuing to depend on Tokio 0.2. I think that we ought to
try to use Tokio 0.3's channels whenever feasible, because the 0.2
channels have pathological memory usage patterns in some cases (see
tokio-rs/tokio#2637). @LucioFranco let me know what you think of the
approach used here and we can compare notes!

For the most part, this was a pretty mechanical change: updating
versions in Cargo.toml, tracking feature flag changes, renaming
`tokio::time::delay` to `sleep`, and so on. Tokio's channel receivers
also lost their `poll_recv` methods, but we can easily replicate that by
enabling the `"stream"` feature and using `poll_next` instead.

The one actually significant change is that `tokio::sync::mpsc::Sender`
lost its `poll_ready` method, which impacts the way `tower::buffer` is
implemeted. When the buffer's channel is full, we want to exert
backpressure in `poll_ready`, so that callers such as load balancers
could choose to call another service rather than waiting for buffer
capacity. Previously, we did this by calling `poll_ready` on the
underlying channel sender.

Unfortunately, this can't be done easily using Tokio 0.3's bounded MPSC
channel, because it no longer exposes a polling-based interface, only an
`async fn ready`, which borrows the sender. Therefore, we implement our
own bounded MPSC on top of the unbounded channel, using a semaphore to
limit how many items are in the channel.

I factored out the code for polling a semaphore acquire future from
`limit::concurrency` into its own module, and reused it in `Buffer`.

Additionally, the buffer tests needed to be updated, because they
currently don't actually poll the buffer service before calling it. This
violates the `Service` contract, and the new code actually fails as a
result.

Closes #473 
Closes #474

Co-authored-by: Lucio Franco <luciofranco14@gmail.com>
Signed-off-by: Eliza Weisman <eliza@buoyant.io>
2020-10-27 11:21:18 -07:00
Henry de Valence
1a84543317
hedge: don't reserve slots for hedged requests (#472) 2020-10-02 10:02:31 -04:00
Oliver Gould
ad348d8ee5
ready-cache: Properly expose error source (#467)
The `ready_cache::error::Failed` type does not actually expose its inner
error type via `Error::source`. This change fixes this and improves
debug formatting.

This change adds a new constraint, ensuring that keys impl Debug in
order for the `error::Failed` type to impl Debug/Error.
2020-08-31 07:21:04 -07:00
Harry Barber
ab7518ef13
Add Future-like combinators (#396) 2020-07-17 16:33:00 -04:00
Bruce Guenter
4316894422
Add get_ref functions to more service layers (#463)
* Implement get_ref, get_mut, and into_inner for Retry

* Implement get_ref, get_mut, and into_inner for Timeout
2020-07-10 10:47:39 -04:00
Taiki Endo
b12a3e3ae9
Remove uses of pin_project::project attribute (#458)
pin-project will deprecate the project attribute due to some unfixable
limitations.

Refs: https://github.com/taiki-e/pin-project/issues/225
2020-06-15 12:38:34 -04:00
Lucio Franco
007b648ea9
Clean up readme and update status (#453) 2020-05-08 13:54:45 -04:00
Bruce Guenter
98e0e41db1
Rework ConcurrencyLimit to use upstream tokio Semaphore (#451) 2020-05-06 11:06:40 -04:00
Lucio Franco
a0a66b10a2
Upgrade cargo deny action (#452) 2020-05-06 09:45:57 -04:00
Jon Gjengset
1c2d50680a
Spring cleaning for tower::balance (#449)
Noteworthy changes:

 - All constructors now follow the same pattern: `new` uses OS entropy,
   `from_rng` takes a `R: Rng` and seeds the randomness from there.
   `from_rng` is fallible, since randomness generators can be fallible.
 - `BalanceLayer` was renamed to `MakeBalanceLayer`, since it is not
   _really_ a `BalanceLayer`. The name of `BalanceMake` was also
   "normalized" to `MakeBalance`.

Another observation: the `Debug` bound on `Load::Metric` in
`p2c::Balance`, while not particularly onerous, generates really
confusing errors if you forget it include it. And crucially, the error
never points at `Debug` (should we file a compiler issue?), so I pretty
much had to guess my way to that being wrong in the doc example.

It would probably be useful to add a documentation example to
`MakeBalanceLayer` or `MakeBalance` (I suspect just one of them is fine,
since they're basically the same). Since I've never used it, and find it
hard to think of uses for it, it might be good if someone with more
experience with it wrote one.
2020-04-24 13:21:11 -04:00
Jon Gjengset
6a25d322b5 Use only one alias for Box<dyn Error>
This was a mostly mechanical change. I think in at least one place it
results in a `'static` bound being added, but the next tower release
will be breaking anyway, so that's okay.

I think it helps to also document the alias at the top to (eventually)
explain how people can interact with the error they get back to discover
the "deeper cause".
2020-04-24 10:30:20 -04:00
Eliza Weisman
8752a38117
util: fix oneshot dropping pending services immediately (#447)
## Motivation

Commit #330 introduced a regression when porting `tower-util::Oneshot`
from `futures` 0.1 to `std::future`. The *intended* behavior is that a
oneshot future should repeatedly call `poll_ready` on the oneshotted
service until it is ready, and then call the service and drive the
returned future. However, #330 inadvertently changed the oneshot future
to poll the service _once_, call it if it is ready, and then drop it,
regardless of its readiness.

In the #330 version of oneshot, an `Option` is used to store the
request while waiting for the service to become ready, so that it can be
`take`n and moved into the service's `call`. However, the `Option`
contains both the request _and_ the service itself, and is taken the
first time the service is polled. `futures::ready!` is then used when
polling the service, so the method returns immediate if it is not ready.
This means that the service itself (and the request), which were taken
out of the `Option`, will be dropped, and if the oneshot future is
polled again, it will panic.

## Solution

This commit changes the `Oneshot` future so that only the request lives
in the `Option`, and it is only taken when the service is called, rather
than every time it is polled. This fixes the bug.

I've also added a test for this which fails against master, but passes
after this change.
Signed-off-by: Eliza Weisman <eliza@buoyant.io>
2020-04-23 16:07:48 -07:00
Steven Fackler
82e578b5b0
Impl Layer for &Layer (#446) 2020-04-21 17:11:27 -04:00
Jon Gjengset
39112cb0ba
Tidy up tower::load (#445)
This also renames the `Instrument` trait, and related types, to better
reflect what they do. Specifically, the trait is now called
`TrackCompletion`, and `NoInstrument` is called `CompleteOnResponse`.

Also brings back balance example and makes it compile.
2020-04-20 14:55:40 -04:00
Jon Gjengset
05b165056b
Tidy up tower::buffer (#444) 2020-04-17 17:41:51 -04:00
Jon Gjengset
c87fdd9c1e
Change Discover to be a sealed trait (#443)
* Change Discover to be a sealed trait

`Discover` was _really_ just a `TryStream<Item = Change>`, so this
change makes that much clearer. Specifically, users are intended to use
`Discover` only in bounds, whereas implementors should implement
`Stream` with the appropriate `Item` type. `Discover` then comes with a
blanket implementation for anything that implements `TryStream`
appropriately. This obviates the need for the `discover::stream` module.
2020-04-17 16:27:44 -04:00
Jon Gjengset
5947e2e145
Some more spring clean fixes. (#442)
* Add doc feature annotations

* Modules should be published or removed
2020-04-17 16:03:15 -04:00
Lucio Franco
85b657bf93
Remove path deps for tower-service (#441) 2020-04-17 14:00:38 -04:00