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) => {
|
||||
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