Skip to content

test(distributed): warm up cluster per class and report cluster state on latch timeout - #224

Open
devin-ai-integration[bot] wants to merge 1 commit into
mainfrom
devin/1784988912-distributed-test-flake-diagnostics
Open

test(distributed): warm up cluster per class and report cluster state on latch timeout#224
devin-ai-integration[bot] wants to merge 1 commit into
mainfrom
devin/1784988912-distributed-test-flake-diagnostics

Conversation

@devin-ai-integration

@devin-ai-integration devin-ai-integration Bot commented Jul 25, 2026

Copy link
Copy Markdown

Description

The Distributed* suites flake under load (14 retried flakes in a recent full run, all in the container-heavy Hazelcast/Kafka/NATS classes; Redis never flaked). Two problems make that hard to act on:

  1. Broker bootstrap is charged to the first test. Each class starts its broker in @BeforeAll and immediately runs a test, so Kafka partition discovery / Hazelcast cluster formation / NATS dispatcher setup eats into that test's 30s OP_TIMEOUT_SECS latch.
  2. The failure message says nothing. "Clients failed to join room" doesn't distinguish "client never got join-ok" from "membership never replicated to the peer node", so every flake is unattributable.

Both are fixed in the shared base class only; no test semantics or timeouts change.

Type of Change

  • Test improvements

Changes Made

  • @BeforeEach warmUpCluster() in DistributedCommonTest performs one connect → join → awaitRoomSync round trip per class (guarded by an AtomicBoolean; all subclasses are PER_CLASS), with its own 120s budget so bootstrap cost sits outside the per-test latches.
  • awaitOrFail is now an instance method that appends a cluster snapshot to every timeout failure:
    Clients failed to join room [timeout=30s, latch remaining=1, node1={room-abc:2}, node2={room-abc:1}]
    
    latch remaining shows how far the operation got; the per-node room maps show whether replication lagged. Snapshot collection is exception-safe and only runs on the failure path.

Testing

  • All existing tests pass
  • Tests pass locally with mvn test
  • Integration tests pass (if applicable)

mvn -pl netty-socketio-core test -Dtest=DistributedKafkaMultiChannelMemoryTest,DistributedNATSSingleChannelMemoryTest → 24/24 green. Kafka class went 17.4s → 18.4s, i.e. the warm-up adds ~1s per class, not per test. mvn -pl netty-socketio-core verify -DskipTests (checkstyle + license) passes.

Additional Notes

This is deliberately diagnostic-first: it does not raise OP_TIMEOUT_SECS (already 30s, with awaitRoomSync at 2 min — a timeout there means something never arrived, not that it arrived late). If flakes persist after this, the failure output will name the culprit instead of us guessing. Independent of #220 — branched from main.

Link to Devin session: https://app.devin.ai/sessions/78bf7322d0ff4d139f1f0c157954bfad
Requested by: @sanjomo

Summary by CodeRabbit

  • Tests
    • Improved reliability of distributed integration tests by adding a cluster warm-up step before test execution.
    • Enhanced timeout diagnostics with cluster and room-state details, making test failures easier to investigate.

…state on latch timeout

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
@sanjomo sanjomo self-assigned this Jul 25, 2026
@devin-ai-integration

Copy link
Copy Markdown
Author

🤖 Devin AI Engineer

I'll be helping with this pull request! Here's what you should know:

✅ I will automatically:

  • Address comments on this PR. Add '(aside)' to your comment to have me ignore it.
  • Look at CI failures and help fix them

Note: I can only respond to comments from users who have write access to this repository.

⚙️ Control Options:

  • Disable automatic comment, CI, and merge conflict monitoring

@devin-ai-integration

Copy link
Copy Markdown
Author

Test run: full core suite (Devin)

mvn -B -pl netty-socketio-core -am verify with Docker/Testcontainers:

Tests run: 709, Failures: 0, Errors: 0, Skipped: 0, Flakes: 8
BUILD SUCCESS  (14:52 min)
Flake count: 14 → 8 vs. the pre-change baseline measured on the same machine
Class Before Now
HazelcastPubSubSingleChannelUnreliable 3 1
HazelcastPubSubMultiChannelUnReliable 0 1
HazelcastRingBufferSingleChannel 2 0
HazelcastRingBufferMultiChannel 0 1
InProcessHazelcast 2 2
KafkaMultiChannelMemory 3 (one needed 2 retries) 1
KafkaMultiChannel 2 1
KafkaSingleChannel 2 1
NATSSingleChannelMemory 1 0

All 8 remaining flakes passed on the first retry. Caveat: single sample per branch.

New diagnostics are doing their job
testPureBroadcastFromNodes:752->joinRoom:1139->awaitOrFail:1069 Not all clients joined the room within timeout
 [timeout=30s, latch remaining=1, node1={:3, sync-f02ebb51-...:3}, node2={:3, sync-f02ebb51-...:3}]

Both nodes already show all 3 clients in the room in-cluster while the client latch is short by 1 → replication completed; the gap is on the client ack side. That attribution was impossible before.

Warm-up runs once per class + cost

Temporary marker print in warmUpCluster(): exactly 1 invocation across DistributedKafkaMultiChannelMemoryTest's 12 tests. Isolated class time 17.54s vs 17.43s/17.53s pre-change — no measurable slowdown.

Not covered by the new snapshot: testConnectAndJoinDifferentRoomTest ack timeout (CompletableFuture path, not awaitOrFail) — still a bare TimeoutException.

@sanjomo

sanjomo commented Jul 25, 2026

Copy link
Copy Markdown
Member

@coderabbitai

@coderabbitai

coderabbitai Bot commented Jul 25, 2026

Copy link
Copy Markdown
Contributor

@sanjomo I’ll review the distributed test warm-up and timeout-diagnostic changes.

✅ Action performed

Review finished.

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.

@coderabbitai

coderabbitai Bot commented Jul 25, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

Changes

Distributed test stability

Layer / File(s) Summary
Cluster warm-up lifecycle
netty-socketio-core/src/test/java/com/socketio4j/socketio/integration/DistributedCommonTest.java
Adds a guarded @BeforeEach warm-up that connects two sockets, joins a shared room, waits for membership replication, and disconnects the sockets.
Timeout diagnostics
netty-socketio-core/src/test/java/com/socketio4j/socketio/integration/DistributedCommonTest.java
Updates timeout assertions to include latch state and per-node room client counts.

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

Sequence Diagram(s)

sequenceDiagram
  participant DistributedCommonTest
  participant SocketA
  participant SocketB
  participant ClusterNodes
  participant ReplicationLatch
  DistributedCommonTest->>SocketA: connect
  DistributedCommonTest->>SocketB: connect
  DistributedCommonTest->>ClusterNodes: join shared warm-up room
  ClusterNodes->>ReplicationLatch: signal room membership replication
  DistributedCommonTest->>ReplicationLatch: await warm-up completion
  DistributedCommonTest->>SocketA: disconnect
  DistributedCommonTest->>SocketB: disconnect
Loading

Suggested reviewers: sanjomo

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly summarizes the main test warm-up and timeout-diagnostics changes.
Description check ✅ Passed The description follows the template and covers the core sections, with only Related Issue and Checklist left incomplete.
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 devin/1784988912-distributed-test-flake-diagnostics

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.

@coderabbitai coderabbitai Bot 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.

Actionable comments posted: 1

🤖 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.

Inline comments:
In
`@netty-socketio-core/src/test/java/com/socketio4j/socketio/integration/DistributedCommonTest.java`:
- Around line 138-143: Update the warm-up flow in DistributedCommonTest around
awaitOrFail and awaitRoomSync to establish a single deadline using
WARMUP_TIMEOUT_SECS before connecting, joining, and synchronizing. Pass each
phase only its remaining time, and preserve failure behavior when the deadline
is exhausted so the entire warm-up remains within the documented 120-second
budget.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: bc5e46f8-d6e6-4bee-b8a9-942c4ce07880

📥 Commits

Reviewing files that changed from the base of the PR and between 0bd75f8 and 1575b99.

📒 Files selected for processing (1)
  • netty-socketio-core/src/test/java/com/socketio4j/socketio/integration/DistributedCommonTest.java

Comment on lines +138 to +143
awaitOrFail(connectLatch, WARMUP_TIMEOUT_SECS, "Warm-up clients failed to connect");

a.emit("join-room", room);
b.emit("join-room", room);
awaitOrFail(joinLatch, WARMUP_TIMEOUT_SECS, "Warm-up clients failed to join room");
awaitRoomSync(room, 2);

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.

🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Enforce the 120-second budget end-to-end.

Each latch can wait 120 seconds, and awaitRoomSync() adds another independent 120-second wait. A slow successful warm-up can therefore take nearly six minutes, not the documented 120 seconds. Create one deadline and pass its remaining time to each phase.

🤖 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
`@netty-socketio-core/src/test/java/com/socketio4j/socketio/integration/DistributedCommonTest.java`
around lines 138 - 143, Update the warm-up flow in DistributedCommonTest around
awaitOrFail and awaitRoomSync to establish a single deadline using
WARMUP_TIMEOUT_SECS before connecting, joining, and synchronizing. Pass each
phase only its remaining time, and preserve failure behavior when the deadline
is exhausted so the entire warm-up remains within the documented 120-second
budget.

@devin-ai-integration devin-ai-integration Bot left a comment

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

✅ Devin Review: No Issues Found

Devin Review analyzed this PR and found no bugs or issues to report.

Open in Devin Review

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