Skip to content

Comments

refactor: Start translating server.rs to async await#787

Closed
Marwes wants to merge 1 commit intomozilla:masterfrom
Marwes:async_server
Closed

refactor: Start translating server.rs to async await#787
Marwes wants to merge 1 commit intomozilla:masterfrom
Marwes:async_server

Conversation

@Marwes
Copy link
Contributor

@Marwes Marwes commented Jun 8, 2020

No description provided.

@froydnj
Copy link
Contributor

froydnj commented Jun 9, 2020

This is really interesting, because we kind of thought there was no good way to incrementally transition to new futures. I assume you basically sprinkle .compat() everywhere and then at some point you can go through and remove all of them?

@luser is this basically what y'all did internally?

@luser
Copy link
Contributor

luser commented Jun 9, 2020

We don't use tokio except for some testing tools so it wasn't as much of a hassle for us. Looks like that's basically what we did for those, though.

@glandium glandium self-requested a review June 10, 2020 01:20
@Marwes
Copy link
Contributor Author

Marwes commented Jun 10, 2020

Yes. My preferred way is to start from the top, replacing things with async/await/std::fuuture::Future and calling compat on any old futures. Then this can repeated, pushing the compat calls deeper into the stack until finally they are completely gone. (By starting from the top it is possible to replace cloning by borrowing in many cases).

Copy link
Collaborator

@glandium glandium left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you a lot. I wish it would have been done in smaller increments to ease review, but that's what I failed to do, so 🤷 . Not mentioned in the inline comments: there's a warning about #[macro_use] that you removed in a subsequent patch that should be part of this one.

Cargo.toml Outdated
blake3 = "0.1.5"
byteorder = "1.0"
bytes = "0.4"
bytes_05 = { version = "0.5", package = "bytes" }
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

bytes 0.4 is actually unused since 17c56c8, so you don't need the suffix.

}
})?;
.block_on_std(async { time::timeout(Duration::new(30, 0), wait).await })
.map_err(|e| io::Error::new(io::ErrorKind::Other, e))?;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This triggers a warning that should be avoided in this patch rather than later:

594 | /         runtime
595 | |             .block_on_std(async { time::timeout(Duration::new(30, 0), wait).await })
596 | |             .map_err(|e| io::Error::new(io::ErrorKind::Other, e))?;
    | |___________________________________________________________________^
    |
    = note: `#[warn(unused_must_use)]` on by default
    = note: this `Result` may be an `Err` variant, which should be handled

You're kind of addressing this in the last patch, but it feels like it should be addressed here instead. That part of the other patch is too much repeating too. How about changing the Output for WaitUntilZero to () instead of io::Result<()>?
It also looks like for some reason (not sure where this is happening), there's an impl From<tokio::time::Elapsed> for std::io::Error, and removing the map_err works.

}
}

struct BincodeCodec;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

github doesn't allow to comment on unpatches sections but there's a compile failure in impl<R> futures_03::Stream for Body<R> because the receiver changed type and doesn't have poll anymore. It does have poll_next, though, which simplifies the implementation.

src/server.rs Outdated

fn serialize(self: Pin<&mut Self>, item: &T) -> std::result::Result<Bytes, Self::Error> {
let mut bytes = BytesMut::new();
use bytes_05::buf::BufMutExt;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This can go at the top of the file.

src/server.rs Outdated
Ok(msg.map(Message::WithoutBody).into())
fn poll_next(mut self: Pin<&mut Self>, cx: &mut task::Context<'_>) -> Poll<Option<Self::Item>> {
Poll::Ready(
ready!(Stream::poll_next(Pin::new(&mut self.inner), cx))
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it more idiomatic than Pin::new(&mut self.inner).poll_next(cx)?

src/server.rs Outdated
io::Error::new(io::ErrorKind::Other, e)
}));
Ok(msg.map(Message::WithoutBody).into())
fn poll_next(mut self: Pin<&mut Self>, cx: &mut task::Context<'_>) -> Poll<Option<Self::Item>> {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

task::Context is a reexport of std::task::Context, which is imported already, please just use Context.

src/server.rs Outdated
future,
prelude::*,
ready, stream,
task::{self, Poll},
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Poll is a reexport of std::task::Poll, please import Poll from there instead. As a follow-up, we can replace std::task::Poll with Poll in this file.

src/server.rs Outdated
// Shutdown received!
Async::Ready(Some(ServerMessage::Shutdown)) => return Ok(().into()),
Async::Ready(Some(ServerMessage::Request)) => {
Poll::Ready(Some(ServerMessage::Shutdown)) => return ().into(),
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

return Poll::Ready(())?

src/server.rs Outdated
}
// All services have shut down, in theory this isn't possible...
Async::Ready(None) => return Ok(().into()),
Poll::Ready(None) => return ().into(),
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Likewise.

src/server.rs Outdated
.poll()
.map_err(|err| io::Error::new(io::ErrorKind::Other, err)),
None => Poll::Pending,
Some(ref mut timeout) => ready!(Pin::new(timeout).poll(cx)).into(),
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is the ready!().into() necessary? I now wonder if that's what was missing in my failed attempt at converting this impl.

Copy link
Collaborator

@glandium glandium Jun 11, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(It wasn't the lack of ready! that made my own attempt fail)

src/errors.rs Outdated
TempfilePersist(tempfile::PersistError);
WalkDir(walkdir::Error);
Timer(tokio_timer::Error);
Timeout(tokio::time::Elapsed);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is likely to lose the race against #777 so you may want to rebase on top of that one after it's merged.

type Response = SccacheResponse;
type Error = Error;
type Future = SFuture<Self::Response>;
type Future = Pin<Box<dyn Future<Output = Result<Self::Response>>>>;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A SFuture03 alias would be valuable.

Message::WithoutBody(Response::ShuttingDown(Box::new(info)))
}));
let self_ = self.clone();
Box::pin(async move {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not particularly convinced using async here is better than not.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why? This allows await to be used, making it more flexible.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It moves some code into a future, and as of right now, I'm not sure this is desired.

let r: Result<Box<dyn Compiler<C>>> = info.map(|info| info.0);
r
}
}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Less indentation FTW.

cache_control,
self.pool.clone(),
)
.compat();
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I really hate what rustfmt does when you add .compat(). Not much you can do about though (although you could probably do something like let result = ...; let result = result.compat();). It's just the nth I see and I had to say it.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

compat calls are just temporary 🤷

res.color_mode = color_mode;
match result {
Ok((compiled, out)) => {
let mut stats = me.stats.borrow_mut();
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's only one Error branch that doesn't use stats. I don't feel it needs to be moved.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I had to move it to prevent it from living across an await

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Moving it back to where it was compiled just fine for me.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It may compile fine, but it can still break because another future accessing the RefCell may run if the future yields in the await

@Marwes
Copy link
Contributor Author

Marwes commented Jun 10, 2020

Should have rebased and squashed these commits before making the PR, don't want to do it now since it messes up reviews.

Copy link
Collaborator

@glandium glandium left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you rebase on top of #792, and squash things, but still separate the tokio-0.2 and the async-await parts?

Cargo.lock Outdated
"bincode",
"blake3",
"byteorder",
"bytes 0.4.12",
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why does this not remove the corresponding [[package]] section?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are still other dependencies that require bytes 0.4

@Marwes Marwes force-pushed the async_server branch 2 times, most recently from 0113664 to 0a3d55e Compare June 11, 2020 08:29
Copy link
Collaborator

@glandium glandium left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The nits for this commit were applied in the second commit :(

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants