util: fix oneshot dropping pending services immediately #447
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Motivation
Commit #330 introduced a regression when porting
tower-util::Oneshot
from
futures
0.1 tostd::future
. The intended behavior is that aoneshot future should repeatedly call
poll_ready
on the oneshottedservice 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 bthe #330 version of oneshot, an
Option
is used to store therequest while waiting for the service to become ready, so that it can be
take
n and moved into the service'scall
. However, theOption
contains both the request and the service itself, and is taken the
first time the service is polled.
futures::ready!
is then used whenpolling 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 ispolled again, it will panic.
Solution
This commit changes the
Oneshot
future so that only the request livesin the
Option
, and it is only taken when the service is called, ratherthan 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.