Skip to content
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

Prevent server from exiting on ECONNABORTED #1874

Merged
merged 5 commits into from
Aug 20, 2024
Merged
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 13 additions & 1 deletion tonic/src/transport/server/incoming.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,19 @@ where
let mut incoming = pin!(incoming);

while let Some(item) = incoming.next().await {
yield item.map(ServerIo::new_io)?
if let Err(e) = item {
if let Some(e) = Into::<crate::Error>::into(e).downcast_ref::<std::io::Error>() {
Copy link
Contributor

Choose a reason for hiding this comment

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

I think this is broadly acceptable but I have bunch of stylistic suggestions.

First, use a match for the top-level error extraction:

let err = match item {
    Ok(io) => yield Ok(ServerIo::new_io(io)), // Or however this is spelled
    Err(err) => err,
};

..

This reduces rightward drift.

Second, I would expect we can just call err.into() and don't need the whole Into::<crate::Error>::into(e) dance?

Third, for the debug messages, I think we should not use an explicit message = name but use the general form which is having the message after the "structured" argument (so tracing::debug!(error = %e, "accept loop error");). Note that error messages should be all-lowercase and not have any . at the end.

Fourth, please import io at the top of the file so we can drop the std:: prefixes here.

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 think this is broadly acceptable but I have bunch of stylistic suggestions.

First, use a match for the top-level error extraction:

let err = match item {
    Ok(io) => yield Ok(ServerIo::new_io(io)), // Or however this is spelled
    Err(err) => err,
};

..

This reduces rightward drift.

Second, I would expect we can just call err.into() and don't need the whole Into::<crate::Error>::into(e) dance?

Third, for the debug messages, I think we should not use an explicit message = name but use the general form which is having the message after the "structured" argument (so tracing::debug!(error = %e, "accept loop error");). Note that error messages should be all-lowercase and not have any . at the end.

Fourth, please import io at the top of the file so we can drop the std:: prefixes here.

Personally I don't have much of an opinion on these style issues, so I just changed things as requested.

There is one thing I really didn't like though, which was error extraction, which would have looked like this:

let err = match item {
    Ok(io) => { yield Ok(ServerIo::new_io(io)); continue },
    Err(err) => err,
};

do more stuff with err, then break;

So instead, I went with clearly defined Ok and Err branches (horizontal drift is IMHO acceptable). I'm quite happy with the readability of the outcome (especially having only one continue statement, pointing out the exception, and no break statements). This should also be relatively easy to parse to people who are not familiar with all language features + the diff to the master branch is very easy to understand.

tracing::debug!(message = "Accept loop error.", error = %e);
if e.kind() == std::io::ErrorKind::ConnectionAborted {
continue;
}
} else {
tracing::debug!(message = "Accept loop error (unknown error).");
}
break;
} else {
yield item.map(ServerIo::new_io)?
}
}
}
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Ok(_) => item.map(ServerIo::new_io)?

could also be written as

Ok(io) => Ok::<ServerIo<IO>, crate::Error>(ServerIo::new_io(io))?,

but in terms of readability and diff, I opted for the former (any better ideas?).

}
Expand Down