feat: Add debounce for meta query (#11195)

This PR combines the approaches in
https://github.com/chatwoot/chatwoot/pull/11190 and
https://github.com/chatwoot/chatwoot/pull/11187 to debounce the meta
request with a max wait time of 2.5 seconds With 500 concurrent users,
the theoretical limit with this is 720K requests per minute, if all of
them continuously receive websocket events.

The max wait of 2.5 seconds is still very generous, and we can easily
make it 2 seconds for smaller accounts and 5 seconds for larger
accounts.

```js
const debouncedFetchMetaData = debounce(fetchMetaData, 500, false, 200);
const longDebouncedFetchMetaData = debounce(fetchMetaData, 500, false, 5000);

export const actions = {
  get: async ({ commit, state: $state }, params) => {
    if ($state.allCount > 100) {
      longDebouncedFetchMetaData(commit, params);
    } else {
      debouncedFetchMetaData(commit, params);
    }
  },
  set({ commit }, meta) {
    commit(types.SET_CONV_TAB_META, meta);
  },
};

```

Related Utils PR: https://github.com/chatwoot/utils/pull/49
Here's the debounce in action

<img width="934" alt="image"
src="https://github.com/user-attachments/assets/5265a108-9c64-4488-9b4c-2e0d06aadc50"
/>

---------

Co-authored-by: Pranav <pranavrajs@gmail.com>
This commit is contained in:
Shivam Mishra
2025-03-28 08:11:02 +05:30
committed by GitHub
parent 5951c4b985
commit 9761214860
7 changed files with 45 additions and 141 deletions

View File

@@ -1,7 +1,6 @@
import types from '../mutation-types';
import ConversationApi from '../../api/inbox/conversation';
import ConversationMetaThrottleManager from 'dashboard/helper/ConversationMetaThrottleManager';
import { debounce } from '@chatwoot/utils';
const state = {
mineCount: 0,
@@ -13,38 +12,24 @@ export const getters = {
getStats: $state => $state,
};
export const shouldThrottle = conversationCount => {
// The threshold for throttling is different for normal users and large accounts
// Normal users: 2 seconds
// Large accounts: 10 seconds
// We would only update the conversation stats based on the threshold above.
// This is done to reduce the number of /meta request made to the server.
const NORMAL_USER_THRESHOLD = 2000;
const LARGE_ACCOUNT_THRESHOLD = 10000;
const threshold =
conversationCount > 100 ? LARGE_ACCOUNT_THRESHOLD : NORMAL_USER_THRESHOLD;
return ConversationMetaThrottleManager.shouldThrottle(threshold);
// Create a debounced version of the actual API call function
const fetchMetaData = async (commit, params) => {
try {
const response = await ConversationApi.meta(params);
const {
data: { meta },
} = response;
commit(types.SET_CONV_TAB_META, meta);
} catch (error) {
// ignore
}
};
export const actions = {
get: async ({ commit, state: $state }, params) => {
if (shouldThrottle($state.allCount)) {
// eslint-disable-next-line no-console
console.warn('Throttle /meta fetch, will resume after threshold');
return;
}
ConversationMetaThrottleManager.markUpdate();
const debouncedFetchMetaData = debounce(fetchMetaData, 500, false, 2500);
try {
const response = await ConversationApi.meta(params);
const {
data: { meta },
} = response;
commit(types.SET_CONV_TAB_META, meta);
} catch (error) {
// Ignore error
}
export const actions = {
get: async ({ commit }, params) => {
debouncedFetchMetaData(commit, params);
},
set({ commit }, meta) {
commit(types.SET_CONV_TAB_META, meta);