From 916d5a238b0247c09a8ce0d1b4d7024fd1d7911b Mon Sep 17 00:00:00 2001 From: duanbing Date: Tue, 2 Jun 2026 06:37:59 +0800 Subject: [PATCH] feat(novita): raise async media poll budget to 1h for a single generation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Split the overloaded REQUEST_TIMEOUT const: it stays the per-HTTP-request timeout (create-task submit, single poll fetch); a new ASYNC_TASK_TIMEOUT (3600s) governs the total poll-loop deadline for one async media generation. Heavy models (e.g. sora_2_pro_i2v) routinely render past the old 300s budget, producing spurious "did not complete within 300s" timeouts. RouterBase no longer retries these (MAX_ATTEMPTS=1), so this is the single, final budget — one upstream task per request, no throwaway re-submissions. Co-Authored-By: Claude Opus 4.8 (1M context) --- tensorzero-core/src/providers/novita.rs | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/tensorzero-core/src/providers/novita.rs b/tensorzero-core/src/providers/novita.rs index 1214529f08..5736c6f796 100644 --- a/tensorzero-core/src/providers/novita.rs +++ b/tensorzero-core/src/providers/novita.rs @@ -15,7 +15,17 @@ use crate::http::TensorzeroHttpClient; const PROVIDER_NAME: &str = "Novita"; const PROVIDER_TYPE: &str = "novita"; +/// Per-HTTP-request timeout for individual calls to Novita (create-task +/// submit, single poll fetch). Bounds one network round-trip, not the whole +/// generation. const REQUEST_TIMEOUT: Duration = Duration::from_secs(300); +/// Total wall-clock budget for a single async media generation to reach a +/// terminal state. Heavy models (e.g. `sora_2_pro_i2v`) routinely render well +/// past the old 300s; allow up to 1h before declaring a timeout. The +/// RouterBase worker does NOT retry after this fires (`MAX_ATTEMPTS = 1`), so +/// this is the one and only budget for a generation — no new Novita task is +/// ever spawned for the same request. +const ASYNC_TASK_TIMEOUT: Duration = Duration::from_secs(3600); lazy_static! { static ref NOVITA_API_BASE: String = @@ -799,7 +809,7 @@ async fn poll_async_result( "{}/v3/async/task-result?task_id={task_id}", *NOVITA_API_BASE ); - let deadline = Instant::now() + REQUEST_TIMEOUT; + let deadline = Instant::now() + ASYNC_TASK_TIMEOUT; let poll_interval = Duration::from_secs(4); loop { @@ -807,7 +817,7 @@ async fn poll_async_result( return Err(Error::new(ErrorDetails::InferenceServer { message: format!( "Novita async task {task_id} did not complete within {}s", - REQUEST_TIMEOUT.as_secs() + ASYNC_TASK_TIMEOUT.as_secs() ), provider_type: PROVIDER_TYPE.to_string(), raw_request: None,