从入门到放弃
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; }
0个评论
点击登录,快来和大家讨论吧~
表情
图片
暂无评论
下载 APP