Skip to content

Conversation

@mostlygeek
Copy link
Owner

@mostlygeek mostlygeek commented Jul 16, 2025

Fix high CPU issue in #189

The root cause was caused by the event library being imported. This PR:

  • refactor out time.Ticker (it was written by Deepseek R1)
    • there may be subtle bugs but all tests from original code passes
    • the performance may not high as the original code but good enough for llama-swap
    • works fine for a time vs outcome trade off :)
  • vendor in the code with README pointing back to the original repo

Summary by CodeRabbit

  • New Features

    • Introduced an in-process, event-driven dispatching system with generic event publishing and subscription capabilities.
    • Provided a default dispatcher instance and convenient functions for subscribing and emitting events.
  • Bug Fixes

    • Improved event queue handling to reduce CPU usage by eliminating reliance on time-based tickers.
  • Documentation

    • Added comprehensive documentation for the new event system, including usage notes and migration details.
  • Tests

    • Added extensive tests and benchmarks to ensure event system reliability and performance.
  • Chores

    • Updated dependencies and import paths to use the new internal event system.

@coderabbitai
Copy link

coderabbitai bot commented Jul 16, 2025

"""

Walkthrough

A generic event dispatching system was introduced, replacing the previous dependency on the external kelindar/event package with an in-tree implementation. New dispatcher code, convenience functions, and comprehensive tests were added. Import paths throughout the codebase were updated to use the local event package, and dispatcher instantiation was made configurable in one location.

Changes

File(s) Change Summary
event/event.go, event/default.go Added a generic, thread-safe event dispatching system with a default dispatcher and convenience functions (On, OnType, Emit).
event/event_test.go, event/default_test.go Added comprehensive unit tests and benchmarks for event publishing, subscribing, concurrency, and backpressure.
event/README.md Added documentation explaining the origin, motivation, and design changes of the event system.
llama-swap.go, proxy/process.go, proxy/proxymanager_api.go Updated import paths from kelindar/event to the new local event package.
proxy/logMonitor.go Updated import path and changed dispatcher instantiation to use NewDispatcherConfig(1000) for buffer sizing.
go.mod Removed external kelindar/event dependency and moved golib to main require block with explicit version.

Sequence Diagram(s)

sequenceDiagram
    participant Publisher
    participant Dispatcher
    participant Subscriber

    Publisher->>Dispatcher: Publish(event)
    Dispatcher->>Subscriber: Deliver event (async, via queue)
    Subscriber-->>Dispatcher: (Processes event)
Loading
sequenceDiagram
    participant Client
    participant Dispatcher

    Client->>Dispatcher: Subscribe(eventType, handler)
    Dispatcher-->>Client: Returns CancelFunc
    Client->>Dispatcher: Emit(event)
    Dispatcher->>Client: Handler invoked (async)
    Client->>Dispatcher: (Optionally calls CancelFunc to unsubscribe)
Loading

Possibly related PRs

  • mostlygeek/llama-swap#184: Adds the external dependency on github.com/kelindar/event and integrates it, which is now replaced by the in-tree event dispatching system introduced in this PR.
    """

📜 Recent review details

Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 37ea5d5 and 34b8df7.

⛔ Files ignored due to path filters (1)
  • go.sum is excluded by !**/*.sum
📒 Files selected for processing (1)
  • go.mod (1 hunks)
✅ Files skipped from review due to trivial changes (1)
  • go.mod

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
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Explain this complex logic.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai explain this code block.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and explain its main purpose.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link

@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: 2

♻️ Duplicate comments (1)
event/event_test.go (1)

1-2: Fix typos in copyright header.

🧹 Nitpick comments (4)
event/README.md (1)

1-3: Fix bare URL formatting

The documentation clearly explains the migration rationale, but the bare URL should be properly formatted.

Apply this diff to fix the bare URL:

-The code in `event` was originally a part of https://github.com/kelindar/event (v1.5.2)
+The code in `event` was originally a part of [kelindar/event](https://github.com/kelindar/event) (v1.5.2)
event/event_test.go (2)

137-204: Replace time.Sleep with deterministic synchronization.

Using time.Sleep for synchronization can lead to flaky tests. Consider using channels or WaitGroups for deterministic behavior.

For example, you could track completion of all subscriptions and publications using WaitGroups instead of arbitrary delays.


206-276: Replace time.Sleep with deterministic synchronization.

Similar to the previous test, avoid using time.Sleep for synchronization to prevent flaky tests.

event/event.go (1)

231-266: Refactor duplicated queue length calculation.

The maximum queue length calculation is duplicated. Consider extracting it into a helper method.

+// calculateMaxQueueLen returns the maximum queue length across all consumers
+func (s *group[T]) calculateMaxQueueLen() int {
+    maxLen := 0
+    for _, sub := range s.subs {
+        if len(sub.queue) > maxLen {
+            maxLen = len(sub.queue)
+        }
+    }
+    return maxLen
+}
+
 // Broadcast sends an event to all consumers
 func (s *group[T]) Broadcast(ev T) {
     s.cond.L.Lock()
     defer s.cond.L.Unlock()
 
     // Calculate current maximum queue length
-    s.maxLen = 0
-    for _, sub := range s.subs {
-        if len(sub.queue) > s.maxLen {
-            s.maxLen = len(sub.queue)
-        }
-    }
+    s.maxLen = s.calculateMaxQueueLen()
 
     // Backpressure: wait if queues are full
     for s.maxLen >= s.maxQueue {
         s.cond.Wait()
-
-        // Recalculate after wakeup
-        s.maxLen = 0
-        for _, sub := range s.subs {
-            if len(sub.queue) > s.maxLen {
-                s.maxLen = len(sub.queue)
-            }
-        }
+        s.maxLen = s.calculateMaxQueueLen()
     }
📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between a906cd4 and 37ea5d5.

📒 Files selected for processing (9)
  • event/README.md (1 hunks)
  • event/default.go (1 hunks)
  • event/default_test.go (1 hunks)
  • event/event.go (1 hunks)
  • event/event_test.go (1 hunks)
  • llama-swap.go (1 hunks)
  • proxy/logMonitor.go (2 hunks)
  • proxy/process.go (1 hunks)
  • proxy/proxymanager_api.go (1 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (4)
proxy/logMonitor.go (1)
event/event.go (1)
  • NewDispatcherConfig (43-54)
event/default_test.go (3)
event/event.go (2)
  • NewDispatcher (38-40)
  • Subscribe (96-99)
event/event_test.go (2)
  • MyEvent1 (308-310)
  • TypeEvent1 (304-304)
event/default.go (3)
  • On (16-18)
  • OnType (22-24)
  • Emit (28-30)
event/default.go (1)
event/event.go (5)
  • NewDispatcherConfig (43-54)
  • Event (17-19)
  • Subscribe (96-99)
  • SubscribeTo (102-152)
  • Publish (155-161)
event/event_test.go (1)
event/event.go (4)
  • NewDispatcher (38-40)
  • Subscribe (96-99)
  • Publish (155-161)
  • SubscribeTo (102-152)
🪛 markdownlint-cli2 (0.17.2)
event/README.md

1-1: Bare URL used

(MD034, no-bare-urls)

🔇 Additional comments (8)
llama-swap.go (1)

17-17: LGTM: Clean import path migration

The import path change from external kelindar/event to the internal github.com/mostlygeek/llama-swap/event package is consistent with the PR objective to address high CPU usage by replacing the ticker-based implementation.

proxy/proxymanager_api.go (1)

10-10: LGTM: Consistent import path migration

The import path update aligns with the migration to the internal event package and maintains API compatibility.

proxy/process.go (1)

17-17: LGTM: Import path migration completed

The import path change maintains consistency across the codebase and preserves the existing event emission functionality.

proxy/logMonitor.go (2)

11-11: LGTM: Import path migration completed

The import path change aligns with the codebase-wide migration to the internal event package.


43-43: Verified NewDispatcherConfig Usage

  • The function func NewDispatcherConfig(maxQueue int) *Dispatcher is defined in event/event.go and returns a valid *Dispatcher.
  • Passing 1000 matches the expected int parameter and is consistent with other defaults in the codebase (e.g., 25 000 and 50 000).
  • No further changes are needed.
event/default_test.go (1)

31-54: LGTM!

The test correctly validates the default dispatcher's event publishing mechanism with proper synchronization and atomic operations.

event/default.go (1)

10-30: LGTM!

The convenience functions provide a clean API for the default dispatcher with proper delegation to the core functions.

event/event.go (1)

29-54: LGTM!

Excellent design using atomic pointers and copy-on-write for lock-free reads with synchronized writes. The configurable queue size provides good flexibility.

Comment on lines +1 to +2
// Copyright (c) Roman Atachiants and contributore. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for detaile.
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Fix typos in copyright header.

The copyright header contains typos that should be corrected.

-// Copyright (c) Roman Atachiants and contributore. All rights reserved.
-// Licensed under the MIT license. See LICENSE file in the project root for detaile.
+// Copyright (c) Roman Atachiants and contributors. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for details.
📝 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
// Copyright (c) Roman Atachiants and contributore. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for detaile.
// Copyright (c) Roman Atachiants and contributors. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for details.
🤖 Prompt for AI Agents
In event/default_test.go at lines 1 to 2, fix the typos in the copyright header
by correcting "contributore" to "contributors" and "detaile" to "details" to
ensure proper spelling and professionalism.

Comment on lines +1 to +2
// Copyright (c) Roman Atachiants and contributore. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for detaile.
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Fix typos in copyright header.

Same typos as in the test file.

-// Copyright (c) Roman Atachiants and contributore. All rights reserved.
-// Licensed under the MIT license. See LICENSE file in the project root for detaile.
+// Copyright (c) Roman Atachiants and contributors. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for details.
📝 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
// Copyright (c) Roman Atachiants and contributore. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for detaile.
// Copyright (c) Roman Atachiants and contributors. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for details.
🤖 Prompt for AI Agents
In event/default.go at lines 1 to 2, fix the typos in the copyright header by
correcting "contributore" to "contributors" and "detaile" to "details" to match
the correct spelling used in the test file.

@mostlygeek mostlygeek merged commit 6299c1b into main Jul 16, 2025
3 checks passed
@mostlygeek mostlygeek deleted the fix-high-cpu branch July 16, 2025 01:04
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.

2 participants