Skip to content

fix: reconnect agent after ELS restarts - #14

Merged
deleteLater merged 3 commits into
mainfrom
fix/does-not-reconnect-when-ELS-restarts
Aug 26, 2026
Merged

deleteLater merged 3 commits into
mainfrom
fix/does-not-reconnect-when-ELS-restarts

Conversation

@deleteLater

@deleteLater deleteLater commented Aug 26, 2026 •

Copy link
Copy Markdown
Contributor

fixed featbit/featbit#966

Summary by CodeRabbit

  • Bug Fixes

    • Improved WebSocket reconnection behavior after connection closures.
    • Prevented reconnection when the client is stopping or the server rejects the request.
    • Continued reconnection after eligible normal closures.
  • Tests

    • Added unit and integration coverage for WebSocket reconnection scenarios.
    • Added test infrastructure for simulating WebSocket connections and closures.

Greptile Summary

The PR updates WebSocket reconnection behavior so eligible closures reconnect repeatedly, shutdown cancels connection attempts, and server rejection prevents retries.

  • Links connection timeout cancellation with agent shutdown.
  • Adds explicit close-status and stop-state reconnect decisions.
  • Adds unit and integration coverage for reconnect, rejection, and shutdown scenarios.
  • Replaces the legacy solution file with a solution containing the API and new test projects.

Confidence Score: 4/5

The PR is not yet safe to merge because reconnect work can still publish a connection and trigger synchronization after shutdown begins.

CloseAsync cancels the stop token but neither tracks nor excludes detached reconnect work; ConnectAsync can pass its final cancellation check immediately before shutdown and then invoke OnConnected afterward.

Files Needing Attention: src/Api/Transport/FbWebSocket.cs

Important Files Changed

Filename Overview
src/Api/Transport/FbWebSocket.cs Reconnection now responds to shutdown and retries normal closures, but detached reconnect work remains unsynchronized with connection publication during CloseAsync.
tests/Api.IntegrationTests/Transport/WebSocketReconnectTests.cs Adds end-to-end coverage for repeated normal-closure reconnects, server rejection, and stopping from OnReconnecting, but does not exercise shutdown after the reconnect stop check.
tests/Api.UnitTests/Transport/ReconnectTests.cs Covers the extracted reconnect predicate for close statuses and explicit stop requests.
tests/Api.IntegrationTests/Transport/WebSocketStubServer.cs Provides a local WebSocket server capable of tracking connections and issuing controlled close frames.

Sequence Diagram

sequenceDiagram
    participant Peer
    participant Socket as FbWebSocket
    participant Reconnect as ReconnectAsync
    participant Stop as CloseAsync
    participant Consumer as OnConnected consumer
    Peer->>Socket: Close frame
    Socket->>Reconnect: Start detached reconnect
    Reconnect->>Socket: ConnectAsync
    Socket->>Socket: Connect succeeds
    Socket->>Socket: Check stop token
    Stop->>Socket: Cancel stop token
    Socket->>Consumer: Invoke OnConnected
    Socket->>Socket: Start pipe with cancelled token
Loading

Reviews (2): Last reviewed commit: "pr feedback" | Re-trigger Greptile

@coderabbitai

coderabbitai Bot commented Aug 26, 2026 •

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

Next included review available in 10 minutes.

View limit details

Limit details: You’ve used the included review currently available.

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

Learn how review limits work.

Review configuration:

⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 10b724ee-f9c2-46d1-98c7-530e68556527

📥 Commits

Reviewing files that changed from the base of the PR and between b810a25 and 500c9cd.

📒 Files selected for processing (4)
  • src/Api/Transport/FbWebSocket.cs
  • tests/Api.IntegrationTests/Transport/WebSocketReconnectTests.cs
  • tests/Api.IntegrationTests/Transport/WebSocketStubServer.cs
  • tests/Api.UnitTests/Transport/ReconnectTests.cs

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: dce9559d-9eb2-4c20-af6e-eef14c3d6bf3

📥 Commits

Reviewing files that changed from the base of the PR and between d5cd1af and b810a25.

📒 Files selected for processing (9)
  • FeatBit.Agent.sln
  • FeatBit.Agent.slnx
  • src/Api/Properties/AssemblyInfo.cs
  • src/Api/Transport/FbWebSocket.cs
  • tests/Api.IntegrationTests/Api.IntegrationTests.csproj
  • tests/Api.IntegrationTests/Transport/WebSocketReconnectTests.cs
  • tests/Api.IntegrationTests/Transport/WebSocketStubServer.cs
  • tests/Api.UnitTests/Api.UnitTests.csproj
  • tests/Api.UnitTests/Transport/ReconnectTests.cs
💤 Files with no reviewable changes (1)
  • FeatBit.Agent.sln

Included review availability: Your plan provides up to 1 included review per hour; 0 remain after this review.


📝 Walkthrough

Walkthrough

The pull request replaces the Visual Studio solution with an .slnx file, adds unit and integration test projects, updates WebSocket reconnection eligibility, and adds tests with a Kestrel WebSocket stub server.

Changes

WebSocket reconnection behavior

Layer / File(s) Summary
Solution and test foundation
FeatBit.Agent.sln, FeatBit.Agent.slnx, src/Api/Properties/AssemblyInfo.cs, tests/Api.UnitTests/Api.UnitTests.csproj, tests/Api.IntegrationTests/Api.IntegrationTests.csproj
The solution now references the API, unit test, and integration test projects. The API grants internal access to both test assemblies.
Reconnect decision logic
src/Api/Transport/FbWebSocket.cs, tests/Api.UnitTests/Transport/ReconnectTests.cs
ShouldReconnect stops reconnecting after manual shutdown or close status 4003. Unit tests cover supported statuses, stopped connections, and invalid requests.
Integration reconnection flow
tests/Api.IntegrationTests/Transport/WebSocketStubServer.cs, tests/Api.IntegrationTests/Transport/WebSocketReconnectTests.cs
The test server hosts a /streaming WebSocket endpoint. Integration tests verify repeated reconnection after normal closure and a single connection after status 4003.
Estimated code review effort: 3 (Moderate) ~20 minutes

Merge Risk: ⚪ Minimal · up to b810a

The PR adds reconnect behavior and related tests without any identified merge-blocking risk at the current head; it is merge-ready after normal checks and review.

Sequence Diagram(s)

sequenceDiagram
  participant FbWebSocket
  participant WebSocketStubServer
  participant OnClosed
  loop Normal closure
    FbWebSocket->>WebSocketStubServer: Connect to /streaming
    WebSocketStubServer-->>FbWebSocket: Close connection
    FbWebSocket->>FbWebSocket: ShouldReconnect
  end
  FbWebSocket->>WebSocketStubServer: Connect to /streaming
  WebSocketStubServer-->>FbWebSocket: Close with status 4003
  FbWebSocket->>OnClosed: Report close status 4003
  FbWebSocket->>FbWebSocket: Stop reconnecting
