mirror of
https://github.com/fluxerapp/fluxer
synced 2026-10-17 21:15:32 +09:00
fix(user): stop invalidating user cache on profile reads (#2142)
This commit is contained in:
1 parent
fcb629ca06
commit
6eca64a8f7
5 files changed
+76
-13
No files matched your search
@@ -136,6 +136,21 @@ describe('UserCacheService', () => {
|
||||
expect(usersServiceClient.requests).toEqual([[userId]]);
|
||||
});
|
||||
|
||||
it('seeds only the request cache when mapping a user on a read path', () => {
|
||||
const userId = createUserID(4501n);
|
||||
const usersServiceClient = new FakeUsersServiceClient();
|
||||
const service = new UserCacheService(usersServiceClient);
|
||||
const user = createUser(userId, 'ReadUser');
|
||||
const requestCache = createRequestCache();
|
||||
|
||||
const partial = service.setUserPartialResponseFromUserInRequestCache(user, requestCache);
|
||||
|
||||
expect(partial.username).toBe('ReadUser');
|
||||
expect(requestCache.userPartials.get(userId)).toBe(partial);
|
||||
expect(usersServiceClient.invalidated).toEqual([]);
|
||||
expect(usersServiceClient.requests).toEqual([]);
|
||||
});
|
||||
|
||||
it('invalidates the users service cache when seeding a partial from a user update', async () => {
|
||||
const userId = createUserID(4001n);
|
||||
const usersServiceClient = new FakeUsersServiceClient();
|
||||
|
||||
@@ -94,6 +94,12 @@ export class UserCacheService {
|
||||
return response;
|
||||
}
|
||||
|
||||
setUserPartialResponseFromUserInRequestCache(user: User, requestCache: RequestCache): UserPartialResponse {
|
||||
const response = mapUserToPartialResponse(user);
|
||||
requestCache.userPartials.set(user.id, response);
|
||||
return response;
|
||||
}
|
||||
|
||||
private createDeletedUserPartialFallback(userId: UserID): UserPartialResponse {
|
||||
return {
|
||||
id: userId.toString(),
|
||||
|
||||
@@ -24,17 +24,17 @@ export async function getCachedUserPartialResponses(params: {
|
||||
return await userCacheService.getUserPartialResponses(userIds, requestCache);
|
||||
}
|
||||
|
||||
export async function mapUserToPartialResponseWithCache(params: {
|
||||
export function mapUserToPartialResponseWithCache(params: {
|
||||
user: User;
|
||||
userCacheService: Pick<UserCacheService, 'setUserPartialResponseFromUserInBackground'>;
|
||||
userCacheService: Pick<UserCacheService, 'setUserPartialResponseFromUserInRequestCache'>;
|
||||
requestCache: RequestCache;
|
||||
}): Promise<UserPartialResponse> {
|
||||
}): UserPartialResponse {
|
||||
const {user, userCacheService, requestCache} = params;
|
||||
const cached = requestCache.userPartials.get(user.id);
|
||||
if (cached) {
|
||||
return cached;
|
||||
}
|
||||
return userCacheService.setUserPartialResponseFromUserInBackground(user, requestCache);
|
||||
return userCacheService.setUserPartialResponseFromUserInRequestCache(user, requestCache);
|
||||
}
|
||||
|
||||
export async function invalidateUserCache(params: {
|
||||
|
||||
@@ -479,19 +479,17 @@ export class UserAccountRequestService {
|
||||
const guildMemberProfile = mapGuildMemberToProfileResponse(profile.guildMemberDomain ?? null, {restrictProfile});
|
||||
const timezoneOffset = profile.timezoneVisible ? getCurrentTimeZoneOffsetMinutes(profileUser.timezone) : null;
|
||||
const mutualFriends = profile.mutualFriends
|
||||
? await Promise.all(
|
||||
profile.mutualFriends.map((user) =>
|
||||
mapUserToPartialResponseWithCache({
|
||||
user,
|
||||
userCacheService: this.userCacheService,
|
||||
requestCache: params.requestCache,
|
||||
}),
|
||||
),
|
||||
? profile.mutualFriends.map((user) =>
|
||||
mapUserToPartialResponseWithCache({
|
||||
user,
|
||||
userCacheService: this.userCacheService,
|
||||
requestCache: params.requestCache,
|
||||
}),
|
||||
)
|
||||
: undefined;
|
||||
const connectedAccounts = profile.connections ? this.mapConnectionsToResponse(profile.connections) : undefined;
|
||||
return {
|
||||
user: await mapUserToPartialResponseWithCache({
|
||||
user: mapUserToPartialResponseWithCache({
|
||||
user: profileUser,
|
||||
userCacheService: this.userCacheService,
|
||||
requestCache: params.requestCache,
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
// SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
|
||||
import type {UserProfileFullResponse} from '@fluxer/schema/src/domains/user/UserResponseSchemas';
|
||||
import {afterAll, beforeAll, beforeEach, describe, expect, it, vi} from 'vitest';
|
||||
import {createTestAccount} from '../../auth/tests/AuthTestUtils';
|
||||
import {createFriendship} from '../../channel/tests/ChannelTestUtils';
|
||||
import {UserCacheService} from '../../infrastructure/UserCacheService';
|
||||
import {type ApiTestHarness, createApiTestHarness} from '../../test/ApiTestHarness';
|
||||
import {createBuilder} from '../../test/TestRequestBuilder';
|
||||
|
||||
describe('User Profile Cache Invalidation', () => {
|
||||
let harness: ApiTestHarness;
|
||||
beforeAll(async () => {
|
||||
harness = await createApiTestHarness();
|
||||
});
|
||||
beforeEach(async () => {
|
||||
await harness.reset();
|
||||
});
|
||||
afterAll(async () => {
|
||||
await harness?.shutdown();
|
||||
});
|
||||
|
||||
it('resolves the profile subject and mutual friends without invalidating the users service cache', async () => {
|
||||
const viewerAccount = await createTestAccount(harness);
|
||||
const targetAccount = await createTestAccount(harness);
|
||||
const mutualAccount = await createTestAccount(harness);
|
||||
await createFriendship(harness, viewerAccount, targetAccount);
|
||||
await createFriendship(harness, viewerAccount, mutualAccount);
|
||||
await createFriendship(harness, targetAccount, mutualAccount);
|
||||
const invalidateUserCache = vi.spyOn(UserCacheService.prototype, 'invalidateUserCache');
|
||||
|
||||
try {
|
||||
const profile = await createBuilder<UserProfileFullResponse>(harness, viewerAccount.token)
|
||||
.get(`/users/${targetAccount.userId}/profile?with_mutual_friends=true`)
|
||||
.execute();
|
||||
|
||||
expect(profile.user.id).toBe(targetAccount.userId);
|
||||
expect(profile.mutual_friends?.map((friend) => friend.id)).toEqual([mutualAccount.userId]);
|
||||
expect(invalidateUserCache).not.toHaveBeenCalled();
|
||||
} finally {
|
||||
invalidateUserCache.mockRestore();
|
||||
}
|
||||
});
|
||||
});
|
||||
Reference in new issue
Block a user