Skip to content

Commit 764e1e1

Browse files
fix: configurable timeout for AI requests (#6497) (#7267)
* fix: configurable timeout for AI requests Add AI_REQUEST_TIMEOUT_SECONDS environment variable (default 3600s) to fix timeout issues with slow AI models like self-hosted Ollama. Previously hardcoded at 300 seconds, causing legitimate long-running requests to fail. Fixes #6497 * docs(ai): add critical NGINX configuration warning Add comprehensive documentation about reverse proxy timeout requirements. Without proper NGINX/proxy configuration, connections will still timeout at the proxy layer regardless of backend timeout settings. Enhanced documentation includes: - CRITICAL warning about proxy configuration requirement - Example NGINX configuration snippet - Explanation of proxy vs backend timeout interaction This addresses the root cause in issue #6497 where logs showed "upstream prematurely closed connection" indicating proxy-level timeout. Part of #6497
1 parent a23d4f0 commit 764e1e1

File tree

2 files changed

+68
-2
lines changed

2 files changed

+68
-2
lines changed

backend/windmill-api/src/ai.rs

Lines changed: 67 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,76 @@ use windmill_common::error::{to_anyhow, Error, Result};
1414
use windmill_common::utils::configure_client;
1515
use windmill_common::variables::get_variable_or_self;
1616

17+
// AI timeout configuration constants
18+
const AI_TIMEOUT_MIN_SECS: u64 = 1;
19+
const AI_TIMEOUT_MAX_SECS: u64 = 86400; // 24 hours
20+
const AI_TIMEOUT_DEFAULT_SECS: u64 = 3600; // 1 hour
21+
const HTTP_POOL_MAX_IDLE_PER_HOST: usize = 10;
22+
const HTTP_POOL_IDLE_TIMEOUT_SECS: u64 = 90;
23+
1724
lazy_static::lazy_static! {
25+
/// AI request timeout in seconds.
26+
///
27+
/// This timeout applies to the TOTAL duration of AI HTTP requests,
28+
/// including streaming responses. Default is 3600 seconds (1 hour).
29+
///
30+
/// Can be configured via AI_REQUEST_TIMEOUT_SECONDS environment variable.
31+
/// Valid range: 1-86400 seconds (24 hours).
32+
/// - Minimum (1s): Prevents immediate timeout, allows minimal response time
33+
/// - Maximum (24h): Prevents indefinite hangs while supporting long-running AI operations
34+
/// - Default (1h): Balances responsiveness with support for complex AI tasks
35+
///
36+
/// Note: This is a total request timeout, not an idle timeout.
37+
/// Long-running streaming responses that exceed this duration will be terminated,
38+
/// even if actively receiving data.
39+
///
40+
/// CRITICAL: If using a reverse proxy (NGINX, Traefik, etc.), you MUST configure
41+
/// proxy timeouts to match or exceed this value. Without proper proxy configuration,
42+
/// connections will be terminated prematurely at the proxy layer regardless of this
43+
/// backend timeout setting.
44+
///
45+
/// Example NGINX configuration:
46+
/// location /api/ {
47+
/// proxy_read_timeout 3600s; # Must be >= AI_REQUEST_TIMEOUT_SECONDS
48+
/// proxy_send_timeout 3600s;
49+
/// proxy_connect_timeout 60s;
50+
/// }
51+
static ref AI_TIMEOUT_SECS: u64 = {
52+
match std::env::var("AI_REQUEST_TIMEOUT_SECONDS")
53+
.ok()
54+
.and_then(|s| s.parse::<u64>().ok())
55+
{
56+
Some(timeout) if timeout >= AI_TIMEOUT_MIN_SECS && timeout <= AI_TIMEOUT_MAX_SECS => {
57+
tracing::info!("AI request timeout configured: {}s", timeout);
58+
timeout
59+
},
60+
Some(timeout) => {
61+
tracing::warn!(
62+
"AI_REQUEST_TIMEOUT_SECONDS value {} is out of range ({}-{}), using default {}s",
63+
timeout,
64+
AI_TIMEOUT_MIN_SECS,
65+
AI_TIMEOUT_MAX_SECS,
66+
AI_TIMEOUT_DEFAULT_SECS
67+
);
68+
AI_TIMEOUT_DEFAULT_SECS
69+
},
70+
None => {
71+
tracing::info!(
72+
"AI_REQUEST_TIMEOUT_SECONDS not set, using default {}s",
73+
AI_TIMEOUT_DEFAULT_SECS
74+
);
75+
AI_TIMEOUT_DEFAULT_SECS
76+
},
77+
}
78+
};
79+
1880
static ref HTTP_CLIENT: Client = configure_client(reqwest::ClientBuilder::new()
19-
.timeout(std::time::Duration::from_secs(60 * 5))
81+
.timeout(std::time::Duration::from_secs(*AI_TIMEOUT_SECS))
82+
.pool_max_idle_per_host(HTTP_POOL_MAX_IDLE_PER_HOST)
83+
.pool_idle_timeout(Some(std::time::Duration::from_secs(HTTP_POOL_IDLE_TIMEOUT_SECS)))
2084
.user_agent("windmill/beta"))
21-
.build().unwrap();
85+
.build()
86+
.expect("Failed to build AI HTTP client - check system TLS configuration");
2287

2388
static ref OPENAI_AZURE_BASE_PATH: Option<String> = std::env::var("OPENAI_AZURE_BASE_PATH").ok();
2489

backend/windmill-common/src/global_settings.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,7 @@ pub const ENV_SETTINGS: &[&str] = &[
114114
"DISABLE_S3_STORE",
115115
"PG_SCHEMA",
116116
"PG_LISTENER_REFRESH_PERIOD_SECS",
117+
"AI_REQUEST_TIMEOUT_SECONDS",
117118
];
118119

119120
use crate::error;

0 commit comments

Comments
 (0)