From 01872419c3feae1cadd10aa299eba3802ec0b5b7 Mon Sep 17 00:00:00 2001 From: dakkar Date: Fri, 13 Jun 2025 10:06:35 +0100 Subject: [PATCH] fix `UserEntityService` packMany hints * there's no need to pre-load follow requests for many users, since at most we'll pack them for only 1 user (the one requesting the data) * similarly, it makes sense to preload security keys for many users if we're serving a moderator's request, but if not, we need at most 1 user's keys (the requesting user's), and we can let `.pack()` fetch those * we always need to preload relations when serving a detailed request, not only when the set of users to pack does not include the requesting user --- .../src/core/entities/UserEntityService.ts | 38 ++++--------------- 1 file changed, 8 insertions(+), 30 deletions(-) diff --git a/packages/backend/src/core/entities/UserEntityService.ts b/packages/backend/src/core/entities/UserEntityService.ts index 91bf258ff4..04b7cbc79b 100644 --- a/packages/backend/src/core/entities/UserEntityService.ts +++ b/packages/backend/src/core/entities/UserEntityService.ts @@ -432,8 +432,6 @@ export class UserEntityService implements OnModuleInit { userIdsByUri?: Map, instances?: Map, securityKeyCounts?: Map, - pendingReceivedFollows?: Set, - pendingSentFollows?: Set, }, ): Promise> { const opts = Object.assign({ @@ -679,8 +677,8 @@ export class UserEntityService implements OnModuleInit { hasUnreadAntenna: this.getHasUnreadAntenna(user.id), hasUnreadChannel: false, // 後方互換性のため hasUnreadNotification: notificationsInfo?.hasUnread, // 後方互換性のため - hasPendingReceivedFollowRequest: opts.pendingReceivedFollows?.has(user.id) ?? this.getHasPendingReceivedFollowRequest(user.id), - hasPendingSentFollowRequest: opts.pendingSentFollows?.has(user.id) ?? this.getHasPendingSentFollowRequest(user.id), + hasPendingReceivedFollowRequest: this.getHasPendingReceivedFollowRequest(user.id), + hasPendingSentFollowRequest: this.getHasPendingSentFollowRequest(user.id), unreadNotificationsCount: notificationsInfo?.unreadCount, mutedWords: profile!.mutedWords, hardMutedWords: profile!.hardMutedWords, @@ -764,7 +762,7 @@ export class UserEntityService implements OnModuleInit { const isMe = meId && _userIds.includes(meId); const isDetailed = options && options.schema !== 'UserLite'; const isDetailedAndMe = isDetailed && isMe; - const isDetailedAndMeOrMod = isDetailed && (isMe || iAmModerator); + const isDetailedAndMod = isDetailed && iAmModerator; const isDetailedAndNotMe = isDetailed && !isMe; const userUris = new Set(_users @@ -787,14 +785,14 @@ export class UserEntityService implements OnModuleInit { // -- 実行者の有無や指定スキーマの種別によって要否が異なる値群を取得 - const [profilesMap, userMemos, userRelations, pinNotes, userIdsByUri, instances, securityKeyCounts, pendingReceivedFollows, pendingSentFollows] = await Promise.all([ + const [profilesMap, userMemos, userRelations, pinNotes, userIdsByUri, instances, securityKeyCounts] = await Promise.all([ // profilesMap this.cacheService.userProfileCache.fetchMany(_profilesToFetch).then(profiles => new Map(profiles.concat(_profilesFromUsers))), // userMemos isDetailed && meId ? this.userMemosRepository.findBy({ userId: meId }) .then(memos => new Map(memos.map(memo => [memo.targetUserId, memo.memo]))) : new Map(), // userRelations - isDetailedAndNotMe && meId ? this.getRelations(meId, _userIds) : new Map(), + isDetailed && meId ? this.getRelations(meId, _userIds) : new Map(), // pinNotes isDetailed ? this.userNotePiningsRepository.createQueryBuilder('pin') .where('pin.userId IN (:...userIds)', { userIds: _userIds }) @@ -828,7 +826,7 @@ export class UserEntityService implements OnModuleInit { Promise.all(Array.from(userHosts).map(async host => [host, await this.federatedInstanceService.fetch(host)] as const)) .then(hosts => new Map(hosts)), // securityKeyCounts - isDetailedAndMeOrMod ? this.userSecurityKeysRepository.createQueryBuilder('key') + isDetailedAndMod ? this.userSecurityKeysRepository.createQueryBuilder('key') .select('key.userId', 'userId') .addSelect('count(key.id)', 'userCount') .where({ @@ -836,26 +834,8 @@ export class UserEntityService implements OnModuleInit { }) .groupBy('key.userId') .getRawMany<{ userId: string, userCount: number }>() - .then(counts => new Map(counts.map(c => [c.userId, c.userCount]))) : new Map(), - // TODO optimization: cache follow requests - // pendingReceivedFollows - isDetailedAndMe ? this.followRequestsRepository.createQueryBuilder('req') - .select('req.followeeId', 'followeeId') - .where({ - followeeId: In(_userIds), - }) - .groupBy('req.followeeId') - .getRawMany<{ followeeId: string }>() - .then(reqs => new Set(reqs.map(r => r.followeeId))) : new Set(), - // pendingSentFollows - isDetailedAndMe ? this.followRequestsRepository.createQueryBuilder('req') - .select('req.followerId', 'followerId') - .where({ - followerId: In(_userIds), - }) - .groupBy('req.followerId') - .getRawMany<{ followerId: string }>() - .then(reqs => new Set(reqs.map(r => r.followerId))) : new Set(), + .then(counts => new Map(counts.map(c => [c.userId, c.userCount]))) + : undefined, // .pack will fetch the keys for the requesting user if it's in the _userIds ]); return Promise.all( @@ -872,8 +852,6 @@ export class UserEntityService implements OnModuleInit { userIdsByUri, instances, securityKeyCounts, - pendingReceivedFollows, - pendingSentFollows, }, )), );