From bb0ee28486c127c2065f93bcc8e82157a3c56e76 Mon Sep 17 00:00:00 2001 From: Diogo Correia Date: Tue, 2 Dec 2025 22:57:01 +0000 Subject: [PATCH] feat: cleanup old download requests --- server/src/enum.ts | 2 ++ .../src/repositories/download-request.repository.ts | 13 ++++++++++++- server/src/services/download.service.ts | 12 +++++++++++- server/src/services/queue.service.ts | 1 + server/src/types.ts | 1 + 5 files changed, 27 insertions(+), 2 deletions(-) diff --git a/server/src/enum.ts b/server/src/enum.ts index d397f9d2ae..b0a40ebb25 100644 --- a/server/src/enum.ts +++ b/server/src/enum.ts @@ -564,6 +564,8 @@ export enum JobName { DatabaseBackup = 'DatabaseBackup', + DownloadRequestCleanup = 'DownloadRequestCleanup', + FacialRecognitionQueueAll = 'FacialRecognitionQueueAll', FacialRecognition = 'FacialRecognition', diff --git a/server/src/repositories/download-request.repository.ts b/server/src/repositories/download-request.repository.ts index d08ac81a86..26b23a9fde 100644 --- a/server/src/repositories/download-request.repository.ts +++ b/server/src/repositories/download-request.repository.ts @@ -1,6 +1,7 @@ import { Injectable } from '@nestjs/common'; import { Insertable, Kysely, sql } from 'kysely'; import _ from 'lodash'; +import { DateTime } from 'luxon'; import { InjectKysely } from 'nestjs-kysely'; import { DummyValue, GenerateSql } from 'src/decorators'; import { DB } from 'src/schema'; @@ -10,12 +11,22 @@ import { DownloadRequestTable } from 'src/schema/tables/download-request.table'; export class DownloadRequestRepository { constructor(@InjectKysely() private db: Kysely) {} + cleanup() { + return this.db + .deleteFrom('download_request') + .where('download_request.expiresAt', '<=', DateTime.now().toJSDate()) + .returning(['id']) + .execute(); + } + @GenerateSql({ params: [DummyValue.UUID] }) get(id: string) { return this.db .selectFrom('download_request') .selectAll('download_request') - .where('download_request.id', '=', id) + .where((eb) => + eb.and([eb('download_request.id', '=', id), eb('download_request.expiresAt', '>', DateTime.now().toJSDate())]), + ) .leftJoin('download_request_asset', 'download_request_asset.downloadRequestId', 'download_request.id') .select((eb) => eb.fn diff --git a/server/src/services/download.service.ts b/server/src/services/download.service.ts index 185f242594..e7639cfd20 100644 --- a/server/src/services/download.service.ts +++ b/server/src/services/download.service.ts @@ -2,6 +2,7 @@ import { BadRequestException, Injectable } from '@nestjs/common'; import { DateTime } from 'luxon'; import { parse } from 'node:path'; import { StorageCore } from 'src/cores/storage.core'; +import { OnJob } from 'src/decorators'; import { AssetIdsDto } from 'src/dtos/asset.dto'; import { AuthDto } from 'src/dtos/auth.dto'; import { @@ -10,7 +11,7 @@ import { DownloadResponseDto, PrepareDownloadResponseDto, } from 'src/dtos/download.dto'; -import { Permission } from 'src/enum'; +import { JobName, JobStatus, Permission, QueueName } from 'src/enum'; import { ImmichReadStream } from 'src/repositories/storage.repository'; import { BaseService } from 'src/services/base.service'; import { HumanReadableSize } from 'src/utils/bytes'; @@ -18,6 +19,15 @@ import { getPreferences } from 'src/utils/preferences'; @Injectable() export class DownloadService extends BaseService { + @OnJob({ name: JobName.DownloadRequestCleanup, queue: QueueName.BackgroundTask }) + async handleDownloadRequestCleanup(): Promise { + const requests = await this.downloadRequestRepository.cleanup(); + + this.logger.log(`Deleted ${requests.length} expired download requests`); + + return JobStatus.Success; + } + async getDownloadInfo(auth: AuthDto, dto: DownloadInfoDto): Promise { let assets; diff --git a/server/src/services/queue.service.ts b/server/src/services/queue.service.ts index bea665e8fd..c6eec0a401 100644 --- a/server/src/services/queue.service.ts +++ b/server/src/services/queue.service.ts @@ -226,6 +226,7 @@ export class QueueService extends BaseService { { name: JobName.SessionCleanup }, { name: JobName.AuditTableCleanup }, { name: JobName.AuditLogCleanup }, + { name: JobName.DownloadRequestCleanup }, ); } diff --git a/server/src/types.ts b/server/src/types.ts index dd3d25a7cb..4ef8e8ea3b 100644 --- a/server/src/types.ts +++ b/server/src/types.ts @@ -362,6 +362,7 @@ export type JobItem = // Cleanup | { name: JobName.AuditLogCleanup; data?: IBaseJob } + | { name: JobName.DownloadRequestCleanup; data?: IBaseJob } | { name: JobName.SessionCleanup; data?: IBaseJob } // Tags