Skip to content

fix(smart): stop rapid proxy rotation on successful dials - #15

Open
qoli wants to merge 3 commits into
vernesong:Alphafrom
qoli:codex/preserve-smart-connections
Open

fix(smart): stop rapid proxy rotation on successful dials#15
qoli wants to merge 3 commits into
vernesong:Alphafrom
qoli:codex/preserve-smart-connections

Conversation

@qoli

@qoli qoli commented Sep 1, 2026

Copy link
Copy Markdown

Severity: this breaks the Smart selection model

This is not merely connection cleanup. It turns Smart from a quality-learning, continuity-preserving selector into a latest-success-wins connection rotator.

Smart stores an unwrap result so later connections to the same SmartTarget can reuse the learned selection. But every successful TCP or UDP dial also calls closeSameConnection(..., false). Any active connection for that target using a different proxy is closed even though no degradation was observed.

Normal web pages create many concurrent connections. If those dials complete through different candidates, every later completion invalidates earlier successful traffic:

  1. Smart establishes healthy traffic through proxy A.
  2. A concurrent dial completes through proxy B.
  3. Success on B closes the healthy connection on A.
  4. The client retries, potentially selecting another proxy and closing more traffic.

This self-induced churn destroys Smart connection continuity and makes it behave like rapid proxy rotation rather than stable learned selection. It applies to every concurrent Smart target, not only Pinterest. Symptoms include TLS unexpected EOF, interrupted transfers, reconnect storms, and browsers shifting toward QUIC after TCP is repeatedly destroyed.

Reproduction

On an isolated iStoreOS 24.10.8 x86_64 router, 15 concurrent Pinterest HTTPS requests produced:

  • Smart: 1 success, 13 TLS unexpected EOF, 1 timeout
  • Fixed stable proxy: 15/15 success
  • Fixed degraded proxy: 10/15 success, 5 ordinary timeouts, no TLS EOF

These controls separate node quality from Smart-generated churn.

Change

Remove success-path sibling cleanup for TCP and UDP. Smart still stores unwrap results and records metrics. Forced cleanup remains unchanged: closeSameConnection(..., true) runs only after measured degradation or host-failure evidence.

Verification

With the same Smart configuration and pool, four bursts totaling 60 Pinterest requests produced:

  • 60/60 completed TLS and received HTTP 200
  • 59/60 completed within 15 seconds
  • 1/60 timed out after receiving about 914 KB
  • 0 TLS unexpected EOF

The final burst had 15 matching controller TCP logs. The same code was then deployed on ARM64 OpenWrt: Smart remained loaded, takeover stayed effective, and a five-request live check completed 5/5 with HTTP 200 and no EOF.

Tests

  • go test ./adapter/outboundgroup ./component/smart ./tunnel/statistic
  • go test ./...
  • git diff --check

@qoli
qoli force-pushed the codex/preserve-smart-connections branch from 5b54ff3 to 5185f6e Compare September 1, 2026 07:51
Smart should preserve connection continuity while it learns proxy quality and only evict traffic after degradation is observed. The success-path closeSameConnection call violates that model by making every newly completed dial authoritative for the entire SmartTarget.

When concurrent dials for one target complete through different proxies, each later success closes connections established by earlier successes. Selection therefore becomes latest-success-wins churn: Smart rapidly rotates active traffic instead of maintaining stable learned routing. Long-lived TCP and UDP sessions are destroyed without any quality failure, surfacing as TLS unexpected EOF and causing browsers to retry or move traffic to QUIC.

Remove the non-forced cleanup from successful TCP and UDP dials. Keep forced cleanup in the measured degradation path so Smart can still evict connections backed by actual failure evidence.
@qoli
qoli force-pushed the codex/preserve-smart-connections branch from 5185f6e to efe02b9 Compare September 1, 2026 07:51
@qoli qoli changed the title fix(smart): preserve established connections after successful selection fix(smart): stop rapid proxy rotation on successful dials Sep 1, 2026
vernesong added a commit that referenced this pull request Sep 4, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant