Skip to content

Conversation

@yyhhyyyyyy
Copy link
Collaborator

@yyhhyyyyyy yyhhyyyyyy commented Aug 28, 2025

optimize polling logic to prevent unnecessary IPC calls
IPCCalls will only be made when rate limiting is enabled

Summary by CodeRabbit

  • New Features
    • Added live provider rate‑limit status in Chat and Title views with dynamic updates when enabled.
    • Integrated rate‑limit settings so UI reflects enable/disable state in real time.
  • Refactor
    • Switched to conditional polling that runs only when rate limiting is enabled, reducing background activity.
    • Improved responsiveness to provider and settings changes with automatic refreshes.
    • Standardized event handling for more reliable updates across views.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Aug 28, 2025

Walkthrough

Introduces provider-aware rate-limit polling across ChatInput, TitleView, and ProviderRateLimitConfig components. Adds helpers to check if rate limiting is enabled via settings, conditions polling accordingly, unifies IPC event handling using RATE_LIMIT_EVENTS, updates lifecycle hooks and watchers, and adjusts types (interval handles; TitleView’s Model now includes providerId).

Changes

Cohort / File(s) Summary of Changes
Rate-limit polling lifecycle (renderer components)
src/renderer/src/components/ChatInput.vue, src/renderer/src/components/TitleView.vue, src/renderer/src/components/settings/ProviderRateLimitConfig.vue
Introduced conditional polling gated by provider rateLimit.enabled; added start/stop polling helpers; normalized interval typing to ReturnType | null; ensured cleanup on unmount; added watchers to restart polling on provider/settings changes.
IPC events consolidation
src/renderer/src/components/ChatInput.vue, src/renderer/src/components/TitleView.vue, src/renderer/src/components/settings/ProviderRateLimitConfig.vue
Replaced ad-hoc IPC listener names with RATE_LIMIT_EVENTS constants for CONFIG_UPDATED, REQUEST_EXECUTED, REQUEST_QUEUED; used removeAllListeners for cleanup; updated handlers to clear or reload status based on enable state.
Status load/control flow
src/renderer/src/components/ChatInput.vue, src/renderer/src/components/TitleView.vue
loadRateLimitStatus short-circuits and clears status when disabled; handleRateLimitEvent clears on disable, otherwise reloads and restarts polling; polling triggered on mount and relevant IPC events.
Public typing change
src/renderer/src/components/TitleView.vue
Model type used by props now includes providerId: string.
Settings view specific
src/renderer/src/components/settings/ProviderRateLimitConfig.vue
Added startStatusPolling/stopStatusPolling methods; watcher on rateLimitEnabled to align polling with enable state.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  actor User
  participant CI as ChatInput/TitleView
  participant SS as SettingsStore
  participant IPC as IPC (RATE_LIMIT_EVENTS)
  participant RL as RateLimit Service

  Note over CI,SS: On mount or provider/settings change
  CI->>SS: isRateLimitEnabled(providerId)
  alt Enabled
    CI->>RL: loadRateLimitStatus(providerId)
    CI->>CI: startRateLimitPolling(1s)
    loop every 1s
      CI->>RL: loadRateLimitStatus(providerId)
      RL-->>CI: status {config,currentQps,queueLength,...}
    end
  else Disabled
    CI->>CI: clear rateLimitStatus, stop polling
  end

  Note over IPC: Event-driven updates
  IPC-->>CI: CONFIG_UPDATED / REQUEST_EXECUTED / REQUEST_QUEUED
  CI->>SS: isRateLimitEnabled(providerId)
  alt Disabled by event/config
    CI->>CI: clear rateLimitStatus, stop polling
  else Still enabled
    CI->>RL: reload status
    CI->>CI: restart polling
  end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

Suggested reviewers

  • zerob13

Poem

A hop, a skip, a tick of time,
I poll the rates in perfect rhyme.
When limits sleep, I rest my feet—
When signals chirp, I’m back on beat.
Ears up, queues down, I keenly glean—
A rabbit’s watch: precise, serene. 🐇⏱️

✨ Finishing Touches
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch fix/rate-limit-polling-optimization

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.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbit in a new review comment at the desired location with your query.
  • PR comments: Tag @coderabbit 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:
    • @coderabbit gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbit read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.

Support

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

CodeRabbit Commands (Invoked using PR/Issue comments)

Type @coderabbit help to get the list of available commands.

Other keywords and placeholders

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

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Status, Documentation and Community

  • Visit our Status Page to check the current availability of CodeRabbit.
  • 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
Contributor

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

🧹 Nitpick comments (9)
src/renderer/src/components/settings/ProviderRateLimitConfig.vue (2)

250-252: Use English for comments

Replace the non-English comment per repo guidelines.

-  // 只有在速率限制启用时才开始轮询
+  // Start polling only when rate limiting is enabled

268-271: Deduplicate polling restarts

You restart polling here and also in handleEnabledChange. One source of truth is enough; the extra restart causes unnecessary clears/sets.

src/renderer/src/components/ChatInput.vue (3)

980-987: Stop polling immediately when disabled in event

If an event disables rate limiting, stop polling before doing anything else to avoid churn.

   if (data.providerId === chatStore.chatConfig.providerId) {
-    if (data.config && !data.config.enabled) {
-      rateLimitStatus.value = null
-    } else {
+    if (data.config && !data.config.enabled) {
+      rateLimitStatus.value = null
+      stopRateLimitPolling()
+    } else {
       loadRateLimitStatus()
-    }
-    startRateLimitPolling()
+      startRateLimitPolling()
+    }
   }

1000-1005: Reset in-flight guard on stop

Ensure the guard is cleared when stopping.

 const stopRateLimitPolling = () => {
   if (statusInterval) {
     clearInterval(statusInterval)
     statusInterval = null
+    isLoadingStatus = false
   }
 }

1039-1041: Use English for comments

Per repo guidelines, switch comment language.

-  // 只有在速率限制启用时才开始轮询
+  // Start polling only when rate limiting is enabled
src/renderer/src/components/TitleView.vue (4)

384-391: Stop polling when disabled in event to avoid churn

Stop before deciding whether to restart.

 if (data.providerId === props.model?.providerId) {
-  if (data.config && !data.config.enabled) {
-    rateLimitStatus.value = null
-  } else {
-    loadRateLimitStatus()
-  }
-  startRateLimitPolling()
+  if (data.config && !data.config.enabled) {
+    rateLimitStatus.value = null
+    stopRateLimitPolling()
+  } else {
+    loadRateLimitStatus()
+    startRateLimitPolling()
+  }
 }

404-409: Reset in-flight guard on stop

Ensure the guard resets when polling stops.

 const stopStatusPolling = () => {
   if (statusInterval) {
     clearInterval(statusInterval)
     statusInterval = null
+    isLoadingStatus = false
   }
 }

428-430: Use English for comments

Switch comment language per repo guidelines.

-  // 只有在速率限制启用时才开始轮询
+  // Start polling only when rate limiting is enabled

393-402: Consider extracting a shared rate-limit polling composable

start/stop/isEnabled/statusInterval patterns are duplicated across three components. Extract to a composable (e.g., useRateLimitPolling) with pluggable loader to reduce drift and ease maintenance.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between e5a205d and dc00ab6.

📒 Files selected for processing (3)
  • src/renderer/src/components/ChatInput.vue (5 hunks)
  • src/renderer/src/components/TitleView.vue (5 hunks)
  • src/renderer/src/components/settings/ProviderRateLimitConfig.vue (3 hunks)
🧰 Additional context used
📓 Path-based instructions (10)
src/renderer/src/**/*

📄 CodeRabbit inference engine (.cursor/rules/i18n.mdc)

