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

server: graceful shutdown check Incoming::Closed #1216

Merged
merged 2 commits into from
Oct 16, 2023
Merged
Changes from 1 commit
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
12 changes: 8 additions & 4 deletions server/src/transport/ws.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ use jsonrpsee_types::error::{
use jsonrpsee_types::{ErrorObject, Id, InvalidRequest, Notification, Params, Request};
use soketto::connection::Error as SokettoError;
use soketto::data::ByteSlice125;
use soketto::Incoming;

use tokio::sync::{mpsc, oneshot};
use tokio_stream::wrappers::{IntervalStream, ReceiverStream};
Expand Down Expand Up @@ -564,10 +565,13 @@ async fn graceful_shutdown(
//
// The receiver is not cancel-safe such that it's used in a stream to enforce that.
let disconnect_stream = futures_util::stream::unfold((receiver, data), |(mut receiver, mut data)| async {
if let Err(SokettoError::Closed) = receiver.receive(&mut data).await {
None
} else {
Some(((), (receiver, data)))
match receiver.receive(&mut data).await {
Ok(Incoming::Closed(_)) | Err(SokettoError::Closed) => None,
Ok(Incoming::Data(_) | Incoming::Pong(_)) => Some(((), (receiver, data))),
Err(e) => {
Copy link
Collaborator

Choose a reason for hiding this comment

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

Just to check; do you no longer need to return None when Err(SokettoError::Closed) is a thing now?

Copy link
Member Author

@niklasad1 niklasad1 Oct 16, 2023

Choose a reason for hiding this comment

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

All errors except Closed are ignored here because we can't really know whether when it's closed or not otherwise.

We will keep the stream alive until either SokettoError::Closed or Incoming::Closed is returned back because some implementations may not do the proper WebSocket close handshake message such as the soketto client #871. Thus, we need to check both

However, soketto will eventually return SokettError::Closed after this https://github.com/paritytech/soketto/blob/master/src/connection.rs#L386-L388 so this extra check in this PR shouldn't matter in "practice" but we need to call receive one more time instead then also I like us to be explicit here which makes it easier to understand.

FWIW, it may also be a bunch of I/O errors that could terminate the connection as well but those are super-tricky to detect so we are relying on the close stuff... and that soketto regards EOF errors as Closed

Copy link
Collaborator

@jsdw jsdw Oct 16, 2023

Choose a reason for hiding this comment

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

Oohh I actually missed that you were still paying attention to SokettoError::Closed anyway, so yup all makes sense to me now; thanks for the explanation! :)

tracing::warn!("Graceful shutdown got WebSocket error: {e} but polling until the connection closed or all pending calls has been executed");
niklasad1 marked this conversation as resolved.
Show resolved Hide resolved
Some(((), (receiver, data)))
}
}
});

Expand Down
Loading