Skip to content

test(messaging): add chat fan-out load test (Week 5) - #77

Open
Harxhit wants to merge 1 commit into
mainfrom
test/chat-load-fanout
Open

test(messaging): add chat fan-out load test (Week 5)#77
Harxhit wants to merge 1 commit into
mainfrom
test/chat-load-fanout

Conversation

@Harxhit

@Harxhit Harxhit commented Aug 27, 2026

Copy link
Copy Markdown
Owner

Note: authored by Claude (Anthropic) via Claude Code. Not yet executed against a live backend — results section is a placeholder, not fabricated.


Summary by cubic

Adds a socket.io load test that measures end-to-end chat fan-out latency and delivery completeness, covering the Week 5 goal of keeping messaging bounded under load. The script hasn't been run against a live backend yet, so the results doc's table is a placeholder.

Load test

  • Connects many receivers into a room with a subset sending; reports fan-out latency percentiles, delivery percentage, and rate-limit/moderation counts.
  • Pass --urls with multiple pod addresses to spread clients across signaling pods and exercise Redis adapter fan-out.
  • Uses an in-payload timestamp to measure latency because chat:message has no ack.

Written for commit 7936135. Summary will update on new commits.

Review in cubic

Adds a Socket.IO chat load driver: many receivers join a room and listen
for chat:message broadcasts while a subset send, measuring end-to-end
fan-out latency, delivery completeness, and rate-limit/moderation engagement.
Supports multi-pod fan-out via --urls (Redis adapter). Plus a README.

- load-test/chat-load-fanout.js — fan-out latency via in-payload timestamp
  (chat:message has no ack); reports delivery %, cross-pod completeness,
  and throttling counts; --urls spreads clients across pods
- load-test/results/CHAT-LOAD.md — how to run, args, interpretation + caveats
  (active rate limiter, shared-token limitation)

Note: authored by Claude (Anthropic) via Claude Code. Not yet executed
against a live backend — results section is a placeholder, not fabricated.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.
To continue using code reviews, you can upgrade your account or add credits to your account and enable them for code reviews in your settings.

@coderabbitai

coderabbitai Bot commented Aug 27, 2026

Copy link
Copy Markdown

Important

  • 🔍 Trigger review

This repository does not receive automatic reviews because it has fewer than 10 stars.

⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 038fa63c-c14b-48ae-b8e3-f34024d17289


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.

@sonarqubecloud

Copy link
Copy Markdown

Quality Gate Failed Quality Gate failed

Failed conditions
6.2% Duplication on New Code (required ≤ 3%)

See analysis details on SonarQube Cloud

@cubic-dev-ai cubic-dev-ai 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.

3 issues found across 2 files

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="load-test/chat-load-fanout.js">

<violation number="1" location="load-test/chat-load-fanout.js:134">
P2: When `--urls` names multiple pods, this round-robin sends viewers to non-owner pods where `joinRoom` cannot find the room state, so most clients fail and the run does not exercise cross-pod fan-out. Route room operations through the owner or restrict this mode to an ingress that provides ownership routing.</violation>

<violation number="2" location="load-test/chat-load-fanout.js:273">
P2: When rate limiting or moderation blocks messages, `totalExpected` still includes those messages even though they never broadcast, understating delivery percentage as a fan-out failure. Exclude rejected messages from the denominator using the rejection events or an explicit server acceptance signal.</violation>
</file>

<file name="load-test/results/CHAT-LOAD.md">

<violation number="1" location="load-test/results/CHAT-LOAD.md:98">
P3: The "Bounded under load" caveat defines the target as `deliveries received ≈ (broadcast messages × receivers)`, but the script computes the reported `Delivery %` against `sent × receivers` (`totalExpected = results.sent * joined.length`). Because the doc also states rate limiting/moderation will actively block some sent messages before they ever broadcast, the printed Delivery% is guaranteed to show a shortfall under load even when fan-out is complete. Ground the caveat's equation in what the script prints (sent × receivers) or instead point readers at the `fully fanned-out` metric, which already uses the broadcast denominator.</violation>
</file>

Reply with feedback, questions, or to request a fix.

Re-trigger cubic

