Java后端
·2023-08-23提问 项目
BI智能平台,想用定时任务重新分析失败的分析任务,
大致思路:是把controller层的线程池异步调用ai的代码抽成一个方法,供接口和定时任务共用,定时任务每隔一段时间通过chartService获取失败任务列表并遍历,遍历中调用controller层的异步调用ai的方法。
现在出现问题,定时任务在调用controller的异步调用ai的方法时,会报错。
报错信息:java.lang.IllegalStateException: No thread-bound request found: Are you referring to request attributes outside of an actual web request, or processing a request outside of the originally receiving thread? If you are actually operating within a web request and still receive this message, your code is probably running outside of DispatcherServlet: In this case, use RequestContextListener or RequestContextFilter to expose the current request.
是什么原因照成的问题和如何解决,请大神指教!
==================定时任务代码=====================
@Component
public class FailedGenChartWrokSchedule {
private static ChartController chartController;
@Autowired
private void setChartController(ChartController chartController) {
FailedGenChartWrokSchedule.chartController = chartController;
}
@Resource
private ChartService chartService;
@Scheduled(fixedRate = 50000)
public void doFailedWrok(){
log.info("失败任务重启策略启动");
QueryWrapper<Chart> wrapper = new QueryWrapper<>();
wrapper.eq("status","failed");
List<Chart> chartList = chartService.list(wrapper);
try {
for (int i = 0; i < chartList.size(); i ) {
Chart chart = chartList.get(i);
StringBuffer userInput = format(chart);
chartController.invokeAI(userInput,chart);
log.info("失败任务id:" chart.getId() ",重启任务成功");
}
}catch (Exception e){
log.error("失败分析任务重试失败," e);
}
}
}
================controller部分代码===================
@RestController
@RequestMapping("/chart")
@Slf4j
public class ChartController {
/**
* 智能分析(异步)
*
* @param multipartFile
* @param genchartByAiRequest
* @param request
* @return
*/
@PostMapping("/gen")
public BaseResponse<BiResponse> genChartByAi(@RequestPart("file") MultipartFile multipartFile,
GenchartByAiRequest genchartByAiRequest, HttpServletRequest request) {
User loginUser = userService.getLoginUser(request);
//限流判断
redisLimiterManager.doRateLimit("genChartByAi_" loginUser.getId(),1);
String name = genchartByAiRequest.getName();
String goal = genchartByAiRequest.getGoal();
String chartType = genchartByAiRequest.getChartType();
//校验表单信息
ThrowUtils.throwIf(StringUtils.isBlank(goal), ErrorCode.PARAMS_ERROR, "目标为空");
ThrowUtils.throwIf(StringUtils.isNotBlank(name) && name.length() > 100, ErrorCode.PARAMS_ERROR, "名字过长");
//校验文件
String fileName = multipartFile.getOriginalFilename();
long fileSize = multipartFile.getSize();//单位:byte
final long ONE_MB = 1 * 1024 * 1024L;
if (fileSize>ONE_MB) {
throw new BusinessException(ErrorCode.PARAMS_ERROR,"数据文件不能超过1MB");
}
String suffix = FileUtil.getSuffix(fileName);
final List<String> validfileSuffixList = Arrays.asList("png","jpg","svg","webp","jpeg","xlsx");
if (!validfileSuffixList.contains(suffix)) {
throw new BusinessException(ErrorCode.PARAMS_ERROR,"文件后缀非法");
}
//Long biModelId = 1659171950288818178L;
//数据格式整理
StringBuffer userInput = new StringBuffer();
userInput.append("分析需求:").append("\n");
String userGoal = goal;
if (StringUtils.isNotBlank(chartType)) {
userGoal = ",请使用" chartType;
}
userInput.append(userGoal).append("\n");
userInput.append("原始数据:").append("\n");
//读取Excel文件转成csv格式
String excelToCsv = ExcelUntils.excelToCsv(multipartFile);
userInput.append(excelToCsv).append("\n");
//插入数据库
Chart chart = new Chart();
chart.setName(name);
chart.setGoal(goal);
chart.setChartType(chartType);
chart.setStatus(ChartStatusEnum.WAIT.getStatus());
chart.setChartData(excelToCsv);
chart.setUserId(loginUser.getId());
boolean save = chartService.save(chart);
ThrowUtils.throwIf(!save, ErrorCode.SYSTEM_ERROR, "图表保存失败");
//调用AI
invokeAI(userInput, chart);
BiResponse biResponse = new BiResponse();
biResponse.setChartId(chart.getId());
return ResultUtils.success(biResponse);
}
@Async("invokeAI")
public void invokeAI(StringBuffer userInput, Chart chart) {
//异步调用ai
try {
CompletableFuture.runAsync(()->{
//把chart状态改为执行中,running
Chart updateChartResult = new Chart();
Long chartId = chart.getId();
updateChartResult.setId(chartId);
updateChartResult.setStatus(ChartStatusEnum.RUNNING.getStatus());
boolean result = chartService.updateById(updateChartResult);
if (!result) {
handleChartUpdateError(chartId,"更新图表执行中状态失败");
return;
}
//调用ai
DevChatResponse answer = aiManager.doChat(biModelId, userInput.toString());
String[] split = answer.getContent().split("【【【【【");
if (split.length < 3){
handleChartUpdateError(chartId,"AI生成失败");
return;
}
String chartCode = split[1];
String analyzeResult = split[2];
updateChartResult.setGenChart(chartCode);
updateChartResult.setGenResult(analyzeResult);
updateChartResult.setStatus(ChartStatusEnum.SUCCEED.getStatus());
boolean updateResult = chartService.updateById(updateChartResult);
if (!updateResult) {
handleChartUpdateError(chartId,"更新图表成功状态失败");
return;
}
},threadPoolExecutor);
} catch (RejectedExecutionException e) {
throw new BusinessException(ErrorCode.SYSTEM_ERROR,"系统繁忙,请稍后再试");
}catch (Exception e){
throw new BusinessException(ErrorCode.SYSTEM_ERROR);
}
}
private void handleChartUpdateError(long chartId,String execMessage){
Chart updateChartResult = new Chart();
updateChartResult.setId(chartId);
updateChartResult.setStatus(ChartStatusEnum.FAILED.getStatus());
updateChartResult.setExecMessage(execMessage);
boolean result = chartService.updateById(updateChartResult);
if (!result) {
log.error("更新图表失败状态失败" chartId "," execMessage);
}
}
}
=================原因及解决办法===============
原因:项目中带的AuthInterceptor拦截器中调用RequestContextHolder.currentRequestAttributes();
,定时任务没有RequestAttributes对象,所以异常了。
解决办法:在AuthInterceptor中的RequestContextHolder.currentRequestAttributes();时捕捉异常。
参考代码:
public Object doInterceptor(ProceedingJoinPoint point) throws Throwable {
// 计时
StopWatch stopWatch = new StopWatch();
stopWatch.start();
// 获取请求路径
RequestAttributes requestAttributes = getRequestAttributesSafely();
// 生成请求唯一 id
String requestId = UUID.randomUUID().toString();
String url = "";
String remoteHost = "";
if (requestAttributes != null) {
HttpServletRequest httpServletRequest = ((ServletRequestAttributes) requestAttributes).getRequest();
url = httpServletRequest.getRequestURI();
remoteHost = httpServletRequest.getRemoteHost();
}
// 获取请求参数
Object[] args = point.getArgs();
String reqParam = "[" StringUtils.join(args, ", ") "]";
// 输出请求日志
log.info("request start,id: {}, path: {}, ip: {}, params: {}", requestId, url,
remoteHost, reqParam);
// 执行原方法
Object result = point.proceed();
// 输出响应日志
stopWatch.stop();
long totalTimeMillis = stopWatch.getTotalTimeMillis();
log.info("request end, id: {}, cost: {}ms", requestId, totalTimeMillis);
return result;
}
private RequestAttributes getRequestAttributesSafely() {
RequestAttributes requestAttributes = null;
try {
requestAttributes = RequestContextHolder.currentRequestAttributes();
} catch (IllegalStateException e) {
log.warn("未能获取到requestAttributes,本地调用");
}
return requestAttributes;
}
11
0
分享
操作
评论
问答助学
相关内容
0个评论
全部评论
点击登录,快来和大家讨论吧~
表情
图片
暂无评论
