Skip to content

fix(autoselect): demote proxies reset mid-stream#284

Merged
garmr-ulfr merged 2 commits into
mainfrom
fix/mid-stream-reset-attribution
Jul 2, 2026
Merged

fix(autoselect): demote proxies reset mid-stream#284
garmr-ulfr merged 2 commits into
mainfrom
fix/mid-stream-reset-attribution

Conversation

@garmr-ulfr

@garmr-ulfr garmr-ulfr commented Jul 2, 2026

Copy link
Copy Markdown
Collaborator

This pull request improves the robustness and clarity of failure detection and attribution in the data plane watchdog logic, and significantly enhances the test coverage for mid-stream errors and edge cases. The main changes include introducing explicit mid-stream transport failure attribution, updating the handling of benign terminal conditions, and refactoring tests for better reliability and coverage.

Data Plane Failure Detection and Attribution

  • Added a new isDataPlaneFailure function to distinguish between real transport failures (such as connection resets) and benign conditions (like EOF, context cancellation, or timeouts), ensuring only genuine failures demote the outbound connection.
  • Introduced the fireFailure method in dataPlaneWatchdog, which immediately attributes a failure on explicit mid-stream transport errors, bypassing the proven/lastWasWrite gates and ensuring accurate and timely demotion.

Improvements to Idle and Error Handling Logic

  • Updated noteIO to use the new failure detection logic, ensuring that empty I/O and benign errors do not trigger failure attribution, and that attribution is short-circuited after the connection is already marked as stalled.
  • Clarified the documentation and logic for fireStall to better explain its role in demoting connections that go idle mid-stream.

Test Suite Enhancements

  • Added comprehensive new test cases covering mid-stream resets, timeouts, EOF, error attribution after close, and ensuring that failures are attributed at most once per connection. This includes new helper types like failingConn and failingPacketConn for simulating error scenarios.
  • Refactored existing tests to use require.NoError and require.FailNow for more consistent and reliable assertions, replacing manual error checks and t.Fatal calls. [1] [2] [3] [4] [5] [6] [7] [8] [9]

These changes collectively make the data plane watchdog more accurate in detecting real failures, prevent spurious demotions, and ensure that the test suite reliably covers a wide range of edge cases.

Summary by CodeRabbit

  • Bug Fixes

    • Improved handling of data-plane transport errors so only real mid-stream failures trigger demotion, while benign endings like EOF, cancellation, and timeouts are ignored.
    • Prevented stall/failure callbacks from blocking by running them asynchronously and ensuring they fire only once.
  • Tests

    • Expanded and refined coverage for data-plane stall behavior, failure-attribution rules, and exhaustion signal delivery.

noteIO discarded every errored read/write, so a proxy that established
fine but was reset mid-stream hit no demotion path: the dial-error path
never re-runs on an established conn, and Close stops the idle timer
before fireStall can fire. Short URL-test probes kept it ranked healthy,
so traffic kept routing through a dead tunnel.

Classify errored data-plane I/O in noteIO and route real transport
failures (non-EOF, non-timeout, non-cancel) through the existing onStall
attribution via fireFailure, which skips the proven/lastWasWrite gates an
explicit reset doesn't need and dispatches onStall off the I/O path.
@coderabbitai

coderabbitai Bot commented Jul 2, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 91b050d0-7ff5-4b90-b6d5-0f8f45bf421f

📥 Commits

Reviewing files that changed from the base of the PR and between d8b433d and 1be32b0.

📒 Files selected for processing (1)
  • protocol/group/mutableautoselect_test.go
🚧 Files skipped from review as they are similar to previous changes (1)
  • protocol/group/mutableautoselect_test.go

📝 Walkthrough

Walkthrough

Adds transport-error classification and a new atomic fireFailure path to the data-plane watchdog, distinguishing benign termination from real failures. The tests expand failure-attribution coverage and replace several fatal-style assertions with require-based checks.

Changes

Data-plane watchdog failure attribution

Layer / File(s) Summary
Error classification and fireFailure implementation
protocol/group/mutableautoselect_dataplane.go
Adds isDataPlaneFailure to classify errors as benign or failures, rewires noteIO to call new fireFailure() for non-benign errors, adds atomic single-fire fireFailure() invoking onStall asynchronously, and updates the fireStall comment.
Stall test assertion updates
protocol/group/mutableautoselect_test.go
Updates stall tests to use require.NoError for read/write operations and adds explicit proven-state checks before waiting on stall callbacks; extends imports for io and syscall.
New failure attribution test suite
protocol/group/mutableautoselect_test.go
Adds failingConn/failingPacketConn helpers and error constructors, plus new tests validating mid-stream reset attribution, non-attribution for EOF/timeouts and post-Close errors, and single-fire CAS behavior.
Test assertion consistency updates
protocol/group/mutableautoselect_test.go
Converts remaining t.Fatalf/t.Fatal calls to require.NoError/require.FailNow in selection, exhaustion signal, interface update, and background loop tests.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Conn
  participant noteIO
  participant isDataPlaneFailure
  participant fireFailure
  participant onStall

  Conn->>noteIO: IO result (err)
  noteIO->>isDataPlaneFailure: classify(err)
  isDataPlaneFailure-->>noteIO: benign or failure
  alt non-benign failure
    noteIO->>fireFailure: fireFailure()
    fireFailure->>fireFailure: CAS stalled/fired
    fireFailure->>onStall: invoke asynchronously
  else benign (EOF, Canceled, timeout)
    noteIO-->>Conn: ignore
  end
