解决接口响应超时
This commit is contained in:
parent
4abfc570a0
commit
4a6cca7373
|
@ -3,6 +3,8 @@ package com.greenorange.promotion;
|
||||||
import org.mybatis.spring.annotation.MapperScan;
|
import org.mybatis.spring.annotation.MapperScan;
|
||||||
import org.springframework.boot.SpringApplication;
|
import org.springframework.boot.SpringApplication;
|
||||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||||
|
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||||
|
import org.springframework.scheduling.annotation.EnableAsync;
|
||||||
|
|
||||||
@SpringBootApplication
|
@SpringBootApplication
|
||||||
@MapperScan("com.greenorange.promotion.mapper")
|
@MapperScan("com.greenorange.promotion.mapper")
|
||||||
|
|
|
@ -0,0 +1,12 @@
|
||||||
|
package com.greenorange.promotion.annotation;
|
||||||
|
|
||||||
|
import java.lang.annotation.ElementType;
|
||||||
|
import java.lang.annotation.Retention;
|
||||||
|
import java.lang.annotation.RetentionPolicy;
|
||||||
|
import java.lang.annotation.Target;
|
||||||
|
|
||||||
|
@Target(ElementType.METHOD) // 只用于方法
|
||||||
|
@Retention(RetentionPolicy.RUNTIME) // 运行时可用
|
||||||
|
public @interface Timeout {
|
||||||
|
long value(); // 超时时间,单位:毫秒
|
||||||
|
}
|
|
@ -0,0 +1,54 @@
|
||||||
|
package com.greenorange.promotion.aop;
|
||||||
|
|
||||||
|
import com.greenorange.promotion.annotation.Timeout;
|
||||||
|
import com.greenorange.promotion.common.ErrorCode;
|
||||||
|
import com.greenorange.promotion.exception.BusinessException;
|
||||||
|
import com.greenorange.promotion.exception.ThrowUtils;
|
||||||
|
import org.aspectj.lang.annotation.Aspect;
|
||||||
|
import org.aspectj.lang.annotation.Before;
|
||||||
|
import org.aspectj.lang.annotation.Pointcut;
|
||||||
|
import org.aspectj.lang.annotation.Around;
|
||||||
|
import org.aspectj.lang.ProceedingJoinPoint;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import java.util.concurrent.*;
|
||||||
|
|
||||||
|
@Aspect
|
||||||
|
@Component
|
||||||
|
public class TimeoutAspect {
|
||||||
|
|
||||||
|
|
||||||
|
private final ExecutorService executorService;
|
||||||
|
|
||||||
|
// 构造器注入线程池
|
||||||
|
@Autowired
|
||||||
|
public TimeoutAspect(ExecutorService executorService) {
|
||||||
|
this.executorService = executorService;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Around("@annotation(timeout)")
|
||||||
|
public Object handleTimeout(ProceedingJoinPoint joinPoint, Timeout timeout) throws Throwable {
|
||||||
|
long timeoutMillis = timeout.value(); // 获取超时时间
|
||||||
|
|
||||||
|
// 创建一个线程池来执行任务
|
||||||
|
Callable<Object> task = () -> {
|
||||||
|
try {
|
||||||
|
// 执行目标方法
|
||||||
|
return joinPoint.proceed();
|
||||||
|
} catch (Throwable e) {
|
||||||
|
throw new BusinessException(ErrorCode.OPERATION_ERROR, e.getMessage());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Future<Object> future = executorService.submit(task); // 提交任务
|
||||||
|
|
||||||
|
try {
|
||||||
|
// 在规定时间内等待任务完成
|
||||||
|
return future.get(timeoutMillis, TimeUnit.MILLISECONDS);
|
||||||
|
} catch (TimeoutException e) {
|
||||||
|
// 超时后抛出自定义异常
|
||||||
|
throw new BusinessException(ErrorCode.TIMEOUT_ERROR, "请求超时,超过最大允许时间 " + timeoutMillis + " 毫秒");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -14,7 +14,8 @@ public enum ErrorCode {
|
||||||
SYSTEM_ERROR(50000,"系统内部异常"),
|
SYSTEM_ERROR(50000,"系统内部异常"),
|
||||||
OPERATION_ERROR(50001,"操作失败"),
|
OPERATION_ERROR(50001,"操作失败"),
|
||||||
DATABASE_ERROR(50002, "数据库内部异常"),
|
DATABASE_ERROR(50002, "数据库内部异常"),
|
||||||
LOGIN_ERROR(40110,"登陆状态变更");
|
LOGIN_ERROR(40110,"登陆状态变更"),
|
||||||
|
TIMEOUT_ERROR(40800, "请求超时");
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 状态码
|
* 状态码
|
||||||
|
|
|
@ -0,0 +1,44 @@
|
||||||
|
package com.greenorange.promotion.config;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import java.util.concurrent.ExecutorService;
|
||||||
|
import java.util.concurrent.LinkedBlockingQueue;
|
||||||
|
import java.util.concurrent.ThreadPoolExecutor;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@Configuration
|
||||||
|
@ConfigurationProperties(prefix = "threadpool")
|
||||||
|
public class ThreadPoolConfig {
|
||||||
|
|
||||||
|
// 从配置文件中读取线程池的配置参数
|
||||||
|
private int corePoolSize; // 核心线程数
|
||||||
|
|
||||||
|
private int maxPoolSize; // 最大线程数
|
||||||
|
|
||||||
|
private int queueCapacity; // 队列容量
|
||||||
|
|
||||||
|
private long keepAliveTime; // 线程空闲时间,单位秒
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 配置线程池
|
||||||
|
* @return 线程池实例
|
||||||
|
*/
|
||||||
|
@Bean
|
||||||
|
public ExecutorService threadPoolExecutor() {
|
||||||
|
return new ThreadPoolExecutor(
|
||||||
|
corePoolSize, // 核心线程数
|
||||||
|
maxPoolSize, // 最大线程数
|
||||||
|
keepAliveTime, // 空闲线程存活时间
|
||||||
|
TimeUnit.SECONDS, // 空闲时间单位
|
||||||
|
new LinkedBlockingQueue<>(queueCapacity), // 任务队列,设置队列大小
|
||||||
|
new ThreadPoolExecutor.CallerRunsPolicy() // 拒绝策略:调用者运行
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
|
@ -6,10 +6,10 @@ import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||||
import com.greenorange.promotion.annotation.RequiresPermission;
|
import com.greenorange.promotion.annotation.RequiresPermission;
|
||||||
import com.greenorange.promotion.annotation.SysLog;
|
import com.greenorange.promotion.annotation.SysLog;
|
||||||
|
import com.greenorange.promotion.annotation.Timeout;
|
||||||
import com.greenorange.promotion.common.BaseResponse;
|
import com.greenorange.promotion.common.BaseResponse;
|
||||||
import com.greenorange.promotion.common.ErrorCode;
|
import com.greenorange.promotion.common.ErrorCode;
|
||||||
import com.greenorange.promotion.common.ResultUtils;
|
import com.greenorange.promotion.common.ResultUtils;
|
||||||
import com.greenorange.promotion.constant.SystemConstant;
|
|
||||||
import com.greenorange.promotion.constant.UserConstant;
|
import com.greenorange.promotion.constant.UserConstant;
|
||||||
import com.greenorange.promotion.exception.ThrowUtils;
|
import com.greenorange.promotion.exception.ThrowUtils;
|
||||||
import com.greenorange.promotion.model.dto.CommonBatchRequest;
|
import com.greenorange.promotion.model.dto.CommonBatchRequest;
|
||||||
|
@ -24,14 +24,11 @@ import com.greenorange.promotion.service.common.CommonService;
|
||||||
import com.greenorange.promotion.service.user.UserInfoService;
|
import com.greenorange.promotion.service.user.UserInfoService;
|
||||||
import com.greenorange.promotion.service.user.UserMainInfoService;
|
import com.greenorange.promotion.service.user.UserMainInfoService;
|
||||||
import com.greenorange.promotion.utils.JWTUtils;
|
import com.greenorange.promotion.utils.JWTUtils;
|
||||||
import com.greenorange.promotion.utils.RegexUtils;
|
|
||||||
import com.greenorange.promotion.utils.SendSmsUtil;
|
|
||||||
import io.swagger.v3.oas.annotations.Operation;
|
import io.swagger.v3.oas.annotations.Operation;
|
||||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||||
import jakarta.annotation.Resource;
|
import jakarta.annotation.Resource;
|
||||||
import jakarta.servlet.http.HttpServletRequest;
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
import jakarta.validation.Valid;
|
import jakarta.validation.Valid;
|
||||||
import jakarta.validation.constraints.NotBlank;
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.data.redis.core.RedisTemplate;
|
import org.springframework.data.redis.core.RedisTemplate;
|
||||||
import org.springframework.web.bind.annotation.*;
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
@ -408,4 +405,16 @@ public class UserInfoController {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@PostMapping("/test")
|
||||||
|
@Timeout(5000) // 设置超时时间为 3000 毫秒(3秒)
|
||||||
|
public String testMethod() throws InterruptedException {
|
||||||
|
// 模拟长时间的任务,超过 3 秒会抛出超时异常
|
||||||
|
Thread.sleep(10000); // 模拟 5 秒的耗时操作
|
||||||
|
return "任务完成";
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -246,6 +246,9 @@ public class UserInfoServiceImpl extends ServiceImpl<UserInfoMapper, UserInfo>
|
||||||
redisTemplate.opsForValue().set(SystemConstant.VERIFICATION_CODE + ":" + verificationCode, verificationCode, 5, TimeUnit.MINUTES);
|
redisTemplate.opsForValue().set(SystemConstant.VERIFICATION_CODE + ":" + verificationCode, verificationCode, 5, TimeUnit.MINUTES);
|
||||||
return verificationCode;
|
return verificationCode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -30,6 +30,12 @@ spring:
|
||||||
springdoc:
|
springdoc:
|
||||||
default-flat-param-object: true
|
default-flat-param-object: true
|
||||||
|
|
||||||
|
#线程池配置
|
||||||
|
threadpool:
|
||||||
|
corePoolSize: 10
|
||||||
|
maxPoolSize: 50
|
||||||
|
queueCapacity: 1024
|
||||||
|
keepAliveTime: 60
|
||||||
|
|
||||||
|
|
||||||
server:
|
server:
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
package com.greenorange.promotion.timeout;
|
package com.greenorange.promotion.timeout;
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.Timeout;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.web.bind.annotation.GetMapping;
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
import org.springframework.web.bind.annotation.RestController;
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
Loading…
Reference in New Issue
Block a user