Skip to content

fix(sdk): keep a shut down client shut down - #4374

Merged
hubcio merged 2 commits into
apache:masterfrom
TomPlanche:fix/sdk-shutdown-terminal
Oct 2, 2026
Merged

hubcio merged 2 commits into
apache:masterfrom
TomPlanche:fix/sdk-shutdown-terminal

Conversation

@TomPlanche

Copy link
Copy Markdown
Contributor

Which issue does this PR address?

Relates to #4287

Rationale

shutdown() must be final, as agreed on #4287: a client that is shut down must not connect again, whatever the caller does next. Problems 1 and 4 of #4287 break this rule. This PR fixes these two problems. Problems 2 and 3, about disconnect(), come in a separate PR.

What changed?

A client that was shut down could come back. WebSocketClient dialed again on connect(), because its connect_inner had no Shutdown arm. On every transport, a disconnect() after shutdown() wrote Disconnected over Shutdown, so connect() worked again.

Now one guard in set_state keeps Shutdown final on TCP, QUIC and WebSocket, so no later write can revive the client. This guard also covers the Disconnected writes that other paths add, for example a timeout. WebSocketClient::connect_inner also returns ClientShutdown before any dial, as TCP and QUIC already do. The guard alone does not stop that dial.

The Client trait now documents this contract on shutdown(). The two lifecycle tests from #4344 for these cases lose their #[ignore]. On the Python side, the strict xfail of the WebSocket case and the known-issue note of shutdown() go away, because the bug is fixed.

Local Execution

I used Zed in devcontainer mode. The build and the tests ran in the devcontainer, and prek ran on macOS.

  • Passed: cargo fmt --all and cargo clippy -p iggy_common -p iggy -p integration --all-features --all-targets -- -D warnings.

  • Passed: cargo test -p iggy --lib, with 232 tests.

  • Passed: the lifecycle tests. The 4 cases of problems 1 and 4 pass, and the 6 cases of problems 2 and 3 stay ignored:

    $ cargo test -p integration -- sdk::client_lifecycle
    test result: ok. 4 passed; 0 failed; 6 ignored; 0 measured; 991 filtered out
    
  • Passed: the sdk:: integration suite (63 passed, 6 ignored), in two runs, and the cluster:: suite (80 passed), because the guard changes state transitions that reconnects and failovers use.

  • Passed: the Python lifecycle tests against a local server, with no xfail left:

    $ uv run --no-sync pytest tests/test_connectivity.py -k Lifecycle
    16 passed, 35 deselected
    
  • Passed: cargo run --bin stub_gen. The stub matches the edited docstring.

  • Passed: pre-commit hooks with SKIP=web-lint prek run --all-files. I skipped web-lint because this PR does not change web/.

AI Usage

  1. No

@github-actions

github-actions Bot commented Oct 1, 2026

Copy link
Copy Markdown

Thanks for the PR. It is labeled S-waiting-on-review and queued for review.

Slash commands (own line, regular comment) move it around the queue:

  • /ready - back to S-waiting-on-review after addressing feedback
  • /author - flip to S-waiting-on-author while you finish changes
  • /request-review @user-or-team - request a reviewer
  • /pin - exempt the PR from the stale bot, /unpin to undo

See CONTRIBUTING.md for details.

@github-actions github-actions Bot added the S-waiting-on-review PR is waiting on a reviewer label Oct 1, 2026
@codecov

codecov Bot commented Oct 1, 2026 •

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 80.00000% with 1 line in your changes missing coverage. Please review.
✅ Project coverage is 87.95%. Comparing base (e51780a) to head (ef03054).

Files with missing lines Patch % Lines
core/sdk/src/websocket/websocket_client.rs 80.00% 1 Missing ⚠️
Additional details and impacted files
@@             Coverage Diff              @@
##             master    #4374      +/-   ##
============================================
+ Coverage     87.84%   87.95%   +0.11%     
  Complexity     1579     1579              
============================================
  Files          1290     1290              
  Lines        230143   230145       +2     
  Branches     193480   193481       +1     
============================================
+ Hits         202169   202425     +256     
+ Misses        23259    22970     -289     
- Partials       4715     4750      +35     
Components Coverage Δ
Rust Core 89.06% <80.00%> (+0.02%) ⬆️
Java SDK 68.74% <ø> (ø)
C# SDK 77.61% <ø> (-0.08%) ⬇️
Python SDK 91.24% <ø> (ø)
PHP SDK 85.67% <ø> (ø)
Node SDK 96.59% <ø> (+1.70%) ⬆️
Go SDK 70.26% <ø> (ø)
Files with missing lines Coverage Δ
core/sdk/src/quic/quic_client.rs 79.14% <ø> (+2.13%) ⬆️
core/sdk/src/tcp/tcp_client.rs 90.11% <ø> (ø)
foreign/python/src/client.rs 99.77% <ø> (ø)
core/sdk/src/websocket/websocket_client.rs 80.31% <80.00%> (+2.56%) ⬆️

... and 44 files with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@hubcio

hubcio commented Oct 1, 2026

Copy link
Copy Markdown
Contributor

/skill team-review-slim

@github-actions github-actions 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.

Summary: The change makes shutdown final on TCP, QUIC and WebSocket by refusing every later state write, un-ignores the two integration tests that pin the contract, and drops the stale Python notes. One gap remains: a connect that is already dialing when shutdown() runs never re-reads the state, so it can still install a live stream and return Ok, which the new trait doc rules out.

Counts: critical 0, warning 1, nit 1, simplification 1


This review was generated by Claude Code 2.1.284 on deepseek-flash[1m]. Review the output before you act on it.

Comment thread core/sdk/src/websocket/websocket_client.rs
Comment thread core/sdk/src/quic/quic_client.rs
Comment thread core/sdk/src/tcp/tcp_client.rs
@github-actions github-actions Bot added S-waiting-on-author PR is waiting on author response and removed S-waiting-on-review PR is waiting on a reviewer labels Oct 1, 2026
@hubcio
hubcio merged commit 7c10d8a into apache:master Oct 2, 2026
104 checks passed
@github-actions github-actions Bot removed the S-waiting-on-author PR is waiting on author response label Oct 2, 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.

4 participants