Loading

Related Issues: None found in the provided context.

Related PRs: None found in the provided context.

Suggested labels: enhancement, tests

Suggested reviewers: None determined from provided context.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title matches the main change: autoselect now demotes proxies on mid-stream resets.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/mid-stream-reset-attribution

Comment @coderabbitai help to get the list of available commands.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR updates the MutableAutoSelect data-plane watchdog to more accurately attribute mid-stream transport failures (so only genuine failures demote an outbound) and expands the test suite to cover mid-stream error scenarios and related edge cases.

Changes:

  • Added isDataPlaneFailure and fireFailure to distinguish benign terminal conditions from real mid-stream transport failures and attribute failures immediately.
  • Refined noteIO and stall attribution behavior to short-circuit once stalled and avoid misclassification.
  • Expanded/refactored tests to cover mid-stream resets, benign EOF/timeouts, post-close behavior, and single-attribution semantics.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 4 comments.

File Description
protocol/group/mutableautoselect_dataplane.go Adds explicit mid-stream failure classification and immediate failure attribution path in the watchdog.
protocol/group/mutableautoselect_test.go Adds new mid-stream failure/benign-condition tests and refactors assertions for consistency.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread protocol/group/mutableautoselect_dataplane.go
Comment thread protocol/group/mutableautoselect_test.go Outdated
Comment thread protocol/group/mutableautoselect_test.go Outdated
Comment thread protocol/group/mutableautoselect_test.go Outdated
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
protocol/group/mutableautoselect_test.go (1)

965-1157: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Solid new failure-attribution coverage; one gap vs. stated classification.

The failingConn/failingPacketConn helpers and reset/EOF/timeout/post-close/single-fire tests correctly exercise the new fireFailure path and its CAS semantics, matching the noteIO/fireFailure implementation from mutableautoselect_dataplane.go. However, both the PR summary and AI summary describe context.Canceled as a benign terminal condition alongside EOF and timeouts, yet no test here verifies that a canceled-context error does not attribute a failure (only io.EOF at line 1088 and a synthetic timeout at line 1106 are covered).

Consider adding a TestDataPlaneStream_ContextCanceledDoesNotAttribute mirroring the EOF/timeout tests, using context.Canceled (or context.DeadlineExceeded, if that's separately classified) as the injected error.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@protocol/group/mutableautoselect_test.go` around lines 965 - 1157, Add a new
failure-attribution test in the same test block as
TestDataPlaneStream_EOFDoesNotAttribute and
TestDataPlaneStream_TimeoutDoesNotAttribute to cover the benign
context-cancellation case. Use the existing failingConn helper and
newDataPlaneStream, inject context.Canceled (or context.DeadlineExceeded if that
is meant to be classified separately), then assert the read returns the error
but the fireFailure callback is not invoked. Reference the same pattern used by
TestDataPlaneStream_EOFDoesNotAttribute,
TestDataPlaneStream_TimeoutDoesNotAttribute, and the noteIO/fireFailure behavior
being validated here.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@protocol/group/mutableautoselect_test.go`:
- Around line 965-1157: Add a new failure-attribution test in the same test
block as TestDataPlaneStream_EOFDoesNotAttribute and
TestDataPlaneStream_TimeoutDoesNotAttribute to cover the benign
context-cancellation case. Use the existing failingConn helper and
newDataPlaneStream, inject context.Canceled (or context.DeadlineExceeded if that
is meant to be classified separately), then assert the read returns the error
but the fireFailure callback is not invoked. Reference the same pattern used by
TestDataPlaneStream_EOFDoesNotAttribute,
TestDataPlaneStream_TimeoutDoesNotAttribute, and the noteIO/fireFailure behavior
being validated here.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 0e8b1694-9a90-4051-8c52-97a553d3fc33

📥 Commits

Reviewing files that changed from the base of the PR and between 8384c76 and d8b433d.

📒 Files selected for processing (2)
  • protocol/group/mutableautoselect_dataplane.go
  • protocol/group/mutableautoselect_test.go

@garmr-ulfr garmr-ulfr marked this pull request as ready for review July 2, 2026 02:05
@garmr-ulfr garmr-ulfr merged commit c8b47d8 into main Jul 2, 2026
4 checks passed
@garmr-ulfr garmr-ulfr deleted the fix/mid-stream-reset-attribution branch July 2, 2026 19:29
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.

3 participants