From bbbf1818a1d70ad188919781ddff5e7c0855f22e Mon Sep 17 00:00:00 2001 From: Ian MacDonald Date: Fri, 20 Mar 2026 10:25:46 -0400 Subject: [PATCH] fix: pass global-timeout to router and use it for sd-server proxy MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The sd-server proxy used hardcoded 600s timeouts for image generation, edits, and variations — causing failures for models that take longer (e.g. Qwen Image Edit at ~36 min on consumer GPUs). Additionally, LEMONADE_GLOBAL_TIMEOUT was never propagated from lemonade-server to lemonade-router because ServerManager didn't pass --global-timeout in the subprocess args. Changes: - sd_server.cpp: replace hardcoded 600s with get_default_timeout() - ServerManager: accept and forward global_timeout to router via --global-timeout arg (both Unix execv and Windows CreateProcess) - TrayApp: pass server_config_.global_timeout to start_server() Co-Authored-By: Claude Opus 4.6 (1M context) --- src/cpp/include/lemon_tray/server_manager.h | 4 +++- src/cpp/server/backends/sd_server.cpp | 8 ++++---- src/cpp/tray/server_manager.cpp | 18 ++++++++++++++++-- src/cpp/tray/tray_app.cpp | 6 ++++-- 4 files changed, 27 insertions(+), 9 deletions(-) diff --git a/src/cpp/include/lemon_tray/server_manager.h b/src/cpp/include/lemon_tray/server_manager.h index 97d218a9a..5f78224b8 100644 --- a/src/cpp/include/lemon_tray/server_manager.h +++ b/src/cpp/include/lemon_tray/server_manager.h @@ -52,7 +52,8 @@ class ServerManager { bool is_ephemeral, const std::string& host, int max_loaded_models, - const std::string& extra_models_dir + const std::string& extra_models_dir, + long global_timeout = 300 ); bool stop_server(); @@ -112,6 +113,7 @@ class ServerManager { std::string api_key_; int port_; int max_loaded_models_; + long global_timeout_ = 300; nlohmann::json recipe_options_; bool show_console_; bool is_ephemeral_; // Suppress output for ephemeral servers diff --git a/src/cpp/server/backends/sd_server.cpp b/src/cpp/server/backends/sd_server.cpp index b7953f93e..0b9c7e3ee 100644 --- a/src/cpp/server/backends/sd_server.cpp +++ b/src/cpp/server/backends/sd_server.cpp @@ -252,8 +252,8 @@ json SDServer::image_generations(const json& request) { LOG(DEBUG, "SDServer") << "Forwarding request to sd-server: " << sd_request.dump(2) << std::endl; - // Use base class forward_request with 10 minute timeout for image generation - return forward_request("/v1/images/generations", sd_request, 600); + // Image generation can take 20+ minutes for large models — use global timeout + return forward_request("/v1/images/generations", sd_request, utils::HttpClient::get_default_timeout()); } json SDServer::image_edits(const json& request) { @@ -307,7 +307,7 @@ json SDServer::image_edits(const json& request) { << " size=" << request.value("size", "") << std::endl; - return forward_multipart_request("/v1/images/edits", fields, 600); + return forward_multipart_request("/v1/images/edits", fields, utils::HttpClient::get_default_timeout()); } json SDServer::image_variations(const json& request) { @@ -335,7 +335,7 @@ json SDServer::image_variations(const json& request) { << " size=" << request.value("size", "") << std::endl; - return forward_multipart_request("/v1/images/edits", fields, 600); + return forward_multipart_request("/v1/images/edits", fields, utils::HttpClient::get_default_timeout()); } } // namespace backends diff --git a/src/cpp/tray/server_manager.cpp b/src/cpp/tray/server_manager.cpp index b54f0eb3e..27a9b9c88 100644 --- a/src/cpp/tray/server_manager.cpp +++ b/src/cpp/tray/server_manager.cpp @@ -56,7 +56,8 @@ bool ServerManager::start_server( bool is_ephemeral, const std::string& host, int max_loaded_models, - const std::string& extra_models_dir) + const std::string& extra_models_dir, + long global_timeout) { if (is_server_running()) { LOG(DEBUG, "ServerManager") << "Server is already running" << std::endl; @@ -67,6 +68,7 @@ bool ServerManager::start_server( port_ = port; recipe_options_ = recipe_options; max_loaded_models_ = max_loaded_models; + global_timeout_ = global_timeout; log_file_ = log_file; log_level_ = log_level; show_console_ = show_console; @@ -228,7 +230,7 @@ bool ServerManager::stop_server() { bool ServerManager::restart_server() { stop_server(); std::this_thread::sleep_for(std::chrono::seconds(1)); - return start_server(server_binary_path_, port_, recipe_options_, log_file_, log_level_, show_console_, false, host_, max_loaded_models_, extra_models_dir_); + return start_server(server_binary_path_, port_, recipe_options_, log_file_, log_level_, show_console_, false, host_, max_loaded_models_, extra_models_dir_, global_timeout_); } bool ServerManager::is_server_running() const { @@ -363,6 +365,10 @@ bool ServerManager::spawn_process() { if (!extra_models_dir_.empty()) { cmdline += " --extra-models-dir \"" + extra_models_dir_ + "\""; } + // Global timeout (only if not default) + if (global_timeout_ != 300) { + cmdline += " --global-timeout " + std::to_string(global_timeout_); + } LOG(DEBUG, "ServerManager") << "Starting server: " << cmdline << std::endl; @@ -581,6 +587,14 @@ bool ServerManager::spawn_process() { args.push_back(extra_models_dir_.c_str()); } + // Global timeout (only if not default) + std::string global_timeout_str; + if (global_timeout_ != 300) { + args.push_back("--global-timeout"); + global_timeout_str = std::to_string(global_timeout_); + args.push_back(global_timeout_str.c_str()); + } + args.push_back(nullptr); execv(server_binary_path_.c_str(), const_cast(args.data())); diff --git a/src/cpp/tray/tray_app.cpp b/src/cpp/tray/tray_app.cpp index 246d50194..dd4151c1c 100644 --- a/src/cpp/tray/tray_app.cpp +++ b/src/cpp/tray/tray_app.cpp @@ -1103,7 +1103,8 @@ bool TrayApp::start_ephemeral_server(int port) { true, // is_ephemeral (suppress startup message) server_config_.host, // Pass host to ServerManager server_config_.max_loaded_models, - server_config_.extra_models_dir // Pass extra models directory + server_config_.extra_models_dir, // Pass extra models directory + server_config_.global_timeout ); if (!success) { @@ -2272,7 +2273,8 @@ bool TrayApp::start_server() { is_service_active(), // is_ephemeral = true if systemd (suppress startup message) server_config_.host, // Pass host to ServerManager server_config_.max_loaded_models, - server_config_.extra_models_dir // Pass extra models directory + server_config_.extra_models_dir, // Pass extra models directory + server_config_.global_timeout ); // Start log tail thread to show logs in console