src/renderer/src/**/*: All user-facing strings must use i18n keys (avoid hardcoded user-visible text in code)
Use the 'vue-i18n' framework for all internationalization in the renderer
Ensure all user-visible text in the renderer uses the translation system

Files:

  • src/renderer/src/components/settings/ProviderRateLimitConfig.vue
  • src/renderer/src/components/ChatInput.vue
  • src/renderer/src/components/TitleView.vue
src/renderer/**/*.{vue,ts,js,tsx,jsx}

📄 CodeRabbit inference engine (.cursor/rules/project-structure.mdc)

渲染进程代码放在 src/renderer

Files:

  • src/renderer/src/components/settings/ProviderRateLimitConfig.vue
  • src/renderer/src/components/ChatInput.vue
  • src/renderer/src/components/TitleView.vue
src/renderer/src/**/*.{vue,ts,tsx,js,jsx}

📄 CodeRabbit inference engine (.cursor/rules/vue-best-practices.mdc)

src/renderer/src/**/*.{vue,ts,tsx,js,jsx}: Use the Composition API for better code organization and reusability
Implement proper state management with Pinia
Utilize Vue Router for navigation and route management
Leverage Vue's built-in reactivity system for efficient data handling

Files:

  • src/renderer/src/components/settings/ProviderRateLimitConfig.vue
  • src/renderer/src/components/ChatInput.vue
  • src/renderer/src/components/TitleView.vue
src/renderer/src/**/*.vue

📄 CodeRabbit inference engine (.cursor/rules/vue-best-practices.mdc)

Use scoped styles to prevent CSS conflicts between components

src/renderer/src/**/*.vue: Follow existing component patterns when creating new UI components
Ensure responsive design with Tailwind CSS for new UI components
Add proper error handling and loading states to UI components

Files:

  • src/renderer/src/components/settings/ProviderRateLimitConfig.vue
  • src/renderer/src/components/ChatInput.vue
  • src/renderer/src/components/TitleView.vue
src/renderer/**/*.{ts,tsx,vue}

📄 CodeRabbit inference engine (.cursor/rules/vue-shadcn.mdc)

src/renderer/**/*.{ts,tsx,vue}: Use descriptive variable names with auxiliary verbs (e.g., isLoading, hasError).
Use TypeScript for all code; prefer types over interfaces.
Avoid enums; use const objects instead.
Use arrow functions for methods and computed properties.
Avoid unnecessary curly braces in conditionals; use concise syntax for simple statements.

Files:

  • src/renderer/src/components/settings/ProviderRateLimitConfig.vue
  • src/renderer/src/components/ChatInput.vue
  • src/renderer/src/components/TitleView.vue
src/renderer/**/*.{vue,ts}

📄 CodeRabbit inference engine (.cursor/rules/vue-shadcn.mdc)

Implement lazy loading for routes and components.

Files:

  • src/renderer/src/components/settings/ProviderRateLimitConfig.vue
  • src/renderer/src/components/ChatInput.vue
  • src/renderer/src/components/TitleView.vue
src/renderer/**/*.{ts,vue}

📄 CodeRabbit inference engine (.cursor/rules/vue-shadcn.mdc)

src/renderer/**/*.{ts,vue}: Use useFetch and useAsyncData for data fetching.
Implement SEO best practices using Nuxt's useHead and useSeoMeta.

src/renderer/**/*.{ts,vue}: Use Pinia for frontend state management
From renderer to main, call presenters via the usePresenter.ts composable

Files:

  • src/renderer/src/components/settings/ProviderRateLimitConfig.vue
  • src/renderer/src/components/ChatInput.vue
  • src/renderer/src/components/TitleView.vue
src/**/*.{ts,tsx,vue}

📄 CodeRabbit inference engine (CLAUDE.md)

Use English for all logs and comments

Files:

  • src/renderer/src/components/settings/ProviderRateLimitConfig.vue
  • src/renderer/src/components/ChatInput.vue
  • src/renderer/src/components/TitleView.vue
src/renderer/**/*.vue

📄 CodeRabbit inference engine (CLAUDE.md)

src/renderer/**/*.vue: Use Vue 3 Composition API for all components
Use Tailwind CSS with scoped styles for component styling

Files:

  • src/renderer/src/components/settings/ProviderRateLimitConfig.vue
  • src/renderer/src/components/ChatInput.vue
  • src/renderer/src/components/TitleView.vue
src/renderer/src/**

📄 CodeRabbit inference engine (CLAUDE.md)

Organize UI components by feature under src/renderer/src/

Files:

  • src/renderer/src/components/settings/ProviderRateLimitConfig.vue
  • src/renderer/src/components/ChatInput.vue
  • src/renderer/src/components/TitleView.vue
🧠 Learnings (1)
📚 Learning: 2025-08-26T14:13:46.601Z
Learnt from: CR
PR: ThinkInAIXYZ/deepchat#0
File: CLAUDE.md:0-0
Timestamp: 2025-08-26T14:13:46.601Z
Learning: Applies to src/renderer/**/*.{ts,vue} : From renderer to main, call presenters via the usePresenter.ts composable

Applied to files:

  • src/renderer/src/components/TitleView.vue
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: build-check (x64)
🔇 Additional comments (11)
src/renderer/src/components/ChatInput.vue (5)

221-221: Consistent IPC event naming

Importing RATE_LIMIT_EVENTS improves consistency across components.


956-960: Good: short-circuit status when disabled

Early return avoids unnecessary IPC calls when rate limiting is off.


970-977: Helper clarity

isRateLimitEnabled() reads from settings for the active provider—clear and aligns with PR goal.


1035-1038: IPC subscription alignment

Using RATE_LIMIT_EVENTS and a single handler is good.


1065-1072: Reacting to provider settings changes is correct

Deep watch + restart keeps UI in sync with settings.

src/renderer/src/components/TitleView.vue (6)

105-105: Settings store import aligns with new polling gate

Import is appropriate for isEnabled checks.


116-116: Settings store usage

Instantiating useSettingsStore() is required for gating; good.


360-365: Helper for enablement is clear and reusable

Looks good.


368-372: Short-circuit status load when disabled

Meets the PR objective to avoid unnecessary IPC.


443-444: ProviderId watcher restart is appropriate

Keeps view responsive to model/provider switches.


448-455: Reacting to provider settings changes is correct

Deep watch + restart maintains consistency with Settings changes.

Comment on lines +131 to 133
// 根据启用状态控制轮询
startStatusPolling()
}
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Avoid unnecessary IPC after toggling; gate status load when disabled

updateRateLimitConfig() calls loadStatus() unconditionally, which still performs IPC even when rate limiting is disabled. Either guard loadStatus() by rateLimitEnabled.value or conditionally call it only when enabled to fully meet the PR objective.

Outside selected lines, apply:

// Guard inside loadStatus
const loadStatus = async () => {
  if (!rateLimitEnabled.value) {
    status.value = null
    return
  }
  // ...existing body
}

// Or guard the call site
const updateRateLimitConfig = async () => {
  // ...existing update
  if (rateLimitEnabled.value) await loadStatus()
  else status.value = null
}
🤖 Prompt for AI Agents
In src/renderer/src/components/settings/ProviderRateLimitConfig.vue around lines
131-133, updateRateLimitConfig() currently calls loadStatus() unconditionally
causing unnecessary IPC when rate limiting is disabled; either gate loadStatus()
at its start to return early and clear status.value if rateLimitEnabled.value is
false, or change the call site to only invoke loadStatus() when
rateLimitEnabled.value is true and set status.value = null otherwise, ensuring
no IPC happens while disabled.

Comment on lines +225 to +242
let statusInterval: ReturnType<typeof setInterval> | null = null

