fix(backend): 古いユーザーキャッシュを使うことへの対策 (misskey-dev#13453)

Co-authored-by: tamaina <tamaina@hotmail.co.jp>
This commit is contained in:
まっちゃとーにゅ 2024-02-25 04:20:12 +09:00
parent 4a615ff251
commit 552354c895
No known key found for this signature in database
GPG key ID: 6AFBBF529601C1DB
7 changed files with 27 additions and 27 deletions

View file

@ -21,7 +21,6 @@ import { ApPersonService } from '@/core/activitypub/models/ApPersonService.js';
import { ApDeliverManagerService } from '@/core/activitypub/ApDeliverManagerService.js'; import { ApDeliverManagerService } from '@/core/activitypub/ApDeliverManagerService.js';
import { ApRendererService } from '@/core/activitypub/ApRendererService.js'; import { ApRendererService } from '@/core/activitypub/ApRendererService.js';
import { UserEntityService } from '@/core/entities/UserEntityService.js'; import { UserEntityService } from '@/core/entities/UserEntityService.js';
import { CacheService } from '@/core/CacheService.js';
import { ProxyAccountService } from '@/core/ProxyAccountService.js'; import { ProxyAccountService } from '@/core/ProxyAccountService.js';
import { FederatedInstanceService } from '@/core/FederatedInstanceService.js'; import { FederatedInstanceService } from '@/core/FederatedInstanceService.js';
import { MetaService } from '@/core/MetaService.js'; import { MetaService } from '@/core/MetaService.js';
@ -61,7 +60,6 @@ export class AccountMoveService {
private instanceChart: InstanceChart, private instanceChart: InstanceChart,
private metaService: MetaService, private metaService: MetaService,
private relayService: RelayService, private relayService: RelayService,
private cacheService: CacheService,
private queueService: QueueService, private queueService: QueueService,
) { ) {
} }
@ -85,7 +83,7 @@ export class AccountMoveService {
Object.assign(src, update); Object.assign(src, update);
// Update cache // Update cache
this.cacheService.uriPersonCache.set(srcUri, src); this.globalEventService.publishInternalEvent('localUserUpdated', src);
const srcPerson = await this.apRendererService.renderPerson(src); const srcPerson = await this.apRendererService.renderPerson(src);
const updateAct = this.apRendererService.addContext(this.apRendererService.renderUpdate(srcPerson, src)); const updateAct = this.apRendererService.addContext(this.apRendererService.renderUpdate(srcPerson, src));

View file

@ -129,10 +129,12 @@ export class CacheService implements OnApplicationShutdown {
switch (type) { switch (type) {
case 'userChangeSuspendedState': case 'userChangeSuspendedState':
case 'userChangeDeletedState': case 'userChangeDeletedState':
case 'remoteUserUpdated': { case 'remoteUserUpdated':
case 'localUserUpdated': {
const user = await this.usersRepository.findOneBy({ id: body.id }); const user = await this.usersRepository.findOneBy({ id: body.id });
if (user == null) { if (user == null) {
this.userByIdCache.delete(body.id); this.userByIdCache.delete(body.id);
this.localUserByIdCache.delete(body.id);
for (const [k, v] of this.uriPersonCache.cache.entries()) { for (const [k, v] of this.uriPersonCache.cache.entries()) {
if (v.value?.id === body.id) { if (v.value?.id === body.id) {
this.uriPersonCache.delete(k); this.uriPersonCache.delete(k);

View file

@ -212,6 +212,7 @@ export interface InternalEventTypes {
userChangeDeletedState: { id: MiUser['id']; isDeleted: MiUser['isDeleted']; }; userChangeDeletedState: { id: MiUser['id']; isDeleted: MiUser['isDeleted']; };
userTokenRegenerated: { id: MiUser['id']; oldToken: string; newToken: string; }; userTokenRegenerated: { id: MiUser['id']; oldToken: string; newToken: string; };
remoteUserUpdated: { id: MiUser['id']; }; remoteUserUpdated: { id: MiUser['id']; };
localUserUpdated: { id: MiUser['id']; };
follow: { followerId: MiUser['id']; followeeId: MiUser['id']; }; follow: { followerId: MiUser['id']; followeeId: MiUser['id']; };
unfollow: { followerId: MiUser['id']; followeeId: MiUser['id']; }; unfollow: { followerId: MiUser['id']; followeeId: MiUser['id']; };
blockingCreated: { blockerId: MiUser['id']; blockeeId: MiUser['id']; }; blockingCreated: { blockerId: MiUser['id']; blockeeId: MiUser['id']; };

View file

@ -100,33 +100,24 @@ export class UserFollowingService implements OnModuleInit {
this.queueService.deliver(followee, content, follower.inbox, false); this.queueService.deliver(followee, content, follower.inbox, false);
} }
/**
* ThinUserでなくともユーザーの情報が最新でない場合はこちらを使うべき
*/
@bindThis
public async followByThinUser(
_follower: ThinUser,
_followee: ThinUser,
options: Parameters<typeof this.follow>[2] = {},
) {
const [follower, followee] = await Promise.all([
this.usersRepository.findOneByOrFail({ id: _follower.id }),
this.usersRepository.findOneByOrFail({ id: _followee.id }),
]) as [MiLocalUser | MiRemoteUser, MiLocalUser | MiRemoteUser];
await this.follow(follower, followee, options);
}
@bindThis @bindThis
public async follow( public async follow(
follower: MiLocalUser | MiRemoteUser, _follower: ThinUser,
followee: MiLocalUser | MiRemoteUser, _followee: ThinUser,
{ requestId, silent = false, withReplies }: { { requestId, silent = false, withReplies }: {
requestId?: string, requestId?: string,
silent?: boolean, silent?: boolean,
withReplies?: boolean, withReplies?: boolean,
} = {}, } = {},
): Promise<void> { ): Promise<void> {
/**
*
*/
const [follower, followee] = await Promise.all([
this.usersRepository.findOneByOrFail({ id: _follower.id }),
this.usersRepository.findOneByOrFail({ id: _followee.id }),
]) as [MiLocalUser | MiRemoteUser, MiLocalUser | MiRemoteUser];
if (this.userEntityService.isRemoteUser(follower) && this.userEntityService.isRemoteUser(followee)) { if (this.userEntityService.isRemoteUser(follower) && this.userEntityService.isRemoteUser(followee)) {
// What? // What?
throw new Error('Remote user cannot follow remote user.'); throw new Error('Remote user cannot follow remote user.');

View file

@ -193,6 +193,10 @@ export class RedisSingleCache<T> {
// TODO: メモリ節約のためあまり参照されないキーを定期的に削除できるようにする? // TODO: メモリ節約のためあまり参照されないキーを定期的に削除できるようにする?
export class MemoryKVCache<T> { export class MemoryKVCache<T> {
/**
*
* @deprecated
*/
public cache: Map<string, { date: number; value: T; }>; public cache: Map<string, { date: number; value: T; }>;
private lifetime: number; private lifetime: number;
private gcIntervalHandle: NodeJS.Timeout; private gcIntervalHandle: NodeJS.Timeout;
@ -207,6 +211,10 @@ export class MemoryKVCache<T> {
} }
@bindThis @bindThis
/**
* Mapにキャッシュをセットします
* @deprecated InternalEventなどで変更を全てのプロセス/
*/
public set(key: string, value: T): void { public set(key: string, value: T): void {
this.cache.set(key, { this.cache.set(key, {
date: Date.now(), date: Date.now(),

View file

@ -35,7 +35,7 @@ export class RelationshipProcessorService {
@bindThis @bindThis
public async processFollow(job: Bull.Job<RelationshipJobData>): Promise<string> { public async processFollow(job: Bull.Job<RelationshipJobData>): Promise<string> {
this.logger.info(`${job.data.from.id} is trying to follow ${job.data.to.id} ${job.data.withReplies ? 'with replies' : 'without replies'}`); this.logger.info(`${job.data.from.id} is trying to follow ${job.data.to.id} ${job.data.withReplies ? 'with replies' : 'without replies'}`);
await this.userFollowingService.followByThinUser(job.data.from, job.data.to, { await this.userFollowingService.follow(job.data.from, job.data.to, {
requestId: job.data.requestId, requestId: job.data.requestId,
silent: job.data.silent, silent: job.data.silent,
withReplies: job.data.withReplies, withReplies: job.data.withReplies,

View file

@ -443,9 +443,9 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
this.hashtagService.updateUsertags(user, tags); this.hashtagService.updateUsertags(user, tags);
//#endregion //#endregion
if (Object.keys(updates).length > 0) await this.usersRepository.update(user.id, updates); if (Object.keys(updates).length > 0) {
if (Object.keys(updates).includes('alsoKnownAs')) { await this.usersRepository.update(user.id, updates);
this.cacheService.uriPersonCache.set(this.userEntityService.genLocalUserUri(user.id), { ...user, ...updates }); this.globalEventService.publishInternalEvent('localUserUpdated', { id: user.id });
} }
await this.userProfilesRepository.update(user.id, { await this.userProfilesRepository.update(user.id, {