-
Notifications
You must be signed in to change notification settings - Fork 341
Change the timeout API? #18
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
Comments
I do agree that I think the |
In the original futures post timeouts were done by The only thing that doesn't seem covered so far is how to create a stream of intervals. For any sort of UI loop or intermittent checking this seems incredibly important. Where should it be placed if not in a In general I don't like the free functions proposed here. I feel we can do better. |
How about I'm not a huge fan of using very generic methods like I'm also generally not a huge fan of free functions, but in this case, I like that the following works, if we change the argument order: io::timeout(Duration::from_secs(5), async {
//.... something
}); |
Sketch code. Another option would be: struct Timeout {
//...
}
impl Timeout {
fn of_duration(d: Duration) -> Self;
fn on<F: Future>(&self, f: F) { } -> TimeoutFuture;
fn try<F: Future<Output=Result<O, E>>, O, E>(&self, f : F) {} -> TryTimeout;
}
fn main () {
let timeout = Timeout::of_duration(Duration::from_secs(5));
timeout.on(async {});
timeout.try(async { Ok((()) })
} This still needs the user to do the right thing, sadly. The underlying problem (no specialization) will persist in any api design. Note that this allows timeout to be reused and e.g. stored as a config value. Alternatively, it also allows |
You probably meant
One idea is to do I kind of want to challenge the assumption that time-related futures and streams should go into the I just find it jarring because there's nothing in |
@stjepang This is a fantastic idea! I'm fully supportive of this.
Lol oops, yeah. I'm behind a laptop again, and the way I'd see these being used is: // equivalent to `futures::timeout`.
let res = reg_fut.select(task::sleep(Duration::from_secs(1))?;
// equivalent to `io::timeout`.
let res = io_fut.try_select(task::sleep(Duration::from_secs(1))?; I'm very sympathetic to @skade's argument that timeouts would benefit from more visibility, and this is def lacking in that department. In general I quite like removing io::timeout(Duration::from_secs(5), async {
//.... something
})?; It's different from the ordering precedent set in, say |
I like Could make timeouts restricted on futures where F::Output implements impl<F, T> Future for TimeoutFuture<F, T>
where:
F: Future,
F::Output: From<std::io::Result<T>>
{
type Output = F::Output;
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
match self.as_mut().future().poll(cx) {
Poll::Ready(v) => Poll::Ready(Ok(v)),
Poll::Pending => match self.delay().poll(cx) {
Poll::Ready(_) => Poll::Ready(F::Output::from(Err(
std::io::Error::new(ErrorKind::TimedOut, "future timed out")
))),
Poll::Pending => Poll::Pending,
},
}
}
} |
In addition to the current variant? IMHO the current variant is useful on its own for non-IO futures too. You might have some more complicated user defined futures (which might or might not be around IO futures) that don't return a plain Removing the current variant would seem suboptimal to me. |
Just as example I prefer timeouts that allow me to restart and retrieve original future on failure:
|
@DoumanAsh If Unless I'm missing something, there's not much reason to return the original future since one can use a mutable borrow of the future. Do you agree with that assessment? |
It is indeed true, that with There is also matter of storing this future, which becomes a user responsibility |
Is that not true also for the case when the timeout function returns the original future back to the user? If |
The original issue has been resolved, and conversation has settled down. I'm going to go ahead and close this for now (: |
Timeouts are confusing. @spacejam recently wrote an example that contains the following piece of code:
The problem here is that we need two
?
s after.await
and it's easy to forget that.I think the confusing part is in that the
.timeout()
combinator looks like it just transforms the future in a similar vein to.map()
or.and_then()
, but it really does not!Instead,
.timeout()
bubbles the result of the future so that its type becomesResult<Result<_, io::Error>, TimeoutError>
.Perhaps it would be less confusing if
timeout()
was a free-standing function in thefuture
module rather than a method on thetime::Timeout
extension trait?This
timeout()
function would stand alongsideready()
,pending()
, and maybe some other convenience functions in thefuture
module.Here's another idea. What if we had
io::timeout()
function that resolves to aResult<_, io::Error>
instead of bubbling the results? Then we could write the following with a single?
:Now it's also more obvious that we're setting a timeout for an I/O operation and not for an arbitrary future.
In addition to that, perhaps we could delete the whole
time
module? I'm not really a fan of it because it looks nothing likestd::time
and I generally dislike extension traits likeTimeout
.Note that we already have a time-related function,
task::sleep()
, which is not placed in thetime
module so we probably shouldn't worry about grouping everything time-related into thetime
module. I think it's okay if we haveio::timeout()
andfuture::timeout()
.Finally, here's a really conservative proposal. Let's remove the whole
time
module and only haveio::timeout()
. A more generic function for timeouts can then be left for later design work. I think I prefer this option the most.The text was updated successfully, but these errors were encountered: