From 41df30df706310de3e55c53b21d8abe04607111a Mon Sep 17 00:00:00 2001 From: yyoyoian-pixel <279225925+yyoyoian-pixel@users.noreply.github.com> Date: Mon, 11 May 2026 02:07:18 +0200 Subject: [PATCH] =?UTF-8?q?fix:=20skip=20H2=20for=20tunnel=5Frequest=20(si?= =?UTF-8?q?ngle=20ops)=20=E2=80=94=20completes=20#1040?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit PR #1040 skipped H2 for `tunnel_batch_request_to` but missed `tunnel_request` (used for plain `connect` ops). This caused 16-17s long-poll stalls to persist on full-tunnel sessions that go through the single-op path. Same fix: remove the H2 try/fallback/NonRetryable block, go straight to H1 pool acquire(). H2 remains active for relay mode. Co-Authored-By: Claude Opus 4.6 (1M context) --- src/domain_fronter.rs | 47 +++---------------------------------------- 1 file changed, 3 insertions(+), 44 deletions(-) diff --git a/src/domain_fronter.rs b/src/domain_fronter.rs index dc59117..42a34a7 100644 --- a/src/domain_fronter.rs +++ b/src/domain_fronter.rs @@ -2653,50 +2653,9 @@ impl DomainFronter { let script_id = self.next_script_id(); let path = format!("/macros/s/{}/exec", script_id); - // h2 fast path. Tunnel ops are stateful — a `connect` may - // have opened an upstream socket; a `data` op may have - // forwarded bytes. Replaying on h1 after the op reached - // Apps Script can corrupt the tunnel session. Only fall back - // when h2 definitely never sent. - // Use the user-configured batch_timeout so Full-mode tuning - // (`request_timeout_secs`) is honored — a fixed cap would let - // legitimately slow batches incorrectly trip strike counters - // on healthy deployments at tunnel_client::fire_batch. - match self - .h2_relay_request(&path, payload.clone(), self.batch_timeout) - .await - { - Ok((status, _hdrs, _resp_body)) if is_h2_fronting_refusal_status(status) => { - // Edge rejected the fronted h2 request. Safe to fall - // back to h1 — the tunnel op never executed because - // Apps Script never received the request. - self.sticky_disable_h2_for_fronting_refusal( - status, - &format!("tunnel op {}", op), - ) - .await; - // fall through to h1 - } - Ok((status, _hdrs, resp_body)) => { - return self.finalize_tunnel_response(&script_id, status, resp_body); - } - Err((e, RequestSent::No)) => { - tracing::debug!( - "h2 tunnel request pre-send failure: {} — falling back to h1", - e - ); - } - Err((e, RequestSent::Maybe)) => { - tracing::warn!( - "h2 tunnel request post-send failure (op={}): {} — \ - not replaying on h1 to avoid corrupting the tunnel session", - op, - e - ); - return Err(e); - } - } - + // Skip h2 for tunnel ops — same rationale as tunnel_batch_request_to + // (PR #1040): tunnel ops are already single HTTP requests, h2 + // multiplexing adds no benefit and causes 16-17s long-poll stalls. let mut entry = self.acquire().await?; let req_head = format!(