Resume 简历管理模块设计与实现
本文记录 interview-guide 项目中 Resume 模块的核心设计、接口职责、异步处理链路与当前问题。
模块能力概览
- 多格式解析:支持
PDF、DOCX、DOC、TXT、MD。 - 异步处理流:基于
Redis Stream异步分析简历,支持进度状态跟踪。 - 稳定性保障:失败自动重试(最多 3 次)+ 基于文件哈希的重复检测。
- 报告导出:支持将 AI 分析结果导出为结构化 PDF 报告。
核心状态流转
关键接口设计
/api/resumes/upload 简历上传(异步分析)
限流策略:
- 全局限流:
@RateLimit(dimension = RateLimit.Dimension.GLOBAL, count = 5) - IP 限流:
@RateLimit(dimension = RateLimit.Dimension.IP, count = 5)
入口调用:
uploadService.uploadAndAnalyze(file);
处理流程:
- 文件基础校验
fileValidationService.validateFile(file, MAX_FILE_SIZE, "简历");
包含:判空、大小限制、日志记录。 2. 文件类型识别
String contentType = parseService.detectContentType(file);
支持:PDF、DOCX、DOC、TXT、MD。
3. 重复文件检测
persistenceService.findExistingResume(file);
内部流程:
String fileHash = fileHashService.calculateHash(file);
resumeRepository.findByFileHash(fileHash);
- 简历解析与文本清洗
parseService.parseResume(file);
Apache Tika解析纯文本textCleaningService.cleanText(content)清理多余换行,减少 Token 消耗
- 文件存储(非结构化)
storageService.uploadResume(file);
storageService.getFileUrl(fileKey);
上传到 RustFS/MinIO,用于非结构化文件存储。
6. 元数据入库
persistenceService.saveResume(file, resumeText, fileKey, fileUrl);
- 投递异步分析任务
analyzeStreamProducer.sendAnalyzeTask(savedResume.getId(), resumeText);
使用 Redis Stream 作为消息队列
8. 返回上传响应
前端通过后续查询接口观察异步分析状态。
/api/resumes 获取简历列表
调用链:
historyService.getAllResumes();
resumePersistenceService.findAllResumes();
当前问题:
- 尚未区分用户数据,默认返回全量列表。
/api/resumes/{id}/detail 获取简历详情
调用链:
historyService.getResumeDetail(id);
resumePersistenceService.findById(id);
resumeRepository.findById(id);
/api/resumes/{id}/export 导出分析报告 PDF
调用链:
historyService.exportAnalysisPdf(id);
resumePersistenceService.findById(resumeId);
resumePersistenceService.getLatestAnalysisAsDTO(resumeId);
pdfExportService.exportResumeAnalysis(resume, analysisDTO);
/api/resumes/{id} 删除简历
调用链:
deleteService.deleteResume(id);
persistenceService.findById(id);
storageService.deleteResume(resume.getStorageKey());
interviewPersistenceService.deleteSessionsByResumeId(id);
persistenceService.deleteResume(id);
/api/resumes/{id}/reanalyze 重新分析
限流策略:
- 全局限流:
@RateLimit(dimension = RateLimit.Dimension.GLOBAL, count = 2) - IP 限流:
@RateLimit(dimension = RateLimit.Dimension.IP, count = 2)
调用链:
uploadService.reanalyze(id);
resumeRepository.findById(resumeId);
analyzeStreamProducer.sendAnalyzeTask(resumeId, resumeText);
并在处理中更新状态后保存。
/api/resumes/health 健康检查
return Result.success();
用于服务可用性探测。
稳定性设计点
- 异步解耦:上传与分析分离,削峰并提升接口响应速度。
- 自动重试:分析失败后最多重试 3 次,降低瞬时故障影响。
- 哈希去重:基于内容
SHA-256快速识别重复简历,避免重复计算。
小结
Resume 模块目前已经具备上传、解析、异步分析、导出与删除的完整闭环。下一阶段重点是用户隔离与可观测性建设,确保在多人使用和高并发场景下依旧稳定可控。