transport: bump QUIC idle timeout + add keep-alive for long builds
Field finding 2026-07-12 (clawverse cold on tank):
Compiling claw-cli v0.1.0 (...)
Finished `dev` profile ... in 45.08s
cargo build finished in 45.135491979s
Error: opening bidi stream for BlobPutStream
Caused by: timed out
Cargo took 45s → QUIC's 30s idle timeout killed the connection between
the initial peer-lookup connect and the follow-up capture+upload path.
The RPC never got a chance to open its stream.
Fix: two belt-and-braces changes:
1. IDLE_TIMEOUT 30s → 600s. The timeout is there to detect crashed
peers, not to enforce build pacing.
2. Client applies a `keep_alive_interval` of 15s so the connection
stays warm across cargo runs even shorter than the idle window.
quinn's keep-alive fires from an internal runtime task, not the app
thread, so a fully-CPU-pinned cargo build doesn't suppress it.
This commit is contained in:
@@ -44,7 +44,18 @@ pub const CLAWSTOR_RPC_ALPN: &[u8] = b"clawstor-rpc/1";
|
||||
/// Idle timeout on connection — if no data for this long the connection
|
||||
/// dies. Short enough to notice partitions, long enough to survive a
|
||||
/// paused laptop.
|
||||
const IDLE_TIMEOUT: Duration = Duration::from_secs(30);
|
||||
/// Field finding 2026-07-12: raised from 30s to 10min because a long
|
||||
/// `cargo build` between the initial connect and the follow-up upload
|
||||
/// would silently kill the QUIC connection on `open_bi`. Cargo builds
|
||||
/// on real workspaces routinely run for minutes; the idle timeout is
|
||||
/// there to detect crashed peers, not to enforce interaction cadence.
|
||||
const IDLE_TIMEOUT: Duration = Duration::from_secs(600);
|
||||
|
||||
/// Field finding 2026-07-12: keep the connection warm with a ping
|
||||
/// every KEEP_ALIVE_INTERVAL — cheap belt-and-braces on top of the
|
||||
/// larger idle window so cargo runs longer than the idle timeout
|
||||
/// still stay dialed.
|
||||
const KEEP_ALIVE_INTERVAL: Duration = Duration::from_secs(15);
|
||||
|
||||
/// Cap on any single RPC message payload. Ping/pong is tiny; other RPCs
|
||||
/// stream larger payloads via streams-of-many-messages. Prevents an
|
||||
@@ -441,7 +452,19 @@ impl QuicClient {
|
||||
let client_crypto = build_client_crypto(&identity)?;
|
||||
let quic_crypto = quinn::crypto::rustls::QuicClientConfig::try_from(client_crypto)
|
||||
.context("wrapping rustls ClientConfig for quinn")?;
|
||||
let client_config = ClientConfig::new(Arc::new(quic_crypto));
|
||||
let mut client_config = ClientConfig::new(Arc::new(quic_crypto));
|
||||
// Field finding 2026-07-12: apply the raised idle timeout + a
|
||||
// keep-alive so a long cargo build between the initial connect
|
||||
// and a follow-up upload doesn't kill the connection.
|
||||
let mut transport = quinn::TransportConfig::default();
|
||||
transport
|
||||
.max_idle_timeout(Some(
|
||||
VarInt::from_u64(IDLE_TIMEOUT.as_millis() as u64)
|
||||
.expect("idle timeout fits u64")
|
||||
.into(),
|
||||
))
|
||||
.keep_alive_interval(Some(KEEP_ALIVE_INTERVAL));
|
||||
client_config.transport_config(Arc::new(transport));
|
||||
let endpoint = Endpoint::client(bind_addr).context("binding quinn client endpoint")?;
|
||||
Ok(Self {
|
||||
endpoint,
|
||||
|
||||
Reference in New Issue
Block a user