Skip to content

Commit

Permalink
doFetchModBlockedList: don't block ui thread (#7674)
Browse files Browse the repository at this point in the history
* doFetchModBlockedList: don't block ui thread

doFetchModBlockedList is blocking the ui thread.

Duplicate data in `doFetchModBlockedList::blockListsPerChannel` to about 1000. The tab is dead when function hits, about 4s after reload.

- Yield occasionally using the `setTimeout` method.
- Doing a chunk size of 1 for now so we don't have to yield the inner loop as well (seems good enough). This is just based on a relatively large blocklist size.

- Can't do `await` in a callback, so must change the `forEach` to a `for`.

* yield thread in storeList

Co-authored-by: infinite-persistence <inf.persistence@gmail.com>
  • Loading branch information
jessopb and infinite-persistence authored Aug 12, 2022
1 parent b9be8d9 commit 1c17ff5
Showing 1 changed file with 66 additions and 53 deletions.
119 changes: 66 additions & 53 deletions ui/redux/actions/comments.js
Original file line number Diff line number Diff line change
Expand Up @@ -1143,6 +1143,9 @@ export function doCommentModUnBlockAsModerator(commenterUri: string, creatorUri:

export function doFetchModBlockedList() {
return async (dispatch: Dispatch, getState: GetState) => {
const LOOP_CHUNK_SIZE = 1;
const yieldThread = () => new Promise((resolve) => setTimeout(resolve));

const state = getState();
const myChannels = selectMyChannelClaims(state);
if (!myChannels) {
Expand Down Expand Up @@ -1172,7 +1175,7 @@ export function doFetchModBlockedList() {
})
)
)
.then((res) => {
.then(async (res) => {
let personalBlockList = [];
let adminBlockList = [];
let moderatorBlockList = [];
Expand All @@ -1185,66 +1188,76 @@ export function doFetchModBlockedList() {
const adminTimeoutMap = {};
const moderatorTimeoutMap = {};

const blockListsPerChannel = res.map((r) => r.value);
blockListsPerChannel
.sort((a, b) => {
return 1;
})
.forEach((channelBlockLists) => {
const storeList = (fetchedList, blockedList, timeoutMap, blockedByMap) => {
if (fetchedList) {
fetchedList.forEach((blockedChannel) => {
if (blockedChannel.blocked_channel_name) {
const channelUri = buildURI({
channelName: blockedChannel.blocked_channel_name,
channelClaimId: blockedChannel.blocked_channel_id,
});

if (!blockedList.find((blockedChannel) => isURIEqual(blockedChannel.channelUri, channelUri))) {
blockedList.push({ channelUri, blockedAt: blockedChannel.blocked_at });

if (blockedChannel.banned_for) {
timeoutMap[channelUri] = {
blockedAt: blockedChannel.blocked_at,
bannedFor: blockedChannel.banned_for,
banRemaining: blockedChannel.ban_remaining,
};
}
const blockListsPerChannel = [];
for (let i = 0; i < res.length; ++i) {
blockListsPerChannel.push(res[i].value);
if (i % 2 === 0) {
await yieldThread();
}
}
for (let i = 0; i < blockListsPerChannel.length; ++i) {
const storeList = async (fetchedList, blockedList, timeoutMap, blockedByMap) => {
if (fetchedList) {
for (let j = 0; j < fetchedList.length; ++j) {
const blockedChannel = fetchedList[j];
if (j > 0 && i % LOOP_CHUNK_SIZE === 0) {
await yieldThread();
}
if (blockedChannel.blocked_channel_name) {
const channelUri = buildURI({
channelName: blockedChannel.blocked_channel_name,
channelClaimId: blockedChannel.blocked_channel_id,
});

if (!blockedList.find((blockedChannel) => isURIEqual(blockedChannel.channelUri, channelUri))) {
blockedList.push({ channelUri, blockedAt: blockedChannel.blocked_at });

if (blockedChannel.banned_for) {
timeoutMap[channelUri] = {
blockedAt: blockedChannel.blocked_at,
bannedFor: blockedChannel.banned_for,
banRemaining: blockedChannel.ban_remaining,
};
}
}

if (blockedByMap !== undefined) {
const blockedByChannelUri = buildURI({
channelName: blockedChannel.blocked_by_channel_name,
channelClaimId: blockedChannel.blocked_by_channel_id,
});

if (blockedByMap[channelUri]) {
if (!blockedByMap[channelUri].includes(blockedByChannelUri)) {
blockedByMap[channelUri].push(blockedByChannelUri);
}
} else {
blockedByMap[channelUri] = [blockedByChannelUri];
if (blockedByMap !== undefined) {
const blockedByChannelUri = buildURI({
channelName: blockedChannel.blocked_by_channel_name,
channelClaimId: blockedChannel.blocked_by_channel_id,
});

if (blockedByMap[channelUri]) {
if (!blockedByMap[channelUri].includes(blockedByChannelUri)) {
blockedByMap[channelUri].push(blockedByChannelUri);
}
} else {
blockedByMap[channelUri] = [blockedByChannelUri];
}
}
});
}
}
};
}
};

const blocked_channels = channelBlockLists && channelBlockLists.blocked_channels;
const globally_blocked_channels = channelBlockLists && channelBlockLists.globally_blocked_channels;
const delegated_blocked_channels = channelBlockLists && channelBlockLists.delegated_blocked_channels;

storeList(blocked_channels, personalBlockList, personalTimeoutMap);
storeList(globally_blocked_channels, adminBlockList, adminTimeoutMap);
storeList(
delegated_blocked_channels,
moderatorBlockList,
moderatorTimeoutMap,
moderatorBlockListDelegatorsMap
);
});
const channelBlockLists = blockListsPerChannel[i];
const blocked_channels = channelBlockLists && channelBlockLists.blocked_channels;
const globally_blocked_channels = channelBlockLists && channelBlockLists.globally_blocked_channels;
const delegated_blocked_channels = channelBlockLists && channelBlockLists.delegated_blocked_channels;

if (i > 0 && i % LOOP_CHUNK_SIZE === 0) {
await yieldThread();
}

await storeList(blocked_channels, personalBlockList, personalTimeoutMap);
await storeList(globally_blocked_channels, adminBlockList, adminTimeoutMap);
await storeList(
delegated_blocked_channels,
moderatorBlockList,
moderatorTimeoutMap,
moderatorBlockListDelegatorsMap
);
}
dispatch({
type: ACTIONS.COMMENT_MODERATION_BLOCK_LIST_COMPLETED,
data: {
Expand Down

0 comments on commit 1c17ff5

Please sign in to comment.