Skip to content

Comments

HTTP transport: respect retry_on_reload and add stale connection detection#798

Merged
dsarno merged 1 commit intobetafrom
codex/issue-795-http-retry
Feb 20, 2026
Merged

HTTP transport: respect retry_on_reload and add stale connection detection#798
dsarno merged 1 commit intobetafrom
codex/issue-795-http-retry

Conversation

@dsarno
Copy link
Collaborator

@dsarno dsarno commented Feb 20, 2026

Summary

Fixes #795 — the HTTP/WebSocket transport path (PluginHub) now respects retry_on_reload=False and performs pre-send liveness checks, matching the stdio path behavior from PR #792.

  • unity_transport.py: Extract retry_on_reload from kwargs and forward to PluginHub.send_command_for_instance() (previously silently dropped)
  • plugin_hub.py:
    • _resolve_session_id() accepts retry_on_reload; when False, skips the reconnect wait loop
    • send_command_for_instance() accepts retry_on_reload; when False + stale connection, returns failure immediately instead of retrying
    • New _ensure_live_connection() checks WebSocket state before sending (best-effort pre-send liveness, mirrors stdios MSG_PEEK check)
    • New _evict_connection() proactively cleans up stale sessions
    • Skips fast-fail readiness probe when retry_on_reload=False

Test plan

  • 3 new unit/integration tests (707/707 passing)
  • Smoke tested against live Unity instance via HTTP transport:
    • script_apply_edits (uses retry_on_reload=False) — survives domain reload
    • create_script (uses retry_on_reload=False) — survives domain reload
    • refresh_unity with compile — recovers from WebSocket disconnect
    • No compilation errors after mutations

Generated with Claude Code

Co-Authored-By: Codex [email protected]

Summary by Sourcery

Respect retry_on_reload for HTTP/WebSocket Unity transport and add stale connection detection and eviction to improve domain reload behavior and error signalling.

Bug Fixes:

  • Ensure HTTP transport forwards retry_on_reload to PluginHub so commands can opt out of reconnect waits during Unity domain reloads.
  • Avoid sending commands over stale WebSocket sessions by checking liveness before send and failing fast when retry_on_reload is disabled.

Enhancements:

  • Introduce explicit stale connection eviction in PluginHub, cleaning up WebSocket state, background ping tasks, and pending futures when a session is no longer valid.
  • Add a shared unavailable retry response helper to standardize error payloads when Unity sessions are missing or connections are stale.
  • Gate fast-fail readiness probes on retry_on_reload to avoid unnecessary waits when callers request no reload retries.

Tests:

  • Add integration tests covering no-wait behavior when retry_on_reload is disabled, fast-fail on stale HTTP sessions without retry, and HTTP transport propagation of retry_on_reload.

Summary by CodeRabbit

  • Bug Fixes

    • Improved connection stability with proactive liveness checks and automatic cleanup of stale connections.
    • Enhanced retry control during domain reloads to enable faster fallbacks when connections are unavailable.
    • Standardized error responses for unavailable sessions.
  • Tests

    • Added integration tests for retry behavior control and stale connection detection.
    • Added HTTP transport verification tests.

@sourcery-ai
Copy link
Contributor

sourcery-ai bot commented Feb 20, 2026

Reviewer's Guide

Extends the HTTP/WebSocket PluginHub transport to respect the retry_on_reload flag and adds pre-send WebSocket liveness checking with proper stale session eviction, while wiring the flag through unity_transport and covering behavior with new tests.

Sequence diagram for PluginHub send_command_for_instance with retry_on_reload and liveness checks

sequenceDiagram
    actor Client
    participant UnityTransport
    participant PluginHub
    participant Registry
    participant WebSocket

    Client->>UnityTransport: send_with_unity_instance(unity_instance, command_type, params, retry_on_reload)
    UnityTransport->>UnityTransport: normalize retry_on_reload from kwargs
    UnityTransport->>PluginHub: send_command_for_instance(unity_instance, command_type, params, user_id, retry_on_reload)

    activate PluginHub
    PluginHub->>PluginHub: _resolve_session_id(unity_instance, user_id, retry_on_reload)
    alt no session found
        PluginHub-->>UnityTransport: _unavailable_retry_response(no_unity_session)
        UnityTransport-->>Client: failure with hint retry
    else session resolved
        PluginHub->>PluginHub: _ensure_live_connection(session_id)
        alt connection live
            PluginHub->>WebSocket: send command over WebSocket
            WebSocket-->>PluginHub: command_result
        else connection stale
            PluginHub->>PluginHub: _evict_connection(session_id, stale_websocket_state)
            alt retry_on_reload is false
                PluginHub-->>UnityTransport: _unavailable_retry_response(stale_connection)
                UnityTransport-->>Client: failure with hint retry
            else retry_on_reload is true
                PluginHub->>PluginHub: _resolve_session_id(unity_instance, user_id, true)
                alt no session after retry
                    PluginHub-->>UnityTransport: _unavailable_retry_response(no_unity_session)
                    UnityTransport-->>Client: failure with hint retry
                else new session resolved
                    PluginHub->>PluginHub: _ensure_live_connection(new_session_id)
                    alt new connection still stale
                        PluginHub-->>UnityTransport: _unavailable_retry_response(stale_connection)
                        UnityTransport-->>Client: failure with hint retry
                    else new connection live
                        PluginHub->>WebSocket: send command over WebSocket
                        WebSocket-->>PluginHub: command_result
                    end
                end
            end
        end
        PluginHub-->>UnityTransport: success response
        UnityTransport-->>Client: normalized response
    end
    deactivate PluginHub
Loading

Class diagram for updated PluginHub HTTP transport retry and liveness handling

classDiagram
    class PluginHub {
        +_get_connection(session_id: str) WebSocket
        +_evict_connection(session_id: str, reason: str) None
        +_ensure_live_connection(session_id: str) bool
        +_unavailable_retry_response(reason: str) dict
        +_resolve_session_id(unity_instance: str, user_id: str, retry_on_reload: bool) str
        +send_command_for_instance(unity_instance: str, command_type: str, params: dict, user_id: str, retry_on_reload: bool) dict
    }

    class UnityTransport {
        +send_with_unity_instance(unity_instance: str, command_type: str, params: dict, user_id: str, retry_on_reload: bool) dict
    }

    class PluginRegistry {
        +unregister(session_id: str) None
    }

    class WebSocket {
        +client_state: WebSocketState
        +application_state: WebSocketState
        +close(code: int) None
    }

    class PingTask {
        +cancel() None
    }

    class PendingEntry {
        +session_id: str
        +future: Future
    }

    class MCPResponse {
        +success: bool
        +error: str
        +hint: str
        +data: dict
        +model_dump() dict
    }

    PluginHub --> PluginRegistry : uses
    PluginHub --> WebSocket : manages
    PluginHub --> PingTask : manages ping_tasks
    PluginHub --> PendingEntry : manages pending
    PluginHub --> MCPResponse : builds retry responses
    UnityTransport --> PluginHub : calls send_command_for_instance
Loading

File-Level Changes

Change Details Files
Add centralized stale WebSocket session eviction and pre-send liveness checking in PluginHub.
  • Introduce _evict_connection to remove a session from in-memory state, cancel ping tasks, fail pending futures with PluginDisconnectedError, and unregister from the registry
  • Add _ensure_live_connection to fetch the WebSocket, verify CONNECTED states, log and evict on stale or missing connections, and return a boolean liveness result
  • Refactor repeated unavailable-session responses into _unavailable_retry_response for consistent error payloads
Server/src/transport/plugin_hub.py
Make session resolution and command sending respect retry_on_reload, including fast-fail semantics for stale or missing sessions.
  • Extend _resolve_session_id to accept retry_on_reload and clamp max_wait_s to 0 when False to avoid reconnect wait loops
  • Update send_command_for_instance to accept retry_on_reload, pass it through to _resolve_session_id, and short-circuit to a retry response when retry_on_reload is False and the connection is stale
  • Add a secondary resolution and liveness check path when retry_on_reload is True to recover from stale connections, and gate fast-fail readiness probing on retry_on_reload
Server/src/transport/plugin_hub.py
Wire retry_on_reload through the HTTP transport path so PluginHub receives and interprets it correctly.
  • Extract retry_on_reload from kwargs in send_with_unity_instance, validate it as a bool, and default to True when invalid
  • Pass retry_on_reload through to PluginHub.send_command_for_instance in HTTP mode
Server/src/transport/unity_transport.py
Add tests to validate no-wait behavior, stale-session fast-fail, and HTTP forwarding of retry_on_reload.
  • Add test_plugin_hub_no_wait_when_retry_disabled to ensure _resolve_session_id does not loop when retry_on_reload is False
  • Add test_send_command_for_instance_fails_fast_on_stale_when_retry_disabled to verify stale connections fail fast without sending commands or retrying
  • Add test_http_forwards_retry_on_reload to confirm the HTTP transport passes retry_on_reload to PluginHub.send_command_for_instance
Server/tests/integration/test_domain_reload_resilience.py
Server/tests/integration/test_transport_smoke.py

Assessment against linked issues

Issue Objective Addressed Explanation
#795 Ensure the HTTP/WebSocket transport path respects the retry_on_reload flag (including passing it through from send_with_unity_instance to PluginHub.send_command_for_instance and skipping reconnect/wait behavior when retry_on_reload=False).
#795 Add stale connection detection / pre-send liveness checks to the HTTP/WebSocket transport path, analogous to stdio’s _ensure_live_connection behavior.
#795 Unify the transport retry and reload-handling contract between stdio and HTTP paths via a shared abstraction or common helper layer for retry_on_reload semantics and connection health checks. The PR improves the HTTP path by adding _ensure_live_connection, _evict_connection, and retry_on_reload handling inside PluginHub, but it does not introduce a shared abstraction or helper layer used by both stdio and HTTP transports; the retry logic remains implemented separately per transport.

Possibly linked issues


Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Feb 20, 2026

Caution

Review failed

The pull request is closed.

📝 Walkthrough

Walkthrough

This pull request introduces robust session lifecycle management and retry control to the PluginHub. New helper methods (_evict_connection, _ensure_live_connection, _unavailable_retry_response) enable per-session cleanup and proactive liveness checking. The _resolve_session_id and send_command_for_instance methods gain a retry_on_reload parameter controlling reconnect waiting behavior. The HTTP transport layer forwards this flag to PluginHub, and integration tests validate fast-fail and no-wait paths.

Changes

Cohort / File(s) Summary
Core Session Lifecycle Management
Server/src/transport/plugin_hub.py
Added _evict_connection, _ensure_live_connection, and _unavailable_retry_response helpers for session cleanup and liveness verification; extended _resolve_session_id and send_command_for_instance with retry_on_reload parameter to control reconnect waiting and stale-connection detection behavior.
Transport Layer
Server/src/transport/unity_transport.py
Updated HTTP transport path to extract retry_on_reload from kwargs and forward it to PluginHub.send_command_for_instance.
Integration Tests
Server/tests/integration/test_domain_reload_resilience.py, Server/tests/integration/test_transport_smoke.py
Added test_plugin_hub_no_wait_when_retry_disabled and test_send_command_for_instance_fails_fast_on_stale_when_retry_disabled to verify no-wait and fast-fail behavior; added test_http_forwards_retry_on_reload to validate HTTP transport forwards the retry flag.

Sequence Diagram(s)

sequenceDiagram
    participant Client
    participant PluginHub
    participant Session
    participant Unity

    rect rgba(100, 149, 237, 0.5)
    Note over Client,Unity: retry_on_reload=True (Default Path)
    Client->>PluginHub: send_command_for_instance(retry_on_reload=True)
    PluginHub->>PluginHub: _resolve_session_id(retry_on_reload=True)
    PluginHub->>PluginHub: Wait for reconnect if needed
    PluginHub->>PluginHub: _ensure_live_connection
    PluginHub->>Session: Check WebSocket state
    Session-->>PluginHub: Connection active
    PluginHub->>Session: Send command
    Session->>Unity: Execute
    Unity-->>Session: Response
    Session-->>PluginHub: Response data
    PluginHub-->>Client: Success response
    end

    rect rgba(255, 99, 71, 0.5)
    Note over Client,Unity: retry_on_reload=False (Fast-Fail Path)
    Client->>PluginHub: send_command_for_instance(retry_on_reload=False)
    PluginHub->>PluginHub: _resolve_session_id(retry_on_reload=False)
    PluginHub->>PluginHub: No wait, resolve immediately
    PluginHub->>PluginHub: _ensure_live_connection
    PluginHub->>Session: Check WebSocket state
    Session-->>PluginHub: Connection stale/missing
    PluginHub-->>Client: Unavailable retry response (fail fast)
    end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~40 minutes

Possibly related issues

Possibly related PRs

Poem

