6.3 KiB
用户导入504超时错误修复说明
问题描述
在导入用户档案数据时,出现 504 Gateway Time-out 错误。这是因为:
- 数据量较大,导入处理时间超过了网关(Nginx)的超时限制
- 同步处理导致HTTP请求长时间等待响应
修复方案
采用异步导入方式,将耗时的导入操作放到后台线程执行,HTTP请求立即返回,通过进度轮询查看导入状态。
修改内容
1. Controller层修改 ✅
文件: ry-xinli-admin/src/main/java/com/ddnai/web/controller/psychology/PsyUserProfileController.java
修改内容:
- 修改
importData方法,调用异步导入方法importProfileAsync - 立即返回响应,告知前端导入任务已启动
- 前端通过
/importProgress接口轮询获取进度
@PostMapping("/importData")
public AjaxResult importData(MultipartFile file, boolean updateSupport) throws Exception
{
ExcelUtil<PsyUserProfile> util = new ExcelUtil<PsyUserProfile>(PsyUserProfile.class);
List<PsyUserProfile> profileList = util.importExcel(file.getInputStream());
String operName = getUsername();
// 异步执行导入任务,立即返回
profileService.importProfileAsync(profileList, updateSupport, operName);
// 立即返回响应,告知前端导入任务已启动
return success("导入任务已启动,共 " + profileList.size() + " 条数据。请稍候查看导入进度...");
}
2. Service接口层修改 ✅
文件: ry-xinli-system/src/main/java/com/ddnai/system/service/psychology/IPsyUserProfileService.java
修改内容:
- 添加异步导入方法接口
importProfileAsync
/**
* 异步导入用户档案数据(避免超时)
*/
public void importProfileAsync(List<PsyUserProfile> profileList, Boolean isUpdateSupport, String operName);
3. Service实现层修改 ✅
文件: ry-xinli-system/src/main/java/com/ddnai/system/service/impl/psychology/PsyUserProfileServiceImpl.java
修改内容:
- 添加
@Async注解导入 - 实现异步导入方法,使用
@Async注解标记
import org.springframework.scheduling.annotation.Async;
@Override
@Async
public void importProfileAsync(List<PsyUserProfile> profileList, Boolean isUpdateSupport, String operName)
{
try
{
log.info("异步导入任务开始,操作人:{},数据量:{}", operName, profileList.size());
// 调用同步导入方法执行实际导入逻辑
importProfile(profileList, isUpdateSupport, operName);
log.info("异步导入任务完成,操作人:{}", operName);
}
catch (Exception e)
{
log.error("异步导入任务失败,操作人:{},错误:{}", operName, e.getMessage(), e);
}
}
4. 启动类修改 ✅
文件: ry-xinli-admin/src/main/java/com/ddnai/XinliApplication.java
修改内容:
- 添加
@EnableAsync注解启用异步支持 - 配置异步任务线程池
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import java.util.concurrent.Executor;
@SpringBootApplication(exclude = { DataSourceAutoConfiguration.class })
@EnableAsync
public class XinliApplication
{
@Bean(name = "taskExecutor")
public Executor taskExecutor()
{
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(5); // 核心线程数
executor.setMaxPoolSize(10); // 最大线程数
executor.setQueueCapacity(100); // 队列容量
executor.setThreadNamePrefix("async-import-");
executor.setWaitForTasksToCompleteOnShutdown(true);
executor.setAwaitTerminationSeconds(60);
executor.initialize();
return executor;
}
}
5. 配置文件修改 ✅
文件: ry-xinli-admin/src/main/resources/application.yml
修改内容:
- 增加MVC异步请求超时配置(作为保险)
spring:
mvc:
async:
# 异步请求超时时间(毫秒),设置为10分钟
request-timeout: 600000
工作原理
- 文件上传: 用户上传Excel文件
- 解析数据: Controller解析Excel文件为对象列表
- 启动异步任务: 调用
importProfileAsync方法,Spring会在独立线程中执行 - 立即返回: HTTP请求立即返回成功响应
- 进度管理: 后台线程执行导入,通过
ImportProgressManager记录进度 - 前端轮询: 前端通过
/importProgress接口定期查询导入进度 - 完成通知: 导入完成后,前端获取到最终结果并显示
优势
✅ 避免超时: HTTP请求立即返回,不会因导入时间长而超时
✅ 用户体验好: 前端实时显示导入进度
✅ 不阻塞服务器: 导入任务在独立线程池中执行
✅ 支持大批量: 可以处理大量数据而不影响其他请求
✅ 向后兼容: 保留了同步导入方法,不影响其他功能
注意事项
⚠️ 重启应用: 修改完成后需要重启Spring Boot应用才能生效
⚠️ 数据库连接: 异步线程需要数据库连接,确保连接池配置足够
⚠️ 事务管理: 异步方法中的事务与主线程独立,需注意事务边界
⚠️ 线程池监控: 生产环境建议监控线程池状态,避免资源耗尽
如何测试
- 重启Spring Boot应用
- 准备一个包含较多数据的Excel文件(建议500+条)
- 在用户档案管理页面点击"导入"
- 上传文件后,应该立即收到"导入任务已启动"的提示
- 观察进度条实时更新
- 等待导入完成,查看结果统计
进一步优化建议(可选)
如果仍然遇到问题,可以考虑:
-
增加Nginx超时配置 (如果使用了Nginx反向代理):
proxy_connect_timeout 600s; proxy_send_timeout 600s; proxy_read_timeout 600s; -
优化批量插入性能:
- 已实现分批处理(每批500条)
- 可以根据实际情况调整批次大小
-
数据库优化:
- 确保相关字段有索引
- 检查批量插入SQL性能
修复完成日期: 2025-12-01
修复人员: Cascade AI
影响范围: 用户档案导入功能
风险评估: 低(仅改变执行方式,核心逻辑未变)