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
All checks were successful
Deploy API Server / build-and-deploy (push) Successful in 35s
This commit is contained in:
parent
7eb7427817
commit
9244db05b4
@ -1,7 +1,7 @@
|
|||||||
import { Global, Module } from '@nestjs/common';
|
import { Global, Module } from '@nestjs/common';
|
||||||
import { BullModule } from '@nestjs/bullmq';
|
import { BullModule } from '@nestjs/bullmq';
|
||||||
import { ConfigService } from '@nestjs/config';
|
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()
|
@Global()
|
||||||
@Module({
|
@Module({
|
||||||
@ -28,6 +28,7 @@ import { QueueService, QUEUE_AI_ANALYSIS, QUEUE_AUDIT_LOG, QUEUE_DOCUMENT_IMPORT
|
|||||||
{ name: QUEUE_DOCUMENT_IMPORT },
|
{ name: QUEUE_DOCUMENT_IMPORT },
|
||||||
{ name: QUEUE_NOTIFICATION },
|
{ name: QUEUE_NOTIFICATION },
|
||||||
{ name: QUEUE_AUDIT_LOG },
|
{ name: QUEUE_AUDIT_LOG },
|
||||||
|
{ name: QUEUE_FILE_CLEANUP },
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
providers: [QueueService],
|
providers: [QueueService],
|
||||||
|
|||||||
@ -6,6 +6,7 @@ export const QUEUE_AI_ANALYSIS = 'ai-analysis';
|
|||||||
export const QUEUE_DOCUMENT_IMPORT = 'document-import';
|
export const QUEUE_DOCUMENT_IMPORT = 'document-import';
|
||||||
export const QUEUE_NOTIFICATION = 'notification';
|
export const QUEUE_NOTIFICATION = 'notification';
|
||||||
export const QUEUE_AUDIT_LOG = 'audit-logs';
|
export const QUEUE_AUDIT_LOG = 'audit-logs';
|
||||||
|
export const QUEUE_FILE_CLEANUP = 'file-cleanup';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class QueueService {
|
export class QueueService {
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
import { Controller, Get, Delete, Param, Query, UseGuards } from '@nestjs/common';
|
import { Controller, Get, Delete, Param, Query, UseGuards } from '@nestjs/common';
|
||||||
import { ApiTags, ApiBearerAuth, ApiOperation } from '@nestjs/swagger';
|
import { ApiTags, ApiBearerAuth, ApiOperation } from '@nestjs/swagger';
|
||||||
import { PrismaService } from '../../infrastructure/database/prisma.service';
|
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 { AdminAuthGuard } from '../../common/guards/admin-auth.guard';
|
||||||
import { AdminRolesGuard } from '../../common/guards/admin-roles.guard';
|
import { AdminRolesGuard } from '../../common/guards/admin-roles.guard';
|
||||||
import { AdminRoles } from '../../common/decorators/admin-roles.decorator';
|
import { AdminRoles } from '../../common/decorators/admin-roles.decorator';
|
||||||
@ -11,7 +12,7 @@ import type { AdminRole } from '../../common/types/admin-role.enum';
|
|||||||
@UseGuards(AdminAuthGuard, AdminRolesGuard)
|
@UseGuards(AdminAuthGuard, AdminRolesGuard)
|
||||||
@ApiBearerAuth()
|
@ApiBearerAuth()
|
||||||
export class AdminFilesController {
|
export class AdminFilesController {
|
||||||
constructor(private readonly prisma: PrismaService) {}
|
constructor(private readonly prisma: PrismaService, private readonly queue: QueueService) {}
|
||||||
|
|
||||||
@Get()
|
@Get()
|
||||||
@AdminRoles('SUPER_ADMIN' as AdminRole)
|
@AdminRoles('SUPER_ADMIN' as AdminRole)
|
||||||
@ -34,6 +35,10 @@ export class AdminFilesController {
|
|||||||
@AdminRoles('SUPER_ADMIN' as AdminRole)
|
@AdminRoles('SUPER_ADMIN' as AdminRole)
|
||||||
@ApiOperation({ summary: '软删除文件' })
|
@ApiOperation({ summary: '软删除文件' })
|
||||||
async remove(@Param('id') id: string) {
|
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 } });
|
await this.prisma.uploadedFile.delete({ where: { id } });
|
||||||
return { success: true };
|
return { success: true };
|
||||||
}
|
}
|
||||||
|
|||||||
24
src/modules/files/file-cleanup.processor.ts
Normal file
24
src/modules/files/file-cleanup.processor.ts
Normal 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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,4 +1,7 @@
|
|||||||
import { Module } from '@nestjs/common';
|
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 { FilesController } from './files.controller';
|
||||||
import { AdminFilesController } from './admin-files.controller';
|
import { AdminFilesController } from './admin-files.controller';
|
||||||
import { FilesService } from './files.service';
|
import { FilesService } from './files.service';
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user