🐰 twitches whiskers with joy
Sessions evict with finesse,
Stale connections—no more mess,
Fast or patient, we now choose,
Resilience wins, never lose! ✨

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch codex/issue-795-http-retry

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 and usage tips.

Copy link
Contributor

@sourcery-ai sourcery-ai bot left a comment

Choose a reason for hiding this comment

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

Hey - I've found 2 issues, and left some high level feedback:

  • In unity_transport.send_with_unity_instance, consider using kwargs.pop('retry_on_reload', True) instead of kwargs.get(...) so the helper does not unintentionally forward the retry_on_reload flag to downstream send functions (e.g., the stdio path) that may not expect it.
  • In _evict_connection, you gather matching entries from cls._pending but never remove those entries from the mapping; if _pending is long-lived this may lead to accumulation of stale entries, so it may be worth pruning them when you collect the associated futures.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- In `unity_transport.send_with_unity_instance`, consider using `kwargs.pop('retry_on_reload', True)` instead of `kwargs.get(...)` so the helper does not unintentionally forward the `retry_on_reload` flag to downstream send functions (e.g., the stdio path) that may not expect it.
- In `_evict_connection`, you gather matching entries from `cls._pending` but never remove those entries from the mapping; if `_pending` is long-lived this may lead to accumulation of stale entries, so it may be worth pruning them when you collect the associated futures.

## Individual Comments

