Add scheduled deletion for cached PDF files

This commit is contained in:
Krisjanis Lejejs
2022-10-25 21:10:40 +03:00
parent 78a32961d7
commit 43ddfba777
4 changed files with 43 additions and 12 deletions

View File

@ -34,6 +34,7 @@ STORAGE_ENDPOINT=
STORAGE_URL_PREFIX=
STORAGE_ACCESS_KEY=
STORAGE_SECRET_KEY=
PDF_DELETION_TIME=
# Flags (Client)
PUBLIC_FLAG_DISABLE_SIGNUPS=false

View File

@ -0,0 +1,5 @@
import { registerAs } from '@nestjs/config';
export default registerAs('cache', () => ({
pdfDeletionTime: parseInt(process.env.PDF_DELETION_TIME, 10),
}));

View File

@ -4,6 +4,7 @@ import Joi from 'joi';
import appConfig from './app.config';
import authConfig from './auth.config';
import cacheConfig from './cache.config';
import databaseConfig from './database.config';
import googleConfig from './google.config';
import mailConfig from './mail.config';
@ -52,12 +53,15 @@ const validationSchema = Joi.object({
STORAGE_URL_PREFIX: Joi.string().allow(''),
STORAGE_ACCESS_KEY: Joi.string().allow(''),
STORAGE_SECRET_KEY: Joi.string().allow(''),
// Cache
PDF_DELETION_TIME: Joi.number().default(6 * 24 * 60 * 60 * 1000), // 6 days
});
@Module({
imports: [
NestConfigModule.forRoot({
load: [appConfig, authConfig, databaseConfig, googleConfig, mailConfig, storageConfig],
load: [appConfig, authConfig, cacheConfig, databaseConfig, googleConfig, mailConfig, storageConfig],
validationSchema: validationSchema,
}),
],

View File

@ -1,18 +1,17 @@
import { Injectable, OnModuleDestroy, OnModuleInit } from '@nestjs/common';
import { ConfigService } from '@nestjs/config';
import { SchedulerRegistry } from '@nestjs/schedule';
import { PageConfig } from '@reactive-resume/schema';
import { access, mkdir, readdir, unlink, writeFile } from 'fs/promises';
import { join } from 'path';
import { PDFDocument } from 'pdf-lib';
import { Browser, chromium } from 'playwright-chromium';
export const DELETION_TIME = 10 * 1000; // 10 seconds
@Injectable()
export class PrinterService implements OnModuleInit, OnModuleDestroy {
private browser: Browser;
constructor(private readonly configService: ConfigService) {}
constructor(private readonly schedulerRegistry: SchedulerRegistry, private readonly configService: ConfigService) {}
async onModuleInit() {
this.browser = await chromium.launch({
@ -31,20 +30,29 @@ export class PrinterService implements OnModuleInit, OnModuleDestroy {
const filename = `RxResume_PDFExport_${username}_${slug}_${lastUpdated}.pdf`;
const publicUrl = `${serverUrl}/assets/exports/${filename}`;
try { // check if file already exists
try {
// check if file already exists
await access(join(directory, filename));
} catch { // create file as it doesn't exist
// delete old files
} catch {
// delete old files and scheduler jobs
const activeSchedulerTimeouts = this.schedulerRegistry.getTimeouts();
await readdir(directory).then(async (files) => {
await Promise.all(files.map(async (file) => {
if (file.startsWith(`RxResume_PDFExport_${username}_${slug}`)) {
await unlink(join(directory, file));
}
}));
await Promise.all(
files.map(async (file) => {
if (file.startsWith(`RxResume_PDFExport_${username}_${slug}`)) {
await unlink(join(directory, file));
if (activeSchedulerTimeouts[`delete-${file}`]) {
this.schedulerRegistry.deleteTimeout(`delete-${file}`);
}
}
})
);
});
// create file as it doesn't exist
const url = this.configService.get<string>('app.url');
const secretKey = this.configService.get<string>('app.secretKey');
const pdfDeletionTime = this.configService.get<number>('cache.pdfDeletionTime');
const page = await this.browser.newPage();
@ -87,6 +95,19 @@ export class PrinterService implements OnModuleInit, OnModuleDestroy {
await mkdir(directory, { recursive: true });
await writeFile(join(directory, filename), pdfBytes);
// Delete PDF artifacts after pdfDeletionTime ms
const timeout = setTimeout(async () => {
try {
await unlink(join(directory, filename));
this.schedulerRegistry.deleteTimeout(`delete-${filename}`);
} catch {
// pass through
}
}, pdfDeletionTime);
this.schedulerRegistry.addTimeout(`delete-${filename}`, timeout);
}
return publicUrl;