diff --git a/orion-ops-framework/orion-ops-common/src/main/java/com/orion/ops/framework/common/config/OrionCommonAutoConfiguration.java b/orion-ops-framework/orion-ops-common/src/main/java/com/orion/ops/framework/common/config/OrionCommonAutoConfiguration.java index 0de2fc5f..f8bc7232 100644 --- a/orion-ops-framework/orion-ops-common/src/main/java/com/orion/ops/framework/common/config/OrionCommonAutoConfiguration.java +++ b/orion-ops-framework/orion-ops-common/src/main/java/com/orion/ops/framework/common/config/OrionCommonAutoConfiguration.java @@ -1,8 +1,15 @@ package com.orion.ops.framework.common.config; +import com.orion.ops.framework.common.thread.ThreadPoolMdcTaskExecutor; import com.orion.spring.SpringHolder; import org.springframework.boot.autoconfigure.AutoConfiguration; +import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Primary; +import org.springframework.core.task.TaskExecutor; +import org.springframework.scheduling.annotation.EnableAsync; + +import java.util.concurrent.ThreadPoolExecutor; /** * 应用配置类 @@ -11,7 +18,9 @@ import org.springframework.context.annotation.Bean; * @version 1.0.0 * @since 2023/6/20 10:34 */ +@EnableAsync @AutoConfiguration +@EnableConfigurationProperties(ThreadPoolConfig.class) public class OrionCommonAutoConfiguration { /** @@ -22,4 +31,31 @@ public class OrionCommonAutoConfiguration { return new SpringHolder.ApplicationContextAwareStore(); } + /** + * 支持 MDC 的异步线程池 + *

+ * {@code @Async("asyncExecutor")} + * + * @return 异步线程池 + */ + @Primary + @Bean(name = "asyncExecutor") + public TaskExecutor asyncExecutor(ThreadPoolConfig config) { + ThreadPoolMdcTaskExecutor executor = new ThreadPoolMdcTaskExecutor(); + executor.setCorePoolSize(config.getCorePoolSize()); + executor.setMaxPoolSize(config.getMaxPoolSize()); + executor.setQueueCapacity(config.getQueueCapacity()); + executor.setKeepAliveSeconds(config.getKeepAliveSeconds()); + executor.setAllowCoreThreadTimeOut(true); + executor.setThreadNamePrefix("async-task-"); + // 设置等待所有任务执行结束再关闭线程池 + executor.setWaitForTasksToCompleteOnShutdown(true); + // 以确保应用最后能够被关闭 + executor.setAwaitTerminationSeconds(60); + // 调用者调用拒绝策略 + executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy()); + executor.initialize(); + return executor; + } + } diff --git a/orion-ops-framework/orion-ops-common/src/main/java/com/orion/ops/framework/common/config/ThreadPoolConfig.java b/orion-ops-framework/orion-ops-common/src/main/java/com/orion/ops/framework/common/config/ThreadPoolConfig.java new file mode 100644 index 00000000..54db43c5 --- /dev/null +++ b/orion-ops-framework/orion-ops-common/src/main/java/com/orion/ops/framework/common/config/ThreadPoolConfig.java @@ -0,0 +1,44 @@ +package com.orion.ops.framework.common.config; + +import lombok.Data; +import org.springframework.boot.context.properties.ConfigurationProperties; + +/** + * 线程池配置类 + * + * @author Jiahang Li + * @version 1.0.0 + * @since 2023/7/10 15:49 + */ +@Data +@ConfigurationProperties(prefix = "orion.thread.pool") +public class ThreadPoolConfig { + + /** + * 核心线程数量 + */ + private int corePoolSize; + + /** + * 最大线程数量 + */ + private int maxPoolSize; + + /** + * 队列容量 + */ + private int queueCapacity; + + /** + * 活跃时间 + */ + private int keepAliveSeconds; + + public ThreadPoolConfig() { + this.corePoolSize = 8; + this.maxPoolSize = 16; + this.queueCapacity = 200; + this.keepAliveSeconds = 300; + } + +} diff --git a/orion-ops-framework/orion-ops-common/src/main/java/com/orion/ops/framework/common/constant/ErrorCode.java b/orion-ops-framework/orion-ops-common/src/main/java/com/orion/ops/framework/common/constant/ErrorCode.java index c4404f16..e80c29d3 100644 --- a/orion-ops-framework/orion-ops-common/src/main/java/com/orion/ops/framework/common/constant/ErrorCode.java +++ b/orion-ops-framework/orion-ops-common/src/main/java/com/orion/ops/framework/common/constant/ErrorCode.java @@ -15,7 +15,7 @@ public enum ErrorCode implements CodeInfo { BAD_REQUEST(400, "参数验证失败"), - UNAUTHORIZED(401, "会话过期"), + UNAUTHORIZED(401, "当前认证信息已失效, 请重新登录"), FORBIDDEN(403, "无操作权限"), diff --git a/orion-ops-framework/orion-ops-common/src/main/java/com/orion/ops/framework/common/meta/TraceIdHolder.java b/orion-ops-framework/orion-ops-common/src/main/java/com/orion/ops/framework/common/meta/TraceIdHolder.java index 611f421b..10810f8c 100644 --- a/orion-ops-framework/orion-ops-common/src/main/java/com/orion/ops/framework/common/meta/TraceIdHolder.java +++ b/orion-ops-framework/orion-ops-common/src/main/java/com/orion/ops/framework/common/meta/TraceIdHolder.java @@ -11,6 +11,10 @@ import com.alibaba.ttl.TransmittableThreadLocal; */ public class TraceIdHolder { + public static final String TRACE_ID_HEADER = "trace-id"; + + public static final String TRACE_ID_MDC = "tid"; + private TraceIdHolder() { } diff --git a/orion-ops-framework/orion-ops-common/src/main/java/com/orion/ops/framework/common/thread/ThreadPoolMdcTaskExecutor.java b/orion-ops-framework/orion-ops-common/src/main/java/com/orion/ops/framework/common/thread/ThreadPoolMdcTaskExecutor.java new file mode 100644 index 00000000..0be3b877 --- /dev/null +++ b/orion-ops-framework/orion-ops-common/src/main/java/com/orion/ops/framework/common/thread/ThreadPoolMdcTaskExecutor.java @@ -0,0 +1,33 @@ +package com.orion.ops.framework.common.thread; + +import com.orion.ops.framework.common.utils.ThreadMdcUtils; +import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; + +import java.util.concurrent.Callable; +import java.util.concurrent.Future; + +/** + * 自动注入 MDC 异步线程池 + * + * @author Jiahang Li + * @version 1.0.0 + * @since 2023/7/10 15:16 + */ +public class ThreadPoolMdcTaskExecutor extends ThreadPoolTaskExecutor { + + @Override + public void execute(Runnable task) { + super.execute(ThreadMdcUtils.wrap(task)); + } + + @Override + public Future submit(Callable task) { + return super.submit(ThreadMdcUtils.wrap(task)); + } + + @Override + public Future submit(Runnable task) { + return super.submit(ThreadMdcUtils.wrap(task)); + } + +} diff --git a/orion-ops-framework/orion-ops-common/src/main/java/com/orion/ops/framework/common/utils/ThreadMdcUtils.java b/orion-ops-framework/orion-ops-common/src/main/java/com/orion/ops/framework/common/utils/ThreadMdcUtils.java new file mode 100644 index 00000000..e026f861 --- /dev/null +++ b/orion-ops-framework/orion-ops-common/src/main/java/com/orion/ops/framework/common/utils/ThreadMdcUtils.java @@ -0,0 +1,84 @@ +package com.orion.ops.framework.common.utils; + +import com.orion.ops.framework.common.meta.TraceIdHolder; +import org.slf4j.MDC; + +import java.util.Map; +import java.util.concurrent.Callable; + +/** + * 多线程下 MDC 工具类 + * + * @author Jiahang Li + * @version 1.0.0 + * @since 2023/7/10 14:55 + */ +public class ThreadMdcUtils { + + private ThreadMdcUtils() { + } + + /** + * 设置 MDC traceId + */ + public static void setTraceIdIfAbsent() { + if (MDC.get(TraceIdHolder.TRACE_ID_MDC) == null) { + MDC.put(TraceIdHolder.TRACE_ID_MDC, TraceIdHolder.get()); + } + } + + /** + * 设置线程 MDC 上下文 + * + * @param callable callable + * @param T + * @return callable + */ + public static Callable wrap(Callable callable) { + // 获取当前线程 MDC 上下文 + Map callerContext = MDC.getCopyOfContextMap(); + return () -> { + if (callerContext == null) { + MDC.clear(); + } else { + MDC.setContextMap(callerContext); + } + // 设置 traceId + setTraceIdIfAbsent(); + // 执行线程并且清理MDC + try { + return callable.call(); + } finally { + MDC.clear(); + } + }; + } + + /** + * 设置线程 MDC 上下文 + * + * @param runnable runnable + * @return callable + */ + public static Runnable wrap(Runnable runnable) { + // 获取当前线程 MDC 上下文 + Map callerContext = MDC.getCopyOfContextMap(); + return () -> { + // + if (callerContext == null) { + MDC.clear(); + } else { + MDC.setContextMap(callerContext); + } + // 设置 traceId + setTraceIdIfAbsent(); + // 执行线程并且清理MDC + try { + runnable.run(); + } finally { + MDC.clear(); + } + }; + } + +} diff --git a/orion-ops-framework/orion-ops-common/src/main/resources/META-INF/spring-configuration-metadata.json b/orion-ops-framework/orion-ops-common/src/main/resources/META-INF/spring-configuration-metadata.json new file mode 100644 index 00000000..b39e42d7 --- /dev/null +++ b/orion-ops-framework/orion-ops-common/src/main/resources/META-INF/spring-configuration-metadata.json @@ -0,0 +1,35 @@ +{ + "groups": [ + { + "name": "orion.thread.pool", + "type": "com.orion.ops.framework.common.config.ThreadPoolConfig", + "sourceType": "com.orion.ops.framework.common.config.ThreadPoolConfig" + } + ], + "properties": [ + { + "name": "orion.thread.pool.core-pool-size", + "type": "java.lang.Integer", + "description": "核心线程数量", + "defaultValue": "8" + }, + { + "name": "orion.thread.pool.max-pool-size", + "type": "java.lang.Integer", + "description": "最大线程数量.", + "defaultValue": "16" + }, + { + "name": "orion.thread.pool.queue-capacity", + "type": "java.lang.Integer", + "description": "队列容量.", + "defaultValue": "200" + }, + { + "name": "orion.thread.pool.keep-alive-seconds", + "type": "java.lang.Integer", + "description": "活跃时间.", + "defaultValue": "300" + } + ] +} \ No newline at end of file diff --git a/orion-ops-launch/src/main/java/com/orion/ops/launch/controller/BootstrapController.java b/orion-ops-launch/src/main/java/com/orion/ops/launch/controller/BootstrapController.java index e1b33211..16d43793 100644 --- a/orion-ops-launch/src/main/java/com/orion/ops/launch/controller/BootstrapController.java +++ b/orion-ops-launch/src/main/java/com/orion/ops/launch/controller/BootstrapController.java @@ -2,6 +2,7 @@ package com.orion.ops.launch.controller; import com.orion.ops.framework.common.annotation.RestWrapper; import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @@ -13,6 +14,7 @@ import org.springframework.web.bind.annotation.RestController; * @version 1.0.0 * @since 2023/6/19 17:08 */ +@Tag(name = "launch - 启动服务") @RestWrapper @RestController @RequestMapping("/server/bootstrap") diff --git a/orion-ops-launch/src/main/resources/application-prod.yaml b/orion-ops-launch/src/main/resources/application-prod.yaml index 2c8700a9..c5fb85b4 100644 --- a/orion-ops-launch/src/main/resources/application-prod.yaml +++ b/orion-ops-launch/src/main/resources/application-prod.yaml @@ -33,16 +33,17 @@ springdoc: knife4j: enable: false -logging: - printer: - mode: ROW - orion: + logging: + printer: + mode: ROW crypto: aes: - enabled: true - working-mode: ECB - padding-mode: PKCS5_PADDING # 加密秘钥 secret-key: uQeacXV8b3isvKLK - generator-key: true + thread: + pool: + core-pool-size: 8 + max-pool-size: 16 + queue-capacity: 200 + keep-alive-seconds: 300