Skip to content

Commit dae8947

Browse files
authored
add websocket pings/pongs to help close zombie connections (#410)
1 parent 97ad5eb commit dae8947

1 file changed

Lines changed: 29 additions & 2 deletions

File tree

crates/y-sweet/src/server.rs

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,12 @@ use y_sweet_core::{
4545

4646
const PLANE_VERIFIED_USER_DATA_HEADER: &str = "x-verified-user-data";
4747

48+
// Every 20 seconds, we send a ping to the client.
49+
const PING_EVERY: Duration = Duration::from_secs(20);
50+
// If we haven't received a pong in the last 40 seconds, we close the connection.
51+
// All modern browsers will respond to websocket pings with a pong message.
52+
const PONG_TIMEOUT: Duration = Duration::from_secs(40);
53+
4854
fn current_time_epoch_millis() -> u64 {
4955
let now = std::time::SystemTime::now();
5056
let duration_since_epoch = now.duration_since(std::time::UNIX_EPOCH).unwrap();
@@ -600,9 +606,26 @@ async fn handle_socket(
600606
let (mut sink, mut stream) = socket.split();
601607
let (send, mut recv) = channel(1024);
602608

609+
let last_pong = Arc::new(RwLock::new(tokio::time::Instant::now()));
610+
let last_pong_clone = last_pong.clone();
611+
603612
tokio::spawn(async move {
604-
while let Some(msg) = recv.recv().await {
605-
let _ = sink.send(Message::Binary(msg)).await;
613+
let mut ticker = tokio::time::interval(PING_EVERY);
614+
ticker.set_missed_tick_behavior(tokio::time::MissedTickBehavior::Delay);
615+
616+
loop {
617+
tokio::select! {
618+
Some(msg) = recv.recv() => {
619+
let _ = sink.send(Message::Binary(msg)).await;
620+
}
621+
_ = ticker.tick() => {
622+
if last_pong_clone.read().expect("Failed to get read lock on last_pong").elapsed() > PONG_TIMEOUT {
623+
tracing::info!("Pong timeout, closing connection");
624+
break;
625+
}
626+
let _ = sink.send(Message::Ping(vec![])).await;
627+
}
628+
}
606629
}
607630
});
608631

@@ -618,6 +641,10 @@ async fn handle_socket(
618641
let msg = match msg {
619642
Ok(Message::Binary(bytes)) => bytes,
620643
Ok(Message::Close(_)) => break,
644+
Ok(Message::Pong(_)) => {
645+
*last_pong.write().expect("Failed to get write lock on last_pong") = tokio::time::Instant::now();
646+
continue;
647+
}
621648
Err(_e) => {
622649
// The stream will complain about things like
623650
// connections being lost without handshake.

0 commit comments

Comments
 (0)