-
-
Notifications
You must be signed in to change notification settings - Fork 1.6k
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
feat(client, server) make timers generic #2904
feat(client, server) make timers generic #2904
Conversation
One note: If we go that route, I believe we'd need to add functions like The alternative is just to use I suspect allowing changes to our Instant type is not worth the additional complexity, but let me know if you think otherwise. |
Yea I don't want to depend directly on |
c8a4eb8
to
f7264e2
Compare
Alright, I'm now working through the last major hiccup in this PR--would appreciate some guidance here if possible (potentially from @seanmonstar ?). I have a I'm trying to cook up a function signature which will allow me to include Do you have any idea how I can include or wrap something similar to |
@Robert-Cunningham you can write your own pub fn timeout<F>(duration: Duration, future: F) -> Timeout<F>
where
F: Future,
{
Timeout {
future,
sleep: sleep(duration),
}
}
pin_project_lite::pin_project! {
pub struct Timeout<F> {
#[pin]
future: F,
sleep: Box<dyn Sleep>
}
}
impl<F> Future for Timeout<F>
where
F: Future,
{
type Output = Result<F::Output, TimedOut>;
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
let mut this = self.project();
if let Poll::Ready(v) = this.future.poll(cx) {
return Poll::Ready(Ok(v));
}
match Pin::new(&mut this.sleep).poll(cx) {
Poll::Ready(()) => Poll::Ready(Err(TimedOut)),
Poll::Pending => Poll::Pending,
}
}
} |
17a4c6b
to
1aca08f
Compare
Thanks a bunch @ibraheemdev; your answer was instructive for me. With that, I think this PR is ready for review (from @seanmonstar, I think?). Please let me know if I need to do anything else before review; this is my first contribution to hyper. Once this PR is merged, I'll open a PR that adds the same |
18f0c31
to
ef358ac
Compare
Thanks so much for working on this! I'm at RustConf today, but I'll take a look beginning of next week <3 |
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 really impressed with this PR, it looks very solid! ❤️
I'm sorry for having taken a while to be able to review it, there were a lot of changes touching the same files and juggling them all in my head was too much. But most of the other changes are done, I can focus on the timer changes now. To that end, there's some code in here that can be removed (since Client
and it's pool are goners now). If it's too annoying to do, I can clean it up, just let me know. :)
src/common/tim.rs
Outdated
fn sleep(&self, duration: Duration) -> Box<dyn Sleep + Unpin> { | ||
match *self { | ||
None => { | ||
panic!("You must supply a timer.") |
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.
We could chose not to implement the trait on the type directly, and instead just have inherent methods. There's also a question of whether it should panic like this, or if we should check "if timer isn't set, don't do the time-related thing".
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.
On the second point, my original reasoning was that if you've tried set up something like header reading timeouts, but we can't do it because you didn't give us a timer, we should fail loudly (panic). The failure mode otherwise--not doing the timeouts--seems subtle and likely only to be discovered when it causes a problem for the user in the future.
On the first point, I'm not sure I understand your suggestion fully. You're saying that instead of implementing Timer
on Time
, we could add these as inherent methods of Timer
? Would you mind elaborating a bit more?
@@ -74,12 +76,13 @@ impl Default for Config { | |||
} | |||
|
|||
pin_project! { | |||
pub(crate) struct Server<T, S, B, E> | |||
pub(crate) struct Server<T, S, B, E, M> |
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.
Do you feel including the generic provides much value? Since the common::time::Time
enum already holds an arced trait object, holding onto that could eliminate the need for the timer.
(The generic for the executor is different, it's propagating the Send
iness of the future to the task that is spawned. I don't believe there's anything a timer needs to propagate there.)
pub trait Sleep: Send + Sync + Unpin + Future<Output = ()> { | ||
|
||
/// An analogue of tokio::time::Sleep::deadline. | ||
fn deadline(&self) -> Instant; |
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.
Do we need these methods? They do seem convenient, but if hyper can live without them, that may be easier for different timer implementations that might not keep that information around. Or that might not be easily reset
.
@dhobsd would these methods be hard to implement in Fuchsia land?
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 for remembering us and reaching out! (Sorry for delay!)
Fuchsia's async executor uses deadlines for its time, so that's at least good. Two points to bring up:
reset
in tokio says "This function can be called both before and after the future has completed." In fuchsia_async's Timer, this isn't true -- you can only reset a timer that's already fired. I'm also not sure what it means to reset a timer that hasn't fired because it's hard to guarantee you won't observe the signal. Does hyper reset timers that haven't fired?is_elapsed
says that it returns true when the time has elapsed, but is this the same as saying the timer has already fired?
I guess a third question: will hyper rely on these divergent behaviors? If not, perhaps we can make the documentation stricter in hyper's trait?
Ah, thanks for your feedback--I appreciate the detail. I'm headed to burning man until September 6, but I'm going to try to get this over the goal line before I arrive today. If I don't manage to finish before I lose cell service, please feel free to make any changes as you see fit and merge--I don't want to stand in the way of progress on 1.0! |
Thanks so much for taking it this far! I've opened #2974 that rebases this, and I may tweak a little more, and then merge. |
Hi Sean,
I'm working through the timer series of issues (#2847, #2846, #2848, #2857) right now. This PR isn't (near) done, but I wanted to do a midway check-in and see if you agree with the design decisions, or have any feedback that I can integrate now, relatively early on in the process.
In particular, I'd appreciate any broad design feedback you have on
rt.rs
ortim.rs
.Otherwise I'll continue moving forwards with this series of issues!
Thanks for your work on hyper!