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:
Pranav
2025-03-26 14:59:39 -07:00
committed by GitHub
parent 49ee147fe3
commit 4b4d9f8f7c
5 changed files with 120 additions and 8 deletions

View File

@@ -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();

View File

@@ -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);
});
});
});

View File

@@ -1,28 +1,40 @@
import types from '../mutation-types';
import ConversationApi from '../../api/inbox/conversation';
import ConversationMetaThrottleManager from 'dashboard/helper/ConversationMetaThrottleManager';
const state = {
mineCount: 0,
unAssignedCount: 0,
allCount: 0,
updatedOn: null,
};
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);
};
export const actions = {
get: async ({ commit, state: $state }, params) => {
const currentTime = new Date();
const lastUpdatedTime = new Date($state.updatedOn);
// Skip large accounts from making too many requests
if (currentTime - lastUpdatedTime < 10000 && $state.allCount > 100) {
if (shouldThrottle($state.allCount)) {
// eslint-disable-next-line no-console
console.warn('Skipping conversation meta fetch');
console.warn('Throttle /meta fetch, will resume after threshold');
return;
}
ConversationMetaThrottleManager.markUpdate();
try {
const response = await ConversationApi.meta(params);

View File

@@ -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);
});
});

View File

@@ -10,7 +10,7 @@
html,
body {
@apply antialiased h-full bg-n-background;
@apply antialiased h-full;
}
.is-mobile {