mateclaw/mateclaw-server/src/main/java/vip/mate/config/AsyncSecurityConfig.java
铭萱 446f34b6b5
feat(db): support KingbaseES (人大金仓) domestic database (#324)
Add KingbaseES support as an opt-in profile: dedicated migration tree, bilingual seed data, runtime DbType detection (KINGBASE_ES / POSTGRE_SQL), and JDBC URL handling in the datasource manager.
2026-06-14 10:30:09 +08:00

50 lines
2.0 KiB
Java

package vip.mate.config;
import org.springframework.boot.task.SimpleAsyncTaskExecutorBuilder;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.AsyncConfigurer;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.security.task.DelegatingSecurityContextTaskExecutor;
import java.util.concurrent.Executor;
/**
* Global async executor config — ensures SecurityContext propagation to @Async threads.
* <p>
* The inner delegate uses virtual threads (JDK 21); the outer
* {@link DelegatingSecurityContextTaskExecutor} wrapper propagates the caller's
* SecurityContext (JWT identity, audit permissions) to every @Async invocation.
* <p>
* A concurrency limit is set to prevent runaway virtual-thread creation
* from exhausting the HikariCP pool (typical pattern: a stampede of
* {@code @Async} tasks all trying to acquire DB connections at the same
* minute boundary). Excess tasks are rejected immediately so the
* scheduler threads never block on submission.
*
* @author MateClaw Team
*/
@Configuration
@EnableAsync
public class AsyncSecurityConfig implements AsyncConfigurer {
/**
* Cap in-flight async tasks. Well below HikariCP maximum-pool-size (30)
* so async tasks never saturate the pool on their own — non-async paths
* (HTTP requests, SSE, channel adapters) always have headroom.
*/
private static final int ASYNC_CONCURRENCY_LIMIT = 24;
@Override
public Executor getAsyncExecutor() {
// Keep DelegatingSecurityContextTaskExecutor so SecurityContext
// is propagated to every @Async invocation (JWT, audit, permission checks).
// Replace the inner platform-thread pool with a virtual-thread executor.
var delegate = new SimpleAsyncTaskExecutorBuilder()
.virtualThreads(true)
.concurrencyLimit(ASYNC_CONCURRENCY_LIMIT)
.threadNamePrefix("async-vt-")
.build();
return new DelegatingSecurityContextTaskExecutor(delegate);
}
}