### Comment 1
<location> `Server/src/transport/plugin_hub.py:572-573` </location>
<code_context>
+        if ping_task is not None and not ping_task.done():
+            ping_task.cancel()
+
+        for future in pending_futures:
+            future.set_exception(
+                PluginDisconnectedError(
+                    f"Unity plugin session {session_id} disconnected while awaiting command_result"
</code_context>

<issue_to_address>
**issue (bug_risk):** Re-check `future.done()` before `set_exception` to avoid race-induced `InvalidStateError`.

Because `pending_futures` is captured under the lock but `set_exception` is called after releasing it, a future can complete in between. Calling `set_exception` on a completed future raises `InvalidStateError`. To avoid this, either re-check `if not future.done():` immediately before `set_exception`, or wrap `set_exception` in a try/except that ignores `InvalidStateError`.
</issue_to_address>

### Comment 2
<location> `Server/src/transport/plugin_hub.py:558-562` </location>
<code_context>
+            websocket = cls._connections.pop(session_id, None)
+            ping_task = cls._ping_tasks.pop(session_id, None)
+            cls._last_pong.pop(session_id, None)
+            for entry in cls._pending.values():
+                if entry.get("session_id") == session_id:
+                    future = entry.get("future")
+                    if future and not future.done():
+                        pending_futures.append(future)
+
</code_context>

<issue_to_address>
**suggestion (bug_risk):** Consider removing `_pending` entries for the evicted session to avoid lingering state.

The eviction logic fails associated futures but leaves their `_pending` entries intact. This can leave stale state for fully-evicted sessions and potentially cause subtle behavior or memory growth. Consider collecting matching keys while holding the lock and removing those `_pending` entries as part of eviction.

```suggestion
        pending_futures: list[asyncio.Future] = []
        async with lock:
            websocket = cls._connections.pop(session_id, None)
            ping_task = cls._ping_tasks.pop(session_id, None)
            cls._last_pong.pop(session_id, None)

            # Collect and remove any pending entries associated with this session.
            pending_keys_to_remove: list[object] = []
            for key, entry in list(cls._pending.items()):
                if entry.get("session_id") == session_id:
                    future = entry.get("future")
                    if future and not future.done():
                        pending_futures.append(future)
                    pending_keys_to_remove.append(key)

            for key in pending_keys_to_remove:
                cls._pending.pop(key, None)
```
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

… detection

Fixes #795 — the HTTP/WebSocket transport path (PluginHub) now respects
retry_on_reload=False and performs pre-send liveness checks, matching
the stdio path behavior from PR #792.

Co-Authored-By: Codex <[email protected]>
@dsarno dsarno force-pushed the codex/issue-795-http-retry branch from c446efa to fb59d56 Compare February 20, 2026 22:11
@dsarno
Copy link
Collaborator Author

dsarno commented Feb 20, 2026

@coderabbitai review

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Feb 20, 2026

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@dsarno dsarno merged commit 2249c82 into beta Feb 20, 2026
2 checks passed
@dsarno dsarno deleted the codex/issue-795-http-retry branch February 20, 2026 22:15
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (1)
Server/src/transport/plugin_hub.py (1)

800-813: InstanceSelectionRequiredError can escape the stale-connection retry path unhandled.

The try/except NoUnitySessionError block at line 810 leaves InstanceSelectionRequiredError unhandled. For the auto-select case (unity_instance=None, originally a single session), if a second session registers during the reconnect-wait window, _resolve_session_id will raise InstanceSelectionRequiredError mid-retry, producing an unexpected error format for what started as a stale-connection scenario.

♻️ Proposed fix
         try:
             session_id = await cls._resolve_session_id(
                 unity_instance,
                 user_id=user_id,
                 retry_on_reload=True,
             )
-        except NoUnitySessionError:
+        except (NoUnitySessionError, InstanceSelectionRequiredError):
             return cls._unavailable_retry_response("no_unity_session")
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@Server/src/transport/plugin_hub.py` around lines 800 - 813, The retry path
can leak InstanceSelectionRequiredError from cls._resolve_session_id and bypass
the stale-connection handling; update the exception handling around the second
attempt to resolve the session id so it also catches
InstanceSelectionRequiredError (in addition to NoUnitySessionError) and returns
the same cls._unavailable_retry_response("stale_connection")/retry behavior;
specifically modify the try/except that calls cls._resolve_session_id (in the
block that previously only excepted NoUnitySessionError) to except
(NoUnitySessionError, InstanceSelectionRequiredError) and handle them the same
way so _ensure_live_connection + retry_on_reload logic remains consistent.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@Server/src/transport/plugin_hub.py`:
- Around line 579-583: In _evict_connection where you close the stale websocket
(the websocket.close call), replace the silent except with a debug log that
mirrors the behavior in _ping_loop: catch Exception as e and call the same
logger used in _ping_loop to emit a debug-level message including the exception
(e) and context that the close failed for the stale websocket; ensure you
reference the websocket variable in the log so diagnostics can tie the error to
the connection being evicted.

---

Nitpick comments:
In `@Server/src/transport/plugin_hub.py`:
- Around line 800-813: The retry path can leak InstanceSelectionRequiredError
from cls._resolve_session_id and bypass the stale-connection handling; update
the exception handling around the second attempt to resolve the session id so it
also catches InstanceSelectionRequiredError (in addition to NoUnitySessionError)
and returns the same cls._unavailable_retry_response("stale_connection")/retry
behavior; specifically modify the try/except that calls cls._resolve_session_id
(in the block that previously only excepted NoUnitySessionError) to except
(NoUnitySessionError, InstanceSelectionRequiredError) and handle them the same
way so _ensure_live_connection + retry_on_reload logic remains consistent.

Comment on lines +579 to +583
if websocket is not None:
try:
await websocket.close(code=1001)
except Exception:
pass
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Add debug logging for the swallowed WebSocket close exception.

The except Exception: pass silently drops any close error, unlike the analogous block in _ping_loop (lines 509–511) which logs it. Given that _evict_connection is explicitly cleaning up a stale socket, even a debug-level log here would aid diagnostics.

🪵 Proposed fix
-        if websocket is not None:
-            try:
-                await websocket.close(code=1001)
-            except Exception:
-                pass
+        if websocket is not None:
+            try:
+                await websocket.close(code=1001)
+            except Exception as close_ex:
+                logger.debug("Error closing evicted WebSocket for session %s: %s", session_id, close_ex)
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if websocket is not None:
try:
await websocket.close(code=1001)
except Exception:
pass
if websocket is not None:
try:
await websocket.close(code=1001)
except Exception as close_ex:
logger.debug("Error closing evicted WebSocket for session %s: %s", session_id, close_ex)
🧰 Tools
🪛 Ruff (0.15.1)

[error] 582-583: try-except-pass detected, consider logging the exception

(S110)


[warning] 582-582: Do not catch blind exception: Exception

(BLE001)

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@Server/src/transport/plugin_hub.py` around lines 579 - 583, In
_evict_connection where you close the stale websocket (the websocket.close
call), replace the silent except with a debug log that mirrors the behavior in
_ping_loop: catch Exception as e and call the same logger used in _ping_loop to
emit a debug-level message including the exception (e) and context that the
close failed for the stale websocket; ensure you reference the websocket
variable in the log so diagnostics can tie the error to the connection being
evicted.

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.

HTTP transport ignores retry_on_reload and lacks stale connection detection

1 participant