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

How can I send pong frames as heartbeats from a client? #329

Closed
hibnikar opened this issue May 7, 2024 · 4 comments
Closed

How can I send pong frames as heartbeats from a client? #329

hibnikar opened this issue May 7, 2024 · 4 comments
Labels

Comments

@hibnikar
Copy link

hibnikar commented May 7, 2024

Suppose I have a client that listens to messages from WS server and simply persits them somewhere else. Server periodically sends ping frames and tungstenite-rs automatically responds with proper pong frames.

However, now the server has introduced a requirement to periodically send pong frames with some custom content as a way to show that the client is still interested in updates.

I've quickly found this comment in tungstenite-rs repo where you are advised to invoke write_pending()? to make sure default pong response is not overwritten with the custom one and only then sending custom pong frame.

But how do i do this in tokio-tungstenite?

Is doing something like

type SocketStream = WebSocketStream<MaybeTlsStream<TcpStream>;

async fn send_custom_pong(&mut sink: SplitSink<SocketStream>, Message>) -> Result<(), WsError> {
    sink.flush().await?;

    Ok(sink.send(Message::Pong(create_custom_pong()).await?)
}

would work? Would this work in case the code sends a lot of data to the server or is there a better way to handle this?

@agalakhov
Copy link
Member

You can just send Pong just like you send normal messages, there is nothing special about it.

@hibnikar
Copy link
Author

hibnikar commented May 7, 2024

Welp, mentioned issue says

If using through tokio-tungstenite or other code that splits reader and writer tasks,
things become complicated, because now you have to communicate from your reader that
received the ping that your writer should call write_pending before sending the next pong,
and through tokio-tungstenite write_pending isn't exactly accessible.

Is this no longer valid?

@agalakhov
Copy link
Member

This is valid, but this is not so different from other (non-ping) communications. Reading includes write_pending(), so if you read all the time, it will be called. Just make sure it happens.

@daniel-abramov
Copy link
Member

@hibnikar I've just read your question and checked the aforementioned issue. If I got your use case right, then yes—the solution that you proposed should achieve the behavior you want. However, beware that your task must not yield between flush() and send() if there is a reader task working in parallel (otherwise, you'll run into a problem that was described in the issue that you linked).

Unfortunately, I can't think of a better way to handle this situation without some drawbacks. Ideally, we would need to solve the original issue to allow for the handling of such cases in a more elegant way. Currently, close and pong frames are handled in a special way (which is good if you want a simple/typical behavior but not particularly useful when your logic is a bit more sophisticated).

Hope this helps.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

3 participants