Loading
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 17 functions across 5 files. (3 skipped: 3… Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly describes the main change: fixing agent reconnection after ELS restarts. The WebSocket reconnection logic and tests directly support this objective.
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.
Full details: Docstring Coverage

Explanation

Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 17 functions across 5 files. (3 skipped: 3 unsupported.)

✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/does-not-reconnect-when-ELS-restarts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

@deleteLater

deleteLater commented Aug 26, 2026 •

Copy link
Copy Markdown
Contributor Author

@greptileai review this

@deleteLater
deleteLater requested a lite review from Copilot August 26, 2026 12:23
@deleteLater deleteLater self-assigned this Aug 26, 2026
@deleteLater deleteLater added the bug Something isn't working label Aug 26, 2026
@deleteLater deleteLater moved this to In Progress in FeatBit Aug 26, 2026
Comment thread src/Api/Transport/FbWebSocket.cs

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 adjusts the FbWebSocket reconnection decision logic so the agent will reconnect after eligible connection closures (including normal closure), while avoiding reconnect when the client is stopping or the server explicitly rejects the request. It also introduces new unit/integration tests and supporting test infrastructure to validate the reconnection behavior.

Changes:

  • Updated FbWebSocket.ShouldReconnect to reconnect on normal closures, but not when stopping or when close code 4003 is received.
  • Added unit + integration tests covering reconnect/no-reconnect scenarios, including a WebSocket stub server for integration testing.
  • Replaced the legacy .sln with an XML-based .slnx including both new test projects.

Reviewed changes

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

Show a summary per file
File Description
tests/Api.UnitTests/Transport/ReconnectTests.cs Unit coverage for FbWebSocket.ShouldReconnect logic (stop requested, normal closure, invalid request code).
tests/Api.UnitTests/Api.UnitTests.csproj Adds a unit test project targeting net10.0 and referencing the API project.
tests/Api.IntegrationTests/Transport/WebSocketStubServer.cs Adds an in-process WebSocket stub server used by integration tests.
tests/Api.IntegrationTests/Transport/WebSocketReconnectTests.cs Integration coverage validating reconnect on normal closure and no reconnect on invalid-request close.
tests/Api.IntegrationTests/Api.IntegrationTests.csproj Adds an integration test project (ASP.NET Core framework reference) targeting net10.0.
src/Api/Transport/FbWebSocket.cs Implements updated reconnect decision logic and exposes it for testability.
src/Api/Properties/AssemblyInfo.cs Adds InternalsVisibleTo so tests can call internal APIs.
FeatBit.Agent.slnx New solution format including src + test projects.
FeatBit.Agent.sln Removed legacy Visual Studio solution file.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread src/Api/Transport/FbWebSocket.cs
Comment thread tests/Api.IntegrationTests/Transport/WebSocketStubServer.cs

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

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

Suppressed comments (1)

tests/Api.IntegrationTests/Transport/WebSocketReconnectTests.cs:93

  • The fixed Task.Delay(250ms) makes this assertion timing-dependent and can cause flakes (either reconnect happens after the delay, or the delay is longer than necessary). Poll ConnectionCount for a short bounded window to assert it never exceeds the initial value after stopping during reconnect.
            await reconnecting.Task.WaitAsync(TimeSpan.FromSeconds(5));
            await Task.Delay(TimeSpan.FromMilliseconds(250));

            Assert.Equal(1, server.ConnectionCount);
        }

Comment thread src/Api/Transport/FbWebSocket.cs
Comment thread tests/Api.IntegrationTests/Transport/WebSocketReconnectTests.cs
@deleteLater

Copy link
Copy Markdown
Contributor Author

The PR is not yet safe to merge because reconnect work can still publish a connection and trigger synchronization after shutdown begins.

CloseAsync cancels the stop token but neither tracks nor excludes detached reconnect work; ConnectAsync can pass its final cancellation check immediately before shutdown and then invoke OnConnected afterward.

Theoretically possible, but FbWebSocket.CloseAsync is currently only called during service shutdown. Not worth fixing right now.

@deleteLater

Copy link
Copy Markdown
Contributor Author

Scripts to validate locally

Reproducible On Main Branch

node scripts\reconnect-test.mjs `
  --branch main `
  --test-duration 300 `
  --downtime 2 `
  --recovery-timeout 90 `
  --relay-proxy-name "local rp" `
  --agent-id "local-test-new-version"

Unreproducible On Fix Branch

node scripts\reconnect-test.mjs `
  --branch fix/does-not-reconnect-when-ELS-restarts `
  --test-duration 300 `
  --downtime 2 `
  --recovery-timeout 90 `
  --relay-proxy-name "local rp" `
  --agent-id "local-test-new-version"

scripts.zip

@deleteLater deleteLater moved this from In Progress to PR Ready in FeatBit Aug 26, 2026
@deleteLater
deleteLater merged commit 8a034fc into main Aug 26, 2026
3 checks passed
@github-project-automation github-project-automation Bot moved this from PR Ready to Done in FeatBit Aug 26, 2026
@deleteLater
deleteLater deleted the fix/does-not-reconnect-when-ELS-restarts branch August 26, 2026 15:39
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

[Bug]: FeatBit Agent remains in Closed WebSocket state after ELS restart

2 participants