feat(backend revision): add clean-up note revisions job (#5349)

This commit is contained in:
yamashu 2024-09-27 00:24:24 +09:00 committed by GitHub
parent b80552bb29
commit 4fce422bdb
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
7 changed files with 337 additions and 4 deletions

View file

@ -3,11 +3,13 @@
*
* SPDX-License-Identifier: AGPL-3.0-only
*/
import { Injectable } from '@nestjs/common';
import { Inject, Injectable } from '@nestjs/common';
import { Cron, Timeout } from '@nestjs/schedule';
import { InjectRepository } from '@nestjs/typeorm';
import { createPatch } from 'diff';
import { Repository } from 'typeorm';
import noteConfiguration, { NoteConfig } from '../config/note.config';
import { NotInDBError } from '../errors/errors';
import { ConsoleLoggerService } from '../logger/console-logger.service';
import { Note } from '../notes/note.entity';
@ -29,6 +31,9 @@ export class RevisionsService {
private readonly logger: ConsoleLoggerService,
@InjectRepository(Revision)
private revisionRepository: Repository<Revision>,
@InjectRepository(Note)
private noteRepository: Repository<Note>,
@Inject(noteConfiguration.KEY) private noteConfig: NoteConfig,
private editService: EditService,
) {
this.logger.setContext(RevisionsService.name);
@ -230,4 +235,80 @@ export class RevisionsService {
await this.revisionRepository.save(revision);
}
}
// Delete all old revisions everyday on 0:00 AM
@Cron('0 0 * * *')
async handleRevisionCleanup(): Promise<void> {
return await this.removeOldRevisions();
}
// Delete all old revisions 5 sec after startup
@Timeout(5000)
async handleRevisionCleanupTimeout(): Promise<void> {
return await this.removeOldRevisions();
}
/**
* Delete old {@link Revision}s except the latest one.
*
* @async
*/
async removeOldRevisions(): Promise<void> {
const currentTime = new Date().getTime();
const revisionRetentionDays: number = this.noteConfig.revisionRetentionDays;
if (revisionRetentionDays <= 0) {
return;
}
const revisionRetentionSeconds =
revisionRetentionDays * 24 * 60 * 60 * 1000;
const notes: Note[] = await this.noteRepository.find();
for (const note of notes) {
const revisions: Revision[] = await this.revisionRepository.find({
where: {
note: { id: note.id },
},
order: {
createdAt: 'ASC',
},
});
const oldRevisions = revisions
.slice(0, -1) // always keep the latest revision
.filter(
(revision) =>
new Date(revision.createdAt).getTime() <=
currentTime - revisionRetentionSeconds,
);
const remainedRevisions = revisions.filter(
(val) => !oldRevisions.includes(val),
);
if (!oldRevisions.length) {
continue;
} else if (oldRevisions.length === revisions.length - 1) {
const beUpdatedRevision = revisions.slice(-1)[0];
beUpdatedRevision.patch = createPatch(
note.publicId,
'', // there is no older revision
beUpdatedRevision.content,
);
await this.revisionRepository.save(beUpdatedRevision);
} else {
const beUpdatedRevision = remainedRevisions.slice(0)[0];
beUpdatedRevision.patch = createPatch(
note.publicId,
oldRevisions.slice(-1)[0].content,
beUpdatedRevision.content,
);
await this.revisionRepository.save(beUpdatedRevision);
}
await this.revisionRepository.remove(oldRevisions);
this.logger.log(
`${oldRevisions.length} old revisions of the note '${note.id}' were removed from the DB`,
'removeOldRevisions',
);
}
}
}