From 2f5286a387e5fb6325e21fecccf9b65a3f2e6f2c Mon Sep 17 00:00:00 2001 From: Mojtaba Jafarzadeh Date: Mon, 26 Oct 2026 09:29:27 +0330 Subject: [PATCH] collab-net: server keeps publish uploads alive with the reply timeout A publish uploads a whole file; a large project on a slow link takes the server a while to receive and answer. But the server's one-shot request connections (manage, hosting, library, plugins) used the short request_idle as their read timeout, so a slow upload could be cut off mid-processing. The manage/hosting connections that carry uploads now wait the longer request_reply_timeout (as the client already did), keeping the short idle for the other one-shot requests and sessions. Co-Authored-By: Claude --- crates/collab-net/src/hub.rs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/crates/collab-net/src/hub.rs b/crates/collab-net/src/hub.rs index c2202919..1471c179 100644 --- a/crates/collab-net/src/hub.rs +++ b/crates/collab-net/src/hub.rs @@ -956,11 +956,18 @@ fn serve(mut stream: TcpStream, conn: u64, hub: &Sender, limits: NetLimit // Sessions and the operator may use the last connections; one-shot requests // (hosting, libraries, browsing plugins) leave them free. let session = matches!(first, ClientMsg::Hello(_) | ClientMsg::Manage(_)); + // A publish uploads a whole file; a large one on a slow link takes the server a + // while to receive and answer. The manage/hosting connections that carry uploads + // wait the longer request-reply timeout, not the short request idle. + let idle = match first { + ClientMsg::Manage(_) | ClientMsg::OpenHosting(_) => limits.request_reply_timeout, + ClientMsg::Hello(_) => limits.idle_timeout, + _ => limits.request_idle, + }; let max = match &first { ClientMsg::OpenPlugins(o) if o.key.is_empty() => limits.max_request, _ => limits.max_client_message, }; - let idle = if session { limits.idle_timeout } else { limits.request_idle }; let reserved = !session && open.0.load(Ordering::Relaxed) > limits.max_connections.saturating_sub(limits.reserve_for_sessions); // (In flight is only taken when the connection goes on: the hub gives it back.) if reserved || !shared.in_flight.take(bytes, limits.max_in_flight) {