From 70988519df66f0b8edeb6ca95140f1d3e436fea8 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Tue, 24 Sep 2024 19:02:36 +0200 Subject: [PATCH] Fix too many requests caused by relationship look-ups in web UI (#32042) Co-authored-by: Claire --- app/javascript/mastodon/actions/accounts.js | 23 +++++++++++++------ .../mastodon/actions/notifications.js | 13 +---------- app/javascript/mastodon/utils/debounce.ts | 23 +++++++++++++++++++ 3 files changed, 40 insertions(+), 19 deletions(-) create mode 100644 app/javascript/mastodon/utils/debounce.ts diff --git a/app/javascript/mastodon/actions/accounts.js b/app/javascript/mastodon/actions/accounts.js index 9144235195..3d0e8b8c90 100644 --- a/app/javascript/mastodon/actions/accounts.js +++ b/app/javascript/mastodon/actions/accounts.js @@ -1,4 +1,5 @@ import { browserHistory } from 'mastodon/components/router'; +import { debounceWithDispatchAndArguments } from 'mastodon/utils/debounce'; import api, { getLinks } from '../api'; @@ -449,6 +450,20 @@ export function expandFollowingFail(id, error) { }; } +const debouncedFetchRelationships = debounceWithDispatchAndArguments((dispatch, ...newAccountIds) => { + if (newAccountIds.length === 0) { + return; + } + + dispatch(fetchRelationshipsRequest(newAccountIds)); + + api().get(`/api/v1/accounts/relationships?with_suspended=true&${newAccountIds.map(id => `id[]=${id}`).join('&')}`).then(response => { + dispatch(fetchRelationshipsSuccess({ relationships: response.data })); + }).catch(error => { + dispatch(fetchRelationshipsFail(error)); + }); +}, { delay: 500 }); + export function fetchRelationships(accountIds) { return (dispatch, getState) => { const state = getState(); @@ -460,13 +475,7 @@ export function fetchRelationships(accountIds) { return; } - dispatch(fetchRelationshipsRequest(newAccountIds)); - - api().get(`/api/v1/accounts/relationships?with_suspended=true&${newAccountIds.map(id => `id[]=${id}`).join('&')}`).then(response => { - dispatch(fetchRelationshipsSuccess({ relationships: response.data })); - }).catch(error => { - dispatch(fetchRelationshipsFail(error)); - }); + debouncedFetchRelationships(dispatch, ...newAccountIds); }; } diff --git a/app/javascript/mastodon/actions/notifications.js b/app/javascript/mastodon/actions/notifications.js index 14072562d4..4c6e27cd5f 100644 --- a/app/javascript/mastodon/actions/notifications.js +++ b/app/javascript/mastodon/actions/notifications.js @@ -10,7 +10,7 @@ import api, { getLinks } from '../api'; import { unescapeHTML } from '../utils/html'; import { requestNotificationPermission } from '../utils/notifications'; -import { fetchFollowRequests, fetchRelationships } from './accounts'; +import { fetchFollowRequests } from './accounts'; import { importFetchedAccount, importFetchedAccounts, @@ -56,14 +56,6 @@ defineMessages({ group: { id: 'notifications.group', defaultMessage: '{count} notifications' }, }); -const fetchRelatedRelationships = (dispatch, notifications) => { - const accountIds = notifications.filter(item => ['follow', 'follow_request', 'admin.sign_up'].indexOf(item.type) !== -1).map(item => item.account.id); - - if (accountIds.length > 0) { - dispatch(fetchRelationships(accountIds)); - } -}; - export const loadPending = () => ({ type: NOTIFICATIONS_LOAD_PENDING, }); @@ -106,8 +98,6 @@ export function updateNotifications(notification, intlMessages, intlLocale) { dispatch(notificationsUpdate({ notification, preferPendingItems, playSound: playSound && !filtered})); - - fetchRelatedRelationships(dispatch, [notification]); } else if (playSound && !filtered) { dispatch({ type: NOTIFICATIONS_UPDATE_NOOP, @@ -199,7 +189,6 @@ export function expandNotifications({ maxId = undefined, forceLoad = false }) { dispatch(importFetchedAccounts(response.data.filter(item => item.report).map(item => item.report.target_account))); dispatch(expandNotificationsSuccess(response.data, next ? next.uri : null, isLoadingMore, isLoadingRecent, isLoadingRecent && preferPendingItems)); - fetchRelatedRelationships(dispatch, response.data); dispatch(submitMarkers()); } catch(error) { dispatch(expandNotificationsFail(error, isLoadingMore)); diff --git a/app/javascript/mastodon/utils/debounce.ts b/app/javascript/mastodon/utils/debounce.ts new file mode 100644 index 0000000000..224a538984 --- /dev/null +++ b/app/javascript/mastodon/utils/debounce.ts @@ -0,0 +1,23 @@ +import { debounce } from 'lodash'; + +import type { AppDispatch } from 'mastodon/store'; + +export const debounceWithDispatchAndArguments = ( + fn: (dispatch: AppDispatch, ...args: T[]) => void, + { delay = 100 }, +) => { + let argumentBuffer: T[] = []; + let dispatchBuffer: AppDispatch; + + const wrapped = debounce(() => { + const tmpBuffer = argumentBuffer; + argumentBuffer = []; + fn(dispatchBuffer, ...tmpBuffer); + }, delay); + + return (dispatch: AppDispatch, ...args: T[]) => { + dispatchBuffer = dispatch; + argumentBuffer.push(...args); + wrapped(); + }; +};