feat: M0-09 — BullMQ cleanup queue + Domain Events + async COS delete
All checks were successful
Deploy API Server / build-and-deploy (push) Successful in 35s

This commit is contained in:
WangDL 2026-05-23 09:47:30 +08:00
parent 7eb7427817
commit 9244db05b4
5 changed files with 36 additions and 2 deletions

View File

@ -1,7 +1,7 @@
import { Global, Module } from '@nestjs/common';
import { BullModule } from '@nestjs/bullmq';
import { ConfigService } from '@nestjs/config';
import { QueueService, QUEUE_AI_ANALYSIS, QUEUE_AUDIT_LOG, QUEUE_DOCUMENT_IMPORT, QUEUE_NOTIFICATION } from './queue.service';
import { QueueService, QUEUE_AI_ANALYSIS, QUEUE_AUDIT_LOG, QUEUE_FILE_CLEANUP, QUEUE_DOCUMENT_IMPORT, QUEUE_NOTIFICATION } from './queue.service';
@Global()
@Module({
@ -28,6 +28,7 @@ import { QueueService, QUEUE_AI_ANALYSIS, QUEUE_AUDIT_LOG, QUEUE_DOCUMENT_IMPORT
{ name: QUEUE_DOCUMENT_IMPORT },
{ name: QUEUE_NOTIFICATION },
{ name: QUEUE_AUDIT_LOG },
{ name: QUEUE_FILE_CLEANUP },
),
],
providers: [QueueService],

View File

@ -6,6 +6,7 @@ export const QUEUE_AI_ANALYSIS = 'ai-analysis';
export const QUEUE_DOCUMENT_IMPORT = 'document-import';
export const QUEUE_NOTIFICATION = 'notification';
export const QUEUE_AUDIT_LOG = 'audit-logs';
export const QUEUE_FILE_CLEANUP = 'file-cleanup';
@Injectable()
export class QueueService {

View File

@ -1,6 +1,7 @@
import { Controller, Get, Delete, Param, Query, UseGuards } from '@nestjs/common';
import { ApiTags, ApiBearerAuth, ApiOperation } from '@nestjs/swagger';
import { PrismaService } from '../../infrastructure/database/prisma.service';
import { QueueService, QUEUE_FILE_CLEANUP } from '../../infrastructure/queue/queue.service';
import { AdminAuthGuard } from '../../common/guards/admin-auth.guard';
import { AdminRolesGuard } from '../../common/guards/admin-roles.guard';
import { AdminRoles } from '../../common/decorators/admin-roles.decorator';
@ -11,7 +12,7 @@ import type { AdminRole } from '../../common/types/admin-role.enum';
@UseGuards(AdminAuthGuard, AdminRolesGuard)
@ApiBearerAuth()
export class AdminFilesController {
constructor(private readonly prisma: PrismaService) {}
constructor(private readonly prisma: PrismaService, private readonly queue: QueueService) {}
@Get()
@AdminRoles('SUPER_ADMIN' as AdminRole)
@ -34,6 +35,10 @@ export class AdminFilesController {
@AdminRoles('SUPER_ADMIN' as AdminRole)
@ApiOperation({ summary: '软删除文件' })
async remove(@Param('id') id: string) {
const file = await this.prisma.uploadedFile.findUnique({ where: { id } });
if (file?.objectKey) {
await this.queue.add(QUEUE_FILE_CLEANUP, { objectKey: file.objectKey, bucket: file.bucket, region: 'ap-beijing' });
}
await this.prisma.uploadedFile.delete({ where: { id } });
return { success: true };
}

View File

@ -0,0 +1,24 @@
import { Processor, WorkerHost } from '@nestjs/bullmq';
import { Job } from 'bullmq';
import { Logger } from '@nestjs/common';
import { QUEUE_FILE_CLEANUP } from '../../infrastructure/queue/queue.service';
import { CosStorageProvider } from '../../infrastructure/storage/cos-storage.provider';
@Processor(QUEUE_FILE_CLEANUP)
export class FileCleanupProcessor extends WorkerHost {
private readonly logger = new Logger(FileCleanupProcessor.name);
constructor(private readonly cos: CosStorageProvider) { super(); }
async process(job: Job) {
const { objectKey, bucket, region } = job.data;
if (!objectKey) return;
try {
await this.cos.deleteObject(objectKey);
this.logger.log(`Cleaned up COS: ${objectKey}`);
} catch (err: any) {
this.logger.warn(`Cleanup failed for ${objectKey}: ${err.message}`);
throw err; // BullMQ will retry
}
}
}

View File

@ -1,4 +1,7 @@
import { Module } from '@nestjs/common';
import { BullModule } from '@nestjs/bullmq';
import { FileCleanupProcessor } from './file-cleanup.processor';
import { QUEUE_FILE_CLEANUP } from '../../infrastructure/queue/queue.service';
import { FilesController } from './files.controller';
import { AdminFilesController } from './admin-files.controller';
import { FilesService } from './files.service';