diff --git a/packages/backend/src/core/NoteCreateService.ts b/packages/backend/src/core/NoteCreateService.ts index 9b7ef57d9c..e7f55f10ad 100644 --- a/packages/backend/src/core/NoteCreateService.ts +++ b/packages/backend/src/core/NoteCreateService.ts @@ -611,7 +611,7 @@ export class NoteCreateService implements OnApplicationShutdown { // Increment notes count (user) await this.incNotesCountOfUser(user); } else { - await this.usersRepository.update({ id: user.id }, { updatedAt: this.timeService.date }); + await this.queueService.createMarkUserUpdatedJob(user.id); } await this.pushToTl(note, user); diff --git a/packages/backend/src/core/NoteDeleteService.ts b/packages/backend/src/core/NoteDeleteService.ts index d780e5167d..82959f0782 100644 --- a/packages/backend/src/core/NoteDeleteService.ts +++ b/packages/backend/src/core/NoteDeleteService.ts @@ -28,12 +28,10 @@ import { ApLogService } from '@/core/ApLogService.js'; import type Logger from '@/logger.js'; import { TimeService } from '@/global/TimeService.js'; import { trackPromise } from '@/misc/promise-tracker.js'; -import { LoggerService } from '@/core/LoggerService.js'; +import { QueueService } from '@/core/QueueService.js'; @Injectable() export class NoteDeleteService { - private readonly logger: Logger; - constructor( @Inject(DI.config) private config: Config, @@ -63,11 +61,8 @@ export class NoteDeleteService { private latestNoteService: LatestNoteService, private readonly apLogService: ApLogService, private readonly timeService: TimeService, - - loggerService: LoggerService, - ) { - this.logger = loggerService.getLogger('note-delete-service'); - } + private readonly queueService: QueueService, + ) {} /** * 投稿を削除します。 @@ -131,7 +126,7 @@ export class NoteDeleteService { // Decrement notes count (user) this.decNotesCountOfUser(user); } else { - this.usersRepository.update({ id: user.id }, { updatedAt: this.timeService.date }); + await this.queueService.createMarkUserUpdatedJob(user.id); } if (this.meta.enableStatsForFederatedInstances) { diff --git a/packages/backend/src/core/NoteEditService.ts b/packages/backend/src/core/NoteEditService.ts index 0c595cbf20..11b22c0798 100644 --- a/packages/backend/src/core/NoteEditService.ts +++ b/packages/backend/src/core/NoteEditService.ts @@ -633,7 +633,7 @@ export class NoteEditService implements OnApplicationShutdown { } } - await this.usersRepository.update({ id: user.id }, { updatedAt: this.timeService.date }); + await this.queueService.createMarkUserUpdatedJob(user.id); // ハッシュタグ更新 await this.pushToTl(note, user); diff --git a/packages/backend/src/core/QueueService.ts b/packages/backend/src/core/QueueService.ts index 99911f38a7..9cd9754f21 100644 --- a/packages/backend/src/core/QueueService.ts +++ b/packages/backend/src/core/QueueService.ts @@ -935,6 +935,11 @@ export class QueueService implements OnModuleInit { return await this.createBackgroundTask({ type: 'delete-ap-logs', dataType, data }); } + @bindThis + public async createMarkUserUpdatedJob(userId: string) { + return await this.createBackgroundTask({ type: 'mark-user-updated', userId }, userId); + } + private async createBackgroundTask(data: T, duplication?: string | { id: string, ttl?: number }) { return await this.backgroundTaskQueue.add( data.type, diff --git a/packages/backend/src/core/ReactionService.ts b/packages/backend/src/core/ReactionService.ts index 27a6d7b514..8f642e014e 100644 --- a/packages/backend/src/core/ReactionService.ts +++ b/packages/backend/src/core/ReactionService.ts @@ -33,6 +33,7 @@ import { PER_NOTE_REACTION_USER_PAIR_CACHE_MAX } from '@/const.js'; import { CacheService } from '@/core/CacheService.js'; import { NoteVisibilityService } from '@/core/NoteVisibilityService.js'; import { TimeService } from '@/global/TimeService.js'; +import { QueueService } from '@/core/QueueService.js'; import type { DataSource } from 'typeorm'; const FALLBACK = '\u2764'; @@ -110,6 +111,7 @@ export class ReactionService implements OnModuleInit { private readonly cacheService: CacheService, private readonly noteVisibilityService: NoteVisibilityService, private readonly timeService: TimeService, + private readonly queueService: QueueService, ) { } @@ -224,7 +226,7 @@ export class ReactionService implements OnModuleInit { .execute(); } - this.usersRepository.update({ id: user.id }, { updatedAt: this.timeService.date }); + await this.queueService.createMarkUserUpdatedJob(user.id); // 30%の確率、セルフではない、3日以内に投稿されたノートの場合ハイライト用ランキング更新 if ( @@ -340,8 +342,7 @@ export class ReactionService implements OnModuleInit { .execute(); } - // TODO update caches - this.usersRepository.update({ id: user.id }, { updatedAt: this.timeService.date }); + await this.queueService.createMarkUserUpdatedJob(user.id); this.globalEventService.publishNoteStream(note.id, 'unreacted', { reaction: this.decodeReaction(exist.reaction).reaction, diff --git a/packages/backend/src/queue/processors/BackgroundTaskProcessorService.ts b/packages/backend/src/queue/processors/BackgroundTaskProcessorService.ts index 826b2af193..14c1523c3e 100644 --- a/packages/backend/src/queue/processors/BackgroundTaskProcessorService.ts +++ b/packages/backend/src/queue/processors/BackgroundTaskProcessorService.ts @@ -5,7 +5,7 @@ import { Inject, Injectable } from '@nestjs/common'; import * as Bull from 'bullmq'; -import { BackgroundTaskJobData, CheckHibernationBackgroundTask, PostDeliverBackgroundTask, PostInboxBackgroundTask, PostNoteBackgroundTask, UpdateFeaturedBackgroundTask, UpdateInstanceBackgroundTask, UpdateUserTagsBackgroundTask, UpdateUserBackgroundTask, UpdateNoteTagsBackgroundTask, DeleteFileBackgroundTask, UpdateLatestNoteBackgroundTask, PostSuspendBackgroundTask, PostUnsuspendBackgroundTask, DeleteApLogsBackgroundTask } from '@/queue/types.js'; +import { BackgroundTaskJobData, CheckHibernationBackgroundTask, PostDeliverBackgroundTask, PostInboxBackgroundTask, PostNoteBackgroundTask, UpdateFeaturedBackgroundTask, UpdateInstanceBackgroundTask, UpdateUserTagsBackgroundTask, UpdateUserBackgroundTask, UpdateNoteTagsBackgroundTask, DeleteFileBackgroundTask, UpdateLatestNoteBackgroundTask, PostSuspendBackgroundTask, PostUnsuspendBackgroundTask, DeleteApLogsBackgroundTask, MarkUserUpdatedBackgroundTask } from '@/queue/types.js'; import { ApPersonService } from '@/core/activitypub/models/ApPersonService.js'; import { QueueLoggerService } from '@/queue/QueueLoggerService.js'; import Logger from '@/logger.js'; @@ -19,7 +19,7 @@ import ApRequestChart from '@/core/chart/charts/ap-request.js'; import FederationChart from '@/core/chart/charts/federation.js'; import { UpdateInstanceQueue } from '@/core/UpdateInstanceQueue.js'; import { NoteCreateService } from '@/core/NoteCreateService.js'; -import type { DriveFilesRepository, NoteEditsRepository, NotesRepository } from '@/models/_.js'; +import type { DriveFilesRepository, NoteEditsRepository, NotesRepository, UsersRepository } from '@/models/_.js'; import { MiUser } from '@/models/_.js'; import { NoteEditService } from '@/core/NoteEditService.js'; import { HashtagService } from '@/core/HashtagService.js'; @@ -28,6 +28,7 @@ import { LatestNoteService } from '@/core/LatestNoteService.js'; import { trackTask } from '@/misc/promise-tracker.js'; import { UserSuspendService } from '@/core/UserSuspendService.js'; import { ApLogService } from '@/core/ApLogService.js'; +import { InternalEventService } from '@/core/InternalEventService.js'; @Injectable() export class BackgroundTaskProcessorService { @@ -46,6 +47,9 @@ export class BackgroundTaskProcessorService { @Inject(DI.noteEditsRepository) private readonly noteEditsRepository: NoteEditsRepository, + @Inject(DI.usersRepository) + private readonly usersRepository: UsersRepository, + private readonly apPersonService: ApPersonService, private readonly cacheService: CacheService, private readonly federatedInstanceService: FederatedInstanceService, @@ -61,6 +65,7 @@ export class BackgroundTaskProcessorService { private readonly latestNoteService: LatestNoteService, private readonly userSuspendService: UserSuspendService, private readonly apLogService: ApLogService, + private readonly internalEventService: InternalEventService, queueLoggerService: QueueLoggerService, ) { @@ -94,9 +99,11 @@ export class BackgroundTaskProcessorService { return await this.processPostSuspend(job.data); } else if (job.data.type === 'post-unsuspend') { return await this.processPostUnsuspend(job.data); - // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition } else if (job.data.type === 'delete-ap-logs') { return await this.processDeleteApLogs(job.data); + // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition + } else if (job.data.type === 'mark-user-updated') { + return await this.processMarkUserUpdated(job.data); } else { this.logger.warn(`Can't process unknown job type "${job.data}"; this is likely a bug. Full job data:`, job.data); throw new Error(`Unknown job type ${job.data}, see system logs for details`); @@ -338,4 +345,19 @@ export class BackgroundTaskProcessorService { return 'ok'; } + + private async processMarkUserUpdated(task: MarkUserUpdatedBackgroundTask): Promise { + const user = await this.cacheService.findOptionalUserById(task.userId); + if (!user || user.isDeleted) return `Skipping post-unsuspend task: user ${task.userId} has been deleted`; + + await this.usersRepository.update({ id: user.id }, { updatedAt: new Date() }); + + if (user.host == null) { + await this.internalEventService.emit('localUserUpdated', { id: user.id }); + } else { + await this.internalEventService.emit('remoteUserUpdated', { id: user.id }); + } + + return 'ok'; + } } diff --git a/packages/backend/src/queue/types.ts b/packages/backend/src/queue/types.ts index cb31e5a3e1..671500a275 100644 --- a/packages/backend/src/queue/types.ts +++ b/packages/backend/src/queue/types.ts @@ -184,7 +184,8 @@ export type BackgroundTaskJobData = UpdateLatestNoteBackgroundTask | PostSuspendBackgroundTask | PostUnsuspendBackgroundTask | - DeleteApLogsBackgroundTask; + DeleteApLogsBackgroundTask | + MarkUserUpdatedBackgroundTask; export type UpdateUserBackgroundTask = { type: 'update-user'; @@ -261,3 +262,8 @@ export type DeleteApLogsBackgroundTask = { dataType: 'inbox' | 'object'; data: string | string[]; }; + +export type MarkUserUpdatedBackgroundTask = { + type: 'mark-user-updated'; + userId: string; +};