mirror of
https://github.com/lingble/chatwoot.git
synced 2025-11-02 12:08:01 +00:00
fix: Update throttle for /meta endpoints, will call every 2s for small account, 10s for large accounts (#11190)
This update improves the throttling mechanism for conversation meta requests to optimize server load and enhance performance. The changes implement differentiated thresholds based on account size - a 2-second throttle for small accounts (≤100 conversations) and a 10-second throttle for large accounts (>100 conversations). Fixes #11178
This commit is contained in:
@@ -0,0 +1,29 @@
|
|||||||
|
class ConversationMetaThrottleManager {
|
||||||
|
constructor() {
|
||||||
|
this.lastUpdatedTime = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
shouldThrottle(threshold = 10000) {
|
||||||
|
if (!this.lastUpdatedTime) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const currentTime = new Date().getTime();
|
||||||
|
const lastUpdatedTime = new Date(this.lastUpdatedTime).getTime();
|
||||||
|
|
||||||
|
if (currentTime - lastUpdatedTime < threshold) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
markUpdate() {
|
||||||
|
this.lastUpdatedTime = new Date();
|
||||||
|
}
|
||||||
|
|
||||||
|
reset() {
|
||||||
|
this.lastUpdatedTime = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default new ConversationMetaThrottleManager();
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
import ConversationMetaThrottleManager from '../ConversationMetaThrottleManager';
|
||||||
|
|
||||||
|
describe('ConversationMetaThrottleManager', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
// Reset the lastUpdatedTime before each test
|
||||||
|
ConversationMetaThrottleManager.lastUpdatedTime = null;
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('shouldThrottle', () => {
|
||||||
|
it('returns false when lastUpdatedTime is not set', () => {
|
||||||
|
expect(ConversationMetaThrottleManager.shouldThrottle()).toBe(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('returns true when time difference is less than threshold', () => {
|
||||||
|
ConversationMetaThrottleManager.markUpdate();
|
||||||
|
expect(ConversationMetaThrottleManager.shouldThrottle()).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('returns false when time difference is more than threshold', () => {
|
||||||
|
ConversationMetaThrottleManager.lastUpdatedTime = new Date(
|
||||||
|
Date.now() - 11000
|
||||||
|
);
|
||||||
|
expect(ConversationMetaThrottleManager.shouldThrottle()).toBe(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('respects custom threshold value', () => {
|
||||||
|
ConversationMetaThrottleManager.lastUpdatedTime = new Date(
|
||||||
|
Date.now() - 5000
|
||||||
|
);
|
||||||
|
expect(ConversationMetaThrottleManager.shouldThrottle(3000)).toBe(false);
|
||||||
|
expect(ConversationMetaThrottleManager.shouldThrottle(6000)).toBe(true);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -1,28 +1,40 @@
|
|||||||
import types from '../mutation-types';
|
import types from '../mutation-types';
|
||||||
import ConversationApi from '../../api/inbox/conversation';
|
import ConversationApi from '../../api/inbox/conversation';
|
||||||
|
|
||||||
|
import ConversationMetaThrottleManager from 'dashboard/helper/ConversationMetaThrottleManager';
|
||||||
|
|
||||||
const state = {
|
const state = {
|
||||||
mineCount: 0,
|
mineCount: 0,
|
||||||
unAssignedCount: 0,
|
unAssignedCount: 0,
|
||||||
allCount: 0,
|
allCount: 0,
|
||||||
updatedOn: null,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export const getters = {
|
export const getters = {
|
||||||
getStats: $state => $state,
|
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);
|
||||||
|
};
|
||||||
|
|
||||||
export const actions = {
|
export const actions = {
|
||||||
get: async ({ commit, state: $state }, params) => {
|
get: async ({ commit, state: $state }, params) => {
|
||||||
const currentTime = new Date();
|
if (shouldThrottle($state.allCount)) {
|
||||||
const lastUpdatedTime = new Date($state.updatedOn);
|
|
||||||
|
|
||||||
// Skip large accounts from making too many requests
|
|
||||||
if (currentTime - lastUpdatedTime < 10000 && $state.allCount > 100) {
|
|
||||||
// eslint-disable-next-line no-console
|
// eslint-disable-next-line no-console
|
||||||
console.warn('Skipping conversation meta fetch');
|
console.warn('Throttle /meta fetch, will resume after threshold');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
ConversationMetaThrottleManager.markUpdate();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const response = await ConversationApi.meta(params);
|
const response = await ConversationApi.meta(params);
|
||||||
|
|||||||
@@ -0,0 +1,37 @@
|
|||||||
|
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
||||||
|
import ConversationMetaThrottleManager from 'dashboard/helper/ConversationMetaThrottleManager';
|
||||||
|
import { shouldThrottle } from '../../conversationStats';
|
||||||
|
|
||||||
|
vi.mock('dashboard/helper/ConversationMetaThrottleManager', () => ({
|
||||||
|
default: {
|
||||||
|
shouldThrottle: vi.fn(),
|
||||||
|
},
|
||||||
|
}));
|
||||||
|
|
||||||
|
describe('shouldThrottle', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
vi.clearAllMocks();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('uses normal threshold for accounts with 100 or fewer conversations', () => {
|
||||||
|
shouldThrottle(100);
|
||||||
|
expect(ConversationMetaThrottleManager.shouldThrottle).toHaveBeenCalledWith(
|
||||||
|
2000
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('uses large account threshold for accounts with more than 100 conversations', () => {
|
||||||
|
shouldThrottle(101);
|
||||||
|
expect(ConversationMetaThrottleManager.shouldThrottle).toHaveBeenCalledWith(
|
||||||
|
10000
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('returns the throttle value from ConversationMetaThrottleManager', () => {
|
||||||
|
ConversationMetaThrottleManager.shouldThrottle.mockReturnValue(true);
|
||||||
|
expect(shouldThrottle(50)).toBe(true);
|
||||||
|
|
||||||
|
ConversationMetaThrottleManager.shouldThrottle.mockReturnValue(false);
|
||||||
|
expect(shouldThrottle(150)).toBe(false);
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -10,7 +10,7 @@
|
|||||||
|
|
||||||
html,
|
html,
|
||||||
body {
|
body {
|
||||||
@apply antialiased h-full bg-n-background;
|
@apply antialiased h-full;
|
||||||
}
|
}
|
||||||
|
|
||||||
.is-mobile {
|
.is-mobile {
|
||||||
|
|||||||
Reference in New Issue
Block a user