Skip to content

perf(broadcast): optimize Broadcaster.broadcastWeight by caching client list#39

Closed
adcondev wants to merge 6 commits intomasterfrom
perf/broadcaster-client-list-cache-16602011425520877998
Closed

perf(broadcast): optimize Broadcaster.broadcastWeight by caching client list#39
adcondev wants to merge 6 commits intomasterfrom
perf/broadcaster-client-list-cache-16602011425520877998

Conversation

@adcondev
Copy link
Owner

This PR optimizes the broadcastWeight method in internal/server/broadcaster.go by introducing a Copy-On-Write (COW) caching mechanism for the list of connected WebSocket clients.

Previously, broadcastWeight would allocate a new slice and iterate over the clients map (O(N)) on every weight reading broadcast. This change maintains a cached clientList slice that is only rebuilt when clients connect or disconnect (which are infrequent operations compared to broadcasting).

The optimization reduces the per-broadcast overhead by eliminating the slice allocation and map iteration, replacing it with a simple pointer read (O(1)).

Performance Impact:
A benchmark with 1000 connected clients showed a ~6.3% improvement in dispatch time (from ~6.45ms/op to ~6.04ms/op). The primary gain is the removal of allocation pressure from the hot path.

Verification:

  • Added TestBroadcasterLogic to ensure the cached list stays in sync with the map during add/remove operations.
  • Added BenchmarkBroadcastWeight to measure the performance impact.
  • Ran existing tests to ensure no regressions.

PR created automatically by Jules for task 16602011425520877998 started by @adcondev

- Added `clientList` field to `Broadcaster` struct to cache the slice of connected clients.
- Updated `AddClient`, `RemoveClient`, and `removeAndCloseClient` to rebuild `clientList` when the `clients` map changes.
- Modified `broadcastWeight` to use the cached `clientList` instead of allocating a new slice and iterating the map on every call.
- Added `internal/server/broadcaster_test.go` with `BenchmarkBroadcastWeight` and `TestBroadcasterLogic` to verify performance and correctness.
- Measured ~6.3% improvement in dispatch time for 1000 clients (6.45ms -> 6.04ms).

Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com>
@google-labs-jules
Copy link
Contributor

👋 Jules, reporting for duty! I'm here to lend a hand with this pull request.

When you start a review, I'll add a 👀 emoji to each comment to let you know I've read it. I'll focus on feedback directed at me and will do my best to stay out of conversations between you and other bots or reviewers to keep the noise down.

I'll push a commit with your requested changes shortly after. Please note there might be a delay between these steps, but rest assured I'm on the job!

For more direct control, you can switch me to Reactive Mode. When this mode is on, I will only act on comments where you specifically mention me with @jules. You can find this option in the Pull Request section of your global Jules UI settings. You can always switch back!

New to Jules? Learn more at jules.google/docs.


For security, I will only act on instructions from the user who triggered this task.

Copilot AI review requested due to automatic review settings February 13, 2026 18:54
@github-actions
Copy link

👋 Thanks for opening this PR, @adcondev!

Here's what will happen next:

  • 🤖 Automated checks will run
  • 🏷️ Labels will be added automatically
  • 👀 A maintainer will review your changes

Please make sure:

  • ✅ All tests pass
  • 📝 Code follows project conventions
  • 📋 Changes are well documented

@github-actions
Copy link

github-actions bot commented Feb 13, 2026

⚡ Benchmark Results

📊 Current Branch Results

BenchmarkBroadcastWeight-4   	     183	   6014889 ns/op	 1696393 B/op	   25906 allocs/op

@codecov-commenter
Copy link

codecov-commenter commented Feb 13, 2026

⚠️ Please install the 'codecov app svg image' to ensure uploads and comments are reliably processed by Codecov.

Codecov Report

❌ Patch coverage is 83.33333% with 2 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
internal/server/broadcaster.go 83.33% 2 Missing ⚠️

📢 Thoughts on this report? Let us know!

Copy link
Contributor

Copilot AI left a comment

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 optimizes the WebSocket weight fan-out path by introducing a copy-on-write cached client slice in the Broadcaster, avoiding per-broadcast map iteration and slice allocation in broadcastWeight.

Changes:

  • Cache connected clients in Broadcaster.clientList, rebuilding the slice only on add/remove.
  • Update broadcastWeight to read the cached slice under RLock instead of rebuilding each call.
  • Add a unit test to validate cache/map synchronization and a benchmark to measure broadcast performance.

Reviewed changes

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

File Description
internal/server/broadcaster.go Adds clientList cache and rebuild logic on client add/remove to reduce hot-path overhead in broadcastWeight.
internal/server/broadcaster_test.go Adds TestBroadcasterLogic for cache correctness and BenchmarkBroadcastWeight for performance measurement.

adcondev and others added 4 commits February 13, 2026 18:58
- Added `clientList` field to `Broadcaster` struct to cache the slice of connected clients.
- Updated `AddClient`, `RemoveClient`, and `removeAndCloseClient` to rebuild `clientList` when the `clients` map changes.
- Modified `broadcastWeight` to use the cached `clientList` instead of allocating a new slice and iterating the map on every call.
- Added `internal/server/broadcaster_test.go` with `BenchmarkBroadcastWeight` and `TestBroadcasterLogic` to verify performance and correctness.
- Fixed linting errors in new test file (`bodyclose`, `errcheck`).
- Measured ~6.3% improvement in dispatch time for 1000 clients (6.45ms -> 6.04ms).

Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com>
- Added `clientList` field to `Broadcaster` struct to cache the slice of connected clients.
- Updated `AddClient`, `RemoveClient`, and `removeAndCloseClient` to rebuild `clientList` when the `clients` map changes.
- Modified `broadcastWeight` to use the cached `clientList` instead of allocating a new slice and iterating the map on every call.
- Added `internal/server/broadcaster_test.go` with `BenchmarkBroadcastWeight` and `TestBroadcasterLogic` to verify performance and correctness.
- Fixed linting errors in new test file (`bodyclose`, `errcheck`) related to `websocket.Dial` response handling.
- Measured ~6.3% improvement in dispatch time for 1000 clients (6.45ms -> 6.04ms).

Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Signed-off-by: Adrián Constante <ad_con.reload@proton.me>
@adcondev adcondev moved this to In review in POS RED2000 Feb 16, 2026
- Added `clientList` field to `Broadcaster` struct to cache the slice of connected clients.
- Updated `AddClient`, `RemoveClient`, and `removeAndCloseClient` to rebuild `clientList` when the `clients` map changes.
- Modified `broadcastWeight` to use the cached `clientList` instead of allocating a new slice and iterating the map on every call.
- Added `internal/server/broadcaster_test.go` with `BenchmarkBroadcastWeight` and `TestBroadcasterLogic` to verify performance and correctness.
- Fixed linting errors in new test file:
  - Addressed `bodyclose` and `errcheck` by closing response bodies from `websocket.Dial`.
  - Addressed `errcheck` by explicitly ignoring (`_ =`) error returns from `c.Close()` calls.
- Measured ~6.3% improvement in dispatch time for 1000 clients (6.45ms -> 6.04ms).

Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com>
@adcondev adcondev changed the title ⚡ Optimize Broadcaster.broadcastWeight by caching client list perf(broadcast): optimize Broadcaster.broadcastWeight by caching client list Feb 16, 2026
@adcondev
Copy link
Owner Author

not for now

@adcondev adcondev closed this Feb 16, 2026
@github-project-automation github-project-automation bot moved this from In review to Done in POS RED2000 Feb 16, 2026
@adcondev adcondev deleted the perf/broadcaster-client-list-cache-16602011425520877998 branch February 16, 2026 19:20
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

3 participants