// Delivery completeness. Each message that passes the server gate should
// reach every joined receiver. Rate-limited / moderated messages never
// broadcast, so they simply won't appear in nonceDeliveries.
const totalExpected = results.sent * joined.length;

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.

P2: When rate limiting or moderation blocks messages, totalExpected still includes those messages even though they never broadcast, understating delivery percentage as a fan-out failure. Exclude rejected messages from the denominator using the rejection events or an explicit server acceptance signal.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At load-test/chat-load-fanout.js, line 273:

<comment>When rate limiting or moderation blocks messages, `totalExpected` still includes those messages even though they never broadcast, understating delivery percentage as a fan-out failure. Exclude rejected messages from the denominator using the rejection events or an explicit server acceptance signal.</comment>

<file context>
@@ -0,0 +1,323 @@
+  // Delivery completeness. Each message that passes the server gate should
+  // reach every joined receiver. Rate-limited / moderated messages never
+  // broadcast, so they simply won't appear in nonceDeliveries.
+  const totalExpected = results.sent * joined.length;
+  const totalReceived = results.delivered;
+  let fullyDelivered = 0;
</file context>


// ---------- connect a receiver and join the room ----------
async function connectAndJoin(idx) {
const url = URLS[idx % URLS.length];

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.

P2: When --urls names multiple pods, this round-robin sends viewers to non-owner pods where joinRoom cannot find the room state, so most clients fail and the run does not exercise cross-pod fan-out. Route room operations through the owner or restrict this mode to an ingress that provides ownership routing.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At load-test/chat-load-fanout.js, line 134:

<comment>When `--urls` names multiple pods, this round-robin sends viewers to non-owner pods where `joinRoom` cannot find the room state, so most clients fail and the run does not exercise cross-pod fan-out. Route room operations through the owner or restrict this mode to an ingress that provides ownership routing.</comment>

<file context>
@@ -0,0 +1,323 @@
+
+// ---------- connect a receiver and join the room ----------
+async function connectAndJoin(idx) {
+  const url = URLS[idx % URLS.length];
+  const socket = io(url, {
+    transports: ["websocket"],
</file context>

Comment on lines +98 to +100
`deliveries received ≈ (broadcast messages × receivers)` as you scale
receivers/senders up. A latency blow-up or delivery shortfall is the signal.

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.

P3: The "Bounded under load" caveat defines the target as deliveries received ≈ (broadcast messages × receivers), but the script computes the reported Delivery % against sent × receivers (totalExpected = results.sent * joined.length). Because the doc also states rate limiting/moderation will actively block some sent messages before they ever broadcast, the printed Delivery% is guaranteed to show a shortfall under load even when fan-out is complete. Ground the caveat's equation in what the script prints (sent × receivers) or instead point readers at the fully fanned-out metric, which already uses the broadcast denominator.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At load-test/results/CHAT-LOAD.md, line 98:

<comment>The "Bounded under load" caveat defines the target as `deliveries received ≈ (broadcast messages × receivers)`, but the script computes the reported `Delivery %` against `sent × receivers` (`totalExpected = results.sent * joined.length`). Because the doc also states rate limiting/moderation will actively block some sent messages before they ever broadcast, the printed Delivery% is guaranteed to show a shortfall under load even when fan-out is complete. Ground the caveat's equation in what the script prints (sent × receivers) or instead point readers at the `fully fanned-out` metric, which already uses the broadcast denominator.</comment>

<file context>
@@ -0,0 +1,110 @@
+  same JWT, so the per-user bucket is shared. To test many *distinct* users,
+  extend the script to accept a token list — noted as a follow-up.
+- **"Bounded under load"** = fan-out latency percentiles stay flat and
+  `deliveries received ≈ (broadcast messages × receivers)` as you scale
+  receivers/senders up. A latency blow-up or delivery shortfall is the signal.
+
</file context>
Suggested change
`deliveries received ≈ (broadcast messages × receivers)` as you scale
receivers/senders up. A latency blow-up or delivery shortfall is the signal.
**"Bounded under load"** = fan-out latency percentiles stay flat and the printed `Delivery %` (against `sent × receivers`) tracks `fully fanned-out` (against `broadcast × receivers`) as you scale receivers/senders up. A latency blow-up or a gap between Delivery % and fully-fanned-out is the signal.

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