ジョブキューの`Progress`の値を正しく計算する (#16218)

* fix: ジョブキューのProgressの値の範囲を 0~100 に統一

* fix(backend): ジョブキューのProgressの計算に用いる総数を最初に一度だけ取得する
This commit is contained in:
keito 2025-06-25 20:30:17 +09:00 committed by GitHub
parent eee9a5f853
commit c424554d4a
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
8 changed files with 36 additions and 34 deletions

View File

@ -34,6 +34,11 @@ export class CleanRemoteFilesProcessorService {
let deletedCount = 0;
let cursor: MiDriveFile['id'] | null = null;
const total = await this.driveFilesRepository.countBy({
userHost: Not(IsNull()),
isLink: false,
});
while (true) {
const files = await this.driveFilesRepository.find({
where: {
@ -58,12 +63,7 @@ export class CleanRemoteFilesProcessorService {
deletedCount += 8;
const total = await this.driveFilesRepository.countBy({
userHost: Not(IsNull()),
isLink: false,
});
job.updateProgress(100 / total * deletedCount);
job.updateProgress(deletedCount * total / 100);
}
this.logger.succ('All cached remote files has been deleted.');

View File

@ -43,6 +43,10 @@ export class DeleteDriveFilesProcessorService {
let deletedCount = 0;
let cursor: MiDriveFile['id'] | null = null;
const total = await this.driveFilesRepository.countBy({
userId: user.id,
});
while (true) {
const files = await this.driveFilesRepository.find({
where: {
@ -67,11 +71,7 @@ export class DeleteDriveFilesProcessorService {
deletedCount++;
}
const total = await this.driveFilesRepository.countBy({
userId: user.id,
});
job.updateProgress(deletedCount / total);
job.updateProgress(deletedCount / total * 100);
}
this.logger.succ(`All drive files (${deletedCount}) of ${user.id} has been deleted.`);

View File

@ -58,6 +58,10 @@ export class ExportBlockingProcessorService {
let exportedCount = 0;
let cursor: MiBlocking['id'] | null = null;
const total = await this.blockingsRepository.countBy({
blockerId: user.id,
});
while (true) {
const blockings = await this.blockingsRepository.find({
where: {
@ -97,11 +101,7 @@ export class ExportBlockingProcessorService {
exportedCount++;
}
const total = await this.blockingsRepository.countBy({
blockerId: user.id,
});
job.updateProgress(exportedCount / total);
job.updateProgress(exportedCount / total * 100);
}
stream.end();

View File

@ -95,6 +95,10 @@ export class ExportClipsProcessorService {
let exportedClipsCount = 0;
let cursor: MiClip['id'] | null = null;
const total = await this.clipsRepository.countBy({
userId: user.id,
});
while (true) {
const clips = await this.clipsRepository.find({
where: {
@ -126,11 +130,7 @@ export class ExportClipsProcessorService {
exportedClipsCount++;
}
const total = await this.clipsRepository.countBy({
userId: user.id,
});
job.updateProgress(exportedClipsCount / total);
job.updateProgress(exportedClipsCount / total * 100);
}
}

View File

@ -78,6 +78,10 @@ export class ExportFavoritesProcessorService {
let exportedFavoritesCount = 0;
let cursor: MiNoteFavorite['id'] | null = null;
const total = await this.noteFavoritesRepository.countBy({
userId: user.id,
});
while (true) {
const favorites = await this.noteFavoritesRepository.find({
where: {
@ -109,11 +113,7 @@ export class ExportFavoritesProcessorService {
exportedFavoritesCount++;
}
const total = await this.noteFavoritesRepository.countBy({
userId: user.id,
});
job.updateProgress(exportedFavoritesCount / total);
job.updateProgress(exportedFavoritesCount / total * 100);
}
await write(']');

View File

@ -58,6 +58,10 @@ export class ExportMutingProcessorService {
let exportedCount = 0;
let cursor: MiMuting['id'] | null = null;
const total = await this.mutingsRepository.countBy({
muterId: user.id,
});
while (true) {
const mutes = await this.mutingsRepository.find({
where: {
@ -98,11 +102,7 @@ export class ExportMutingProcessorService {
exportedCount++;
}
const total = await this.mutingsRepository.countBy({
muterId: user.id,
});
job.updateProgress(exportedCount / total);
job.updateProgress(exportedCount / total * 100);
}
stream.end();

View File

@ -37,6 +37,8 @@ class NoteStream extends ReadableStream<Record<string, unknown>> {
let exportedNotesCount = 0;
let cursor: MiNote['id'] | null = null;
const totalPromise = notesRepository.countBy({ userId });
const serialize = (
note: MiNote,
poll: MiPoll | null,
@ -88,8 +90,8 @@ class NoteStream extends ReadableStream<Record<string, unknown>> {
exportedNotesCount++;
}
const total = await notesRepository.countBy({ userId });
job.updateProgress(exportedNotesCount / total);
const total = await totalPromise;
job.updateProgress(exportedNotesCount / total * 100);
},
});
}

View File

@ -12,7 +12,7 @@ SPDX-License-Identifier: AGPL-3.0-only
</template>
<template #suffix>
<MkTime :time="job.finishedOn ?? job.processedOn ?? job.timestamp" mode="relative"/>
<span v-if="job.progress != null && typeof job.progress === 'number' && job.progress > 0" style="margin-left: 1em;">{{ Math.floor(job.progress * 100) }}%</span>
<span v-if="job.progress != null && typeof job.progress === 'number' && job.progress > 0" style="margin-left: 1em;">{{ Math.floor(job.progress) }}%</span>
<span v-if="job.opts.attempts != null && job.opts.attempts > 0 && job.attempts > 1" style="margin-left: 1em; color: var(--MI_THEME-warn); font-variant-numeric: diagonal-fractions;">{{ job.attempts }}/{{ job.opts.attempts }}</span>
<span v-if="job.isFailed && job.finishedOn != null" style="margin-left: 1em; color: var(--MI_THEME-error)"><i class="ti ti-circle-x"></i></span>
<span v-else-if="job.isFailed" style="margin-left: 1em; color: var(--MI_THEME-warn)"><i class="ti ti-alert-triangle"></i></span>