From 46398b3dcd2d0a28352cb36683e20482469b44f8 Mon Sep 17 00:00:00 2001 From: Hazelnoot Date: Wed, 1 Oct 2025 12:28:30 -0400 Subject: [PATCH] manage system accounts cache and fix sync issues --- .../backend/src/core/SystemAccountService.ts | 51 ++++++++++--------- 1 file changed, 28 insertions(+), 23 deletions(-) diff --git a/packages/backend/src/core/SystemAccountService.ts b/packages/backend/src/core/SystemAccountService.ts index 1288dc6ffa..38ad186f62 100644 --- a/packages/backend/src/core/SystemAccountService.ts +++ b/packages/backend/src/core/SystemAccountService.ts @@ -19,12 +19,15 @@ import { bindThis } from '@/decorators.js'; import { generateNativeUserToken } from '@/misc/token.js'; import { IdService } from '@/core/IdService.js'; import { genRsaKeyPair } from '@/misc/gen-key-pair.js'; +import { CacheManagementService, type ManagedMemoryKVCache } from '@/core/CacheManagementService.js'; +import { CacheService } from '@/core/CacheService.js'; +import { InternalEventService } from '@/core/InternalEventService.js'; export const SYSTEM_ACCOUNT_TYPES = ['actor', 'relay', 'proxy'] as const; @Injectable() export class SystemAccountService implements OnApplicationShutdown { - private cache: MemoryKVCache; + private readonly cache: ManagedMemoryKVCache; constructor( @Inject(DI.redisForSub) @@ -46,8 +49,11 @@ export class SystemAccountService implements OnApplicationShutdown { private userProfilesRepository: UserProfilesRepository, private idService: IdService, + private readonly cacheService: CacheService, + private readonly internalEventService: InternalEventService, + cacheManagementService: CacheManagementService, ) { - this.cache = new MemoryKVCache(1000 * 60 * 10); // 10m + this.cache = cacheManagementService.createMemoryKVCache(1000 * 60 * 10); // 10m this.redisForSub.on('message', this.onMessage); } @@ -84,25 +90,26 @@ export class SystemAccountService implements OnApplicationShutdown { @bindThis public async fetch(type: typeof SYSTEM_ACCOUNT_TYPES[number]): Promise { - const cached = this.cache.get(type); - if (cached) return cached; + // Use local cache to find userId for type + const userId = await this.cache.fetch(type, async () => { + const systemAccount = await this.systemAccountsRepository.findOne({ + where: { type: type }, + select: { id: true }, + }) as { id: string } | null; - const systemAccount = await this.systemAccountsRepository.findOne({ - where: { type: type }, - relations: ['user'], + if (systemAccount) { + return systemAccount.id; + } else { + const created = await this.createCorrespondingUser(type, { + username: `system.${type}`, // NOTE: (できれば避けたいが) . が含まれるかどうかでシステムアカウントかどうかを判定している処理もあるので変えないように + name: this.meta.name, + }); + return created.id; + } }); - if (systemAccount) { - this.cache.set(type, systemAccount.user as MiLocalUser); - return systemAccount.user as MiLocalUser; - } else { - const created = await this.createCorrespondingUser(type, { - username: `system.${type}`, // NOTE: (できれば避けたいが) . が含まれるかどうかでシステムアカウントかどうかを判定している処理もあるので変えないように - name: this.meta.name, - }); - this.cache.set(type, created); - return created; - } + // Get the actual user entity from shared caches. + return await this.cacheService.findLocalUserById(userId); } @bindThis @@ -192,6 +199,7 @@ export class SystemAccountService implements OnApplicationShutdown { if (Object.keys(updates).length > 0) { await this.usersRepository.update(user.id, updates); + await this.internalEventService.emit('localUserUpdated', { id: user.id }); } const profileUpdates = {} as Partial; @@ -199,12 +207,10 @@ export class SystemAccountService implements OnApplicationShutdown { if (Object.keys(profileUpdates).length > 0) { await this.userProfilesRepository.update(user.id, profileUpdates); + await this.internalEventService.emit('updateUserProfile', { userId: user.id }); } - const updated = await this.usersRepository.findOneByOrFail({ id: user.id }) as MiLocalUser; - this.cache.set(type, updated); - - return updated; + return await this.cacheService.findLocalUserById(user.id); } public async getInstanceActor() { @@ -222,7 +228,6 @@ export class SystemAccountService implements OnApplicationShutdown { @bindThis public dispose(): void { this.redisForSub.off('message', this.onMessage); - this.cache.dispose(); } @bindThis