From 2427b22204c72443fd1890583e39568140037ea4 Mon Sep 17 00:00:00 2001 From: tv Date: Mon, 26 Oct 2026 19:00:35 +0100 Subject: POST timeout depends on content size Replace the fixed timeout by a variable one depending on content size with the formula: 10 s + content-size / 1 MiB/s --- src/transport/mycelium/mod.rs | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) (limited to 'src/transport') diff --git a/src/transport/mycelium/mod.rs b/src/transport/mycelium/mod.rs index f20f6a0..4edd1fd 100644 --- a/src/transport/mycelium/mod.rs +++ b/src/transport/mycelium/mod.rs @@ -15,6 +15,13 @@ pub mod daemon; pub use daemon::{MyceliumSetup, MyceliumSpawnConfig}; const MYCELIUM_POLL_TIMEOUT_SECS: u64 = 300; +/// How long a request to our Mycelium may take, before what its body adds +/// (`post_timeout`). +const REQUEST_TIMEOUT: Duration = Duration::from_secs(10); +/// The slowest our Mycelium is expected to take a message body, in bytes per second: +/// a large sync message gets more time than a PING, instead of failing (and being +/// generated and sent whole again) at a fixed limit. +const POST_MIN_RATE: u64 = 1 << 20; /// The one Mycelium topic all of continuum's messages travel on; what a message is, its /// payload says (`wire`). @@ -74,7 +81,7 @@ impl MyceliumTransport { let rest_url = setup.rest_url.clone(); let client = reqwest::Client::builder() - .timeout(Duration::from_secs(10)) + .timeout(REQUEST_TIMEOUT) .build()?; let poll_client = reqwest::Client::builder() .timeout(Duration::from_secs(MYCELIUM_POLL_TIMEOUT_SECS + 30)) @@ -205,6 +212,7 @@ impl Transport for MyceliumTransport { .client .post(self.messages_endpoint.clone()) .header(reqwest::header::CONTENT_TYPE, "application/json") + .timeout(post_timeout(message.body.len())) .body(message.body.clone()) .send() .await?; @@ -398,6 +406,12 @@ fn encode_payload(payload: &Vec) -> String { BASE64.encode(payload) } +/// How long posting a body of `bytes` may take: `REQUEST_TIMEOUT`, plus the body at +/// `POST_MIN_RATE`. +fn post_timeout(bytes: usize) -> Duration { + REQUEST_TIMEOUT + Duration::from_millis(bytes as u64 * 1000 / POST_MIN_RATE) +} + /// Length of what padded base64 `encoded` decodes to. fn base64_decoded_len(encoded: &str) -> usize { let padding = encoded.bytes().rev().take_while(|&b| b == b'=').count(); @@ -478,6 +492,15 @@ mod tests { /// Mycelium splits messages into chunks of this size. const MYCELIUM_CHUNK: usize = 1300; + #[test] + fn post_timeout_grows_with_the_body() { + assert_eq!(post_timeout(0), REQUEST_TIMEOUT); + assert_eq!( + post_timeout(64 << 20), + REQUEST_TIMEOUT + Duration::from_secs(64) + ); + } + #[test] fn largest_keepalive_fits_in_one_chunk() { let keepalive = Keepalive { -- cgit v1.3.1