add "immediate" option to NoteDeleteService

This commit is contained in:
Hazelnoot 2025-09-18 19:51:00 -04:00
parent 372385b755
commit 87212185b2
3 changed files with 25 additions and 14 deletions

View file

@ -28,7 +28,6 @@ import { ApLogService } from '@/core/ApLogService.js';
import { TimeService } from '@/global/TimeService.js'; import { TimeService } from '@/global/TimeService.js';
import { trackTask } from '@/misc/promise-tracker.js'; import { trackTask } from '@/misc/promise-tracker.js';
import { CollapsedQueueService } from '@/core/CollapsedQueueService.js'; import { CollapsedQueueService } from '@/core/CollapsedQueueService.js';
import { CacheService } from '@/core/CacheService.js';
@Injectable() @Injectable()
export class NoteDeleteService { export class NoteDeleteService {
@ -62,15 +61,12 @@ export class NoteDeleteService {
private readonly apLogService: ApLogService, private readonly apLogService: ApLogService,
private readonly timeService: TimeService, private readonly timeService: TimeService,
private readonly collapsedQueueService: CollapsedQueueService, private readonly collapsedQueueService: CollapsedQueueService,
private readonly cacheService: CacheService,
) {} ) {}
/** /**
* 稿 * 稿
* @param user 稿
* @param note 稿
*/ */
async delete(user: { id: MiUser['id']; uri: MiUser['uri']; host: MiUser['host']; isBot: MiUser['isBot']; }, note: MiNote, quiet = false, deleter?: MiUser) { async delete(user: MiUser, note: MiNote, deleter?: MiUser, immediate = false) {
// This kicks off lots of things that can run in parallel, but we should still wait for completion to ensure consistent state and to avoid task flood when calling in a loop. // This kicks off lots of things that can run in parallel, but we should still wait for completion to ensure consistent state and to avoid task flood when calling in a loop.
const promises: Promise<unknown>[] = []; const promises: Promise<unknown>[] = [];
@ -91,7 +87,8 @@ export class NoteDeleteService {
} }
} }
if (!quiet) { // Braces preserved to avoid merge conflicts
{
promises.push(this.globalEventService.publishNoteStream(note.id, 'deleted', { promises.push(this.globalEventService.publishNoteStream(note.id, 'deleted', {
deletedAt: deletedAt, deletedAt: deletedAt,
})); }));
@ -188,13 +185,16 @@ export class NoteDeleteService {
}); });
// Update the Latest Note index / following feed *after* note is deleted // Update the Latest Note index / following feed *after* note is deleted
promises.push(this.latestNoteService.handleDeletedNoteDeferred(note)); promises.push(immediate
? this.latestNoteService.handleDeletedNote(note)
: this.latestNoteService.handleDeletedNoteDeferred(note));
for (const cascadingNote of cascadingNotes) { for (const cascadingNote of cascadingNotes) {
promises.push(this.latestNoteService.handleDeletedNoteDeferred(cascadingNote)); promises.push(immediate
? this.latestNoteService.handleDeletedNote(cascadingNote)
: this.latestNoteService.handleDeletedNoteDeferred(cascadingNote));
} }
if (deleter && (note.userId !== deleter.id)) { if (deleter && (user.id !== deleter.id)) {
const user = await this.cacheService.findUserById(note.userId);
promises.push(this.moderationLogService.log(deleter, 'deleteNote', { promises.push(this.moderationLogService.log(deleter, 'deleteNote', {
noteId: note.id, noteId: note.id,
noteUserId: note.userId, noteUserId: note.userId,
@ -207,11 +207,22 @@ export class NoteDeleteService {
.map(n => n.uri) .map(n => n.uri)
.filter((u): u is string => u != null); .filter((u): u is string => u != null);
if (deletedUris.length > 0) { if (deletedUris.length > 0) {
promises.push(this.apLogService.deleteObjectLogsDeferred(deletedUris)); promises.push(immediate
? this.apLogService.deleteObjectLogs(deletedUris)
: this.apLogService.deleteObjectLogsDeferred(deletedUris));
} }
await trackTask(async () => { await trackTask(async () => {
await Promise.allSettled(promises); await Promise.allSettled(promises);
// This is deferred to make sure we don't race the enqueue() calls
if (immediate) {
await Promise.allSettled([
this.collapsedQueueService.updateNoteQueue.performAllNow(),
this.collapsedQueueService.updateUserQueue.performAllNow(),
this.collapsedQueueService.updateInstanceQueue.performAllNow(),
]);
}
}); });
} }

View file

@ -70,7 +70,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
} }
// この操作を行うのが投稿者とは限らない(例えばモデレーター)ため // この操作を行うのが投稿者とは限らない(例えばモデレーター)ため
await this.noteDeleteService.delete(await this.usersRepository.findOneByOrFail({ id: note.userId }), note, false, me); await this.noteDeleteService.delete(await this.usersRepository.findOneByOrFail({ id: note.userId }), note, me);
}); });
} }
} }

View file

@ -70,9 +70,9 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
// TODO inline this into the above query // TODO inline this into the above query
for (const note of renotes) { for (const note of renotes) {
if (ps.quote) { if (ps.quote) {
if (isQuote(note)) await this.noteDeleteService.delete(me, note, false); if (isQuote(note)) await this.noteDeleteService.delete(me, note);
} else { } else {
if (!isQuote(note)) await this.noteDeleteService.delete(me, note, false); if (!isQuote(note)) await this.noteDeleteService.delete(me, note);
} }
} }
}); });