const startStatusPolling = () => {
if (statusInterval) {
clearInterval(statusInterval)
}
if (rateLimitEnabled.value) {
statusInterval = setInterval(loadStatus, 1000)
}
}

const stopStatusPolling = () => {
if (statusInterval) {
clearInterval(statusInterval)
statusInterval = null
}
}

Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Prevent overlapping async polls; add in-flight guard

setInterval(loadStatus, 1000) can overlap if loadStatus is still running. Add an in-flight guard and reset on stop.

-let statusInterval: ReturnType<typeof setInterval> | null = null
+let statusInterval: ReturnType<typeof setInterval> | null = null
+let isLoadingStatus = false

 const startStatusPolling = () => {
   if (statusInterval) {
     clearInterval(statusInterval)
   }
   if (rateLimitEnabled.value) {
-    statusInterval = setInterval(loadStatus, 1000)
+    statusInterval = setInterval(async () => {
+      if (isLoadingStatus) return
+      isLoadingStatus = true
+      try {
+        await loadStatus()
+      } finally {
+        isLoadingStatus = false
+      }
+    }, 1000)
   }
 }

 const stopStatusPolling = () => {
   if (statusInterval) {
     clearInterval(statusInterval)
     statusInterval = null
+    isLoadingStatus = false
   }
 }
📝 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
let statusInterval: ReturnType<typeof setInterval> | null = null
const startStatusPolling = () => {
if (statusInterval) {
clearInterval(statusInterval)
}
if (rateLimitEnabled.value) {
statusInterval = setInterval(loadStatus, 1000)
}
}
const stopStatusPolling = () => {
if (statusInterval) {
clearInterval(statusInterval)
statusInterval = null
}
}
let statusInterval: ReturnType<typeof setInterval> | null = null
let isLoadingStatus = false
const startStatusPolling = () => {
if (statusInterval) {
clearInterval(statusInterval)
}
if (rateLimitEnabled.value) {
statusInterval = setInterval(async () => {
if (isLoadingStatus) return
isLoadingStatus = true
try {
await loadStatus()
} finally {
isLoadingStatus = false
}
}, 1000)
}
}
const stopStatusPolling = () => {
if (statusInterval) {
clearInterval(statusInterval)
statusInterval = null
isLoadingStatus = false
}
}
🤖 Prompt for AI Agents
In src/renderer/src/components/settings/ProviderRateLimitConfig.vue around lines
225 to 242, the current setInterval(loadStatus, 1000) can start a new loadStatus
while a previous call is still running; add an in-flight guard (e.g. let
statusLoading = false) and modify the polled callback to return early if
statusLoading is true, set statusLoading = true just before awaiting loadStatus
and set it back to false in finally so overlapping calls are prevented, and
ensure stopStatusPolling clears the interval and also resets statusLoading =
false to avoid a stuck-in-flight state.

Comment on lines +254 to 258
stopStatusPolling()
window.electron.ipcRenderer.removeAllListeners(RATE_LIMIT_EVENTS.CONFIG_UPDATED)
window.electron.ipcRenderer.removeAllListeners(RATE_LIMIT_EVENTS.REQUEST_EXECUTED)
window.electron.ipcRenderer.removeAllListeners(RATE_LIMIT_EVENTS.REQUEST_QUEUED)
})
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Do not use removeAllListeners; it nukes other components’ listeners

removeAllListeners(event) will detach listeners registered by other components for the same IPC event. Remove only this component’s handler.

-    stopStatusPolling()
-    window.electron.ipcRenderer.removeAllListeners(RATE_LIMIT_EVENTS.CONFIG_UPDATED)
-    window.electron.ipcRenderer.removeAllListeners(RATE_LIMIT_EVENTS.REQUEST_EXECUTED)
-    window.electron.ipcRenderer.removeAllListeners(RATE_LIMIT_EVENTS.REQUEST_QUEUED)
+    stopStatusPolling()
+    window.electron.ipcRenderer.removeListener(
+      RATE_LIMIT_EVENTS.CONFIG_UPDATED,
+      handleRateLimitEvent
+    )
+    window.electron.ipcRenderer.removeListener(
+      RATE_LIMIT_EVENTS.REQUEST_EXECUTED,
+      handleRateLimitEvent
+    )
+    window.electron.ipcRenderer.removeListener(
+      RATE_LIMIT_EVENTS.REQUEST_QUEUED,
+      handleRateLimitEvent
+    )
📝 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
stopStatusPolling()
window.electron.ipcRenderer.removeAllListeners(RATE_LIMIT_EVENTS.CONFIG_UPDATED)
window.electron.ipcRenderer.removeAllListeners(RATE_LIMIT_EVENTS.REQUEST_EXECUTED)
window.electron.ipcRenderer.removeAllListeners(RATE_LIMIT_EVENTS.REQUEST_QUEUED)
})
stopStatusPolling()
window.electron.ipcRenderer.removeListener(
RATE_LIMIT_EVENTS.CONFIG_UPDATED,
handleRateLimitEvent
)
window.electron.ipcRenderer.removeListener(
RATE_LIMIT_EVENTS.REQUEST_EXECUTED,
handleRateLimitEvent
)
window.electron.ipcRenderer.removeListener(
RATE_LIMIT_EVENTS.REQUEST_QUEUED,
handleRateLimitEvent
)
})
🤖 Prompt for AI Agents
In src/renderer/src/components/settings/ProviderRateLimitConfig.vue around lines
254-258, the cleanup currently calls removeAllListeners for
RATE_LIMIT_EVENTS.CONFIG_UPDATED, REQUEST_EXECUTED, and REQUEST_QUEUED which
removes listeners registered by other components; instead keep references to the
specific handlers added by this component (e.g., store bound functions on the
component instance or local variables when registering), and call
window.electron.ipcRenderer.removeListener (or .off) with each specific handler
for those three events, and also call stopStatusPolling() as before so only this
component’s listeners are removed.

Comment on lines +393 to 402
let statusInterval: ReturnType<typeof setInterval> | null = null

const startRateLimitPolling = () => {
if (statusInterval) {
clearInterval(statusInterval)
}
if (isRateLimitEnabled()) {
statusInterval = setInterval(loadRateLimitStatus, 1000)
}
}
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Prevent overlapping async polls; add in-flight guard

Same polling correctness concern as other components.

-let statusInterval: ReturnType<typeof setInterval> | null = null
+let statusInterval: ReturnType<typeof setInterval> | null = null
+let isLoadingStatus = false

 const startRateLimitPolling = () => {
   if (statusInterval) {
     clearInterval(statusInterval)
   }
   if (isRateLimitEnabled()) {
-    statusInterval = setInterval(loadRateLimitStatus, 1000)
+    statusInterval = setInterval(async () => {
+      if (isLoadingStatus) return
+      isLoadingStatus = true
+      try {
+        await loadRateLimitStatus()
+      } finally {
+        isLoadingStatus = false
+      }
+    }, 1000)
   }
 }
📝 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
let statusInterval: ReturnType<typeof setInterval> | null = null
const startRateLimitPolling = () => {
if (statusInterval) {
clearInterval(statusInterval)
}
if (isRateLimitEnabled()) {
statusInterval = setInterval(loadRateLimitStatus, 1000)
}
}
let statusInterval: ReturnType<typeof setInterval> | null = null
let isLoadingStatus = false
const startRateLimitPolling = () => {
if (statusInterval) {
clearInterval(statusInterval)
}
if (isRateLimitEnabled()) {
statusInterval = setInterval(async () => {
if (isLoadingStatus) return
isLoadingStatus = true
try {
await loadRateLimitStatus()
} finally {
isLoadingStatus = false
}
}, 1000)
}
}
🤖 Prompt for AI Agents
In src/renderer/src/components/TitleView.vue around lines 393 to 402, the
polling setup can re-enter loadRateLimitStatus if the previous async call hasn't
finished; add an in-flight guard boolean (e.g., let rateLimitPollInFlight =
false) alongside statusInterval, wrap loadRateLimitStatus calls in a small async
runner that returns immediately when the guard is true, set the guard to true
before awaiting loadRateLimitStatus and clear it in a finally block (clearing on
error as well), and update startRateLimitPolling to use setInterval against this
runner so polls never overlap while preserving the existing clearInterval logic.

Comment on lines +433 to 437
stopRateLimitPolling()
window.electron.ipcRenderer.removeAllListeners(RATE_LIMIT_EVENTS.CONFIG_UPDATED)
window.electron.ipcRenderer.removeAllListeners(RATE_LIMIT_EVENTS.REQUEST_EXECUTED)
window.electron.ipcRenderer.removeAllListeners(RATE_LIMIT_EVENTS.REQUEST_QUEUED)
})
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Avoid removeAllListeners; remove only this handler

Prevent collateral listener removal in other components.

-  stopRateLimitPolling()
-  window.electron.ipcRenderer.removeAllListeners(RATE_LIMIT_EVENTS.CONFIG_UPDATED)
-  window.electron.ipcRenderer.removeAllListeners(RATE_LIMIT_EVENTS.REQUEST_EXECUTED)
-  window.electron.ipcRenderer.removeAllListeners(RATE_LIMIT_EVENTS.REQUEST_QUEUED)
+  stopRateLimitPolling()
+  window.electron.ipcRenderer.removeListener(
+    RATE_LIMIT_EVENTS.CONFIG_UPDATED,
+    handleRateLimitEvent
+  )
+  window.electron.ipcRenderer.removeListener(
+    RATE_LIMIT_EVENTS.REQUEST_EXECUTED,
+    handleRateLimitEvent
+  )
+  window.electron.ipcRenderer.removeListener(
+    RATE_LIMIT_EVENTS.REQUEST_QUEUED,
+    handleRateLimitEvent
+  )
📝 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
stopRateLimitPolling()
window.electron.ipcRenderer.removeAllListeners(RATE_LIMIT_EVENTS.CONFIG_UPDATED)
window.electron.ipcRenderer.removeAllListeners(RATE_LIMIT_EVENTS.REQUEST_EXECUTED)
window.electron.ipcRenderer.removeAllListeners(RATE_LIMIT_EVENTS.REQUEST_QUEUED)
})
stopRateLimitPolling()
window.electron.ipcRenderer.removeListener(
RATE_LIMIT_EVENTS.CONFIG_UPDATED,
handleRateLimitEvent
)
window.electron.ipcRenderer.removeListener(
RATE_LIMIT_EVENTS.REQUEST_EXECUTED,
handleRateLimitEvent
)
window.electron.ipcRenderer.removeListener(
RATE_LIMIT_EVENTS.REQUEST_QUEUED,
handleRateLimitEvent
)
})
🤖 Prompt for AI Agents
In src/renderer/src/components/TitleView.vue around lines 433 to 437, avoid
calling removeAllListeners for RATE_LIMIT_EVENTS as it removes other components'
handlers; instead remove only the specific handlers you previously registered by
passing the same function references. Ensure the handlers you added earlier are
stored as named variables or component instance properties (not anonymous inline
functions) so you can call
window.electron.ipcRenderer.removeListener(RATE_LIMIT_EVENTS.CONFIG_UPDATED,
configUpdatedHandler) (and likewise for REQUEST_EXECUTED and REQUEST_QUEUED)
when cleaning up; keep stopRateLimitPolling() as-is and use removeListener/off
with the matching references to prevent collateral removal.

@zerob13 zerob13 merged commit 7e77985 into dev Aug 28, 2025
2 checks passed
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.

3 participants