fix(server): Do not panic when a channel read fails
A read timeout or an abrupt client hang-up unwound the channel thread, which flooded the logs with "closing channel" panics and skipped the connected clients counter decrement, leaking a client slot each time. Fixes #256
This commit is contained in:
1 parent
c492bcc85f
commit
cb9cbacdd3
2 files changed
+54
-2
No files matched your search
@@ -216,9 +216,11 @@ impl ChannelHandle {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
tracing::error!("closing channel thread with traceback: {}", err);
|
// NOTE: Panicking here would unwind past the connected clients
|
||||||
|
// counter decrement in `client()`, leaking a client slot.
|
||||||
|
tracing::debug!("closing channel thread: {}", err);
|
||||||
|
|
||||||
panic!("closing channel");
|
break 'handler;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,50 @@
|
|||||||
|
// Sonic
|
||||||
|
//
|
||||||
|
// Fast, lightweight and schema-less search backend
|
||||||
|
// Copyright: 2026, DualFroz <me@dualfroz.com>
|
||||||
|
// License: Mozilla Public License v2.0 (MPL v2.0)
|
||||||
|
|
||||||
|
mod common;
|
||||||
|
|
||||||
|
use std::io::{BufRead, BufReader, Write};
|
||||||
|
use std::net::TcpStream;
|
||||||
|
use std::time::Duration;
|
||||||
|
|
||||||
|
use crate::common::prelude::*;
|
||||||
|
|
||||||
|
const TCP_TIMEOUT: u64 = 1;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn read_timeout_releases_client_slot() {
|
||||||
|
let ctx =
|
||||||
|
start_empty(|command| command.env("SONIC_CHANNEL__TCP_TIMEOUT", TCP_TIMEOUT.to_string()));
|
||||||
|
|
||||||
|
{
|
||||||
|
let mut stream = TcpStream::connect(ctx.addr).unwrap();
|
||||||
|
let mut reader = BufReader::new(stream.try_clone().unwrap());
|
||||||
|
let mut line = String::new();
|
||||||
|
|
||||||
|
reader.read_line(&mut line).unwrap();
|
||||||
|
|
||||||
|
stream
|
||||||
|
.write_all(format!("START search {SONIC_PASSWORD}\n").as_bytes())
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
line.clear();
|
||||||
|
reader.read_line(&mut line).unwrap();
|
||||||
|
assert!(line.starts_with("STARTED"), "unexpected greeting: {line:?}");
|
||||||
|
|
||||||
|
// Stay idle until the server hits its read timeout, then hang up.
|
||||||
|
std::thread::sleep(Duration::from_secs(TCP_TIMEOUT + 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
std::thread::sleep(Duration::from_millis(200));
|
||||||
|
|
||||||
|
let multiplexer = SonicMultiplexer::new().unwrap();
|
||||||
|
let control =
|
||||||
|
SonicChannelControlBlocking::connect(ctx.addr, SONIC_PASSWORD, &multiplexer).unwrap();
|
||||||
|
|
||||||
|
let stats = control.info().unwrap();
|
||||||
|
|
||||||
|
assert_eq!(stats.clients_connected, 1);
|
||||||
|
}
|
||||||
Reference in new issue
Block a user