You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Spring Boot:执行/stopRunningJobs API时拦截或排队其他请求方案

针对Spring Boot 2.7.0中/stopRunningJobs API的请求控制方案

方案1:执行/stopRunningJobs时阻止接收其他请求

完全可行,核心通过全局状态开关+请求拦截实现,也可以直接操作Servlet容器的连接池彻底拦截请求:

实现方式1:自定义全局过滤器

  1. 定义原子布尔变量作为全局开关,确保线程安全:private static final AtomicBoolean STOP_MODE_ACTIVE = new AtomicBoolean(false);
  2. 在/stopRunningJobs接口逻辑开头将开关设为true,所有Batch任务停止完成后再重置为false
  3. 编写过滤器拦截除/stopRunningJobs外的所有请求,开关激活时直接返回服务不可用状态

代码示例:

@Component
public class RequestBlockFilter implements Filter {
    private static final AtomicBoolean STOP_MODE_ACTIVE = new AtomicBoolean(false);

    public static void setStopModeActive(boolean active) {
        STOP_MODE_ACTIVE.set(active);
    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        HttpServletRequest httpRequest = (HttpServletRequest) request;
        if (STOP_MODE_ACTIVE.get() && !"/stopRunningJobs".equals(httpRequest.getRequestURI())) {
            HttpServletResponse httpResponse = (HttpServletResponse) response;
            httpResponse.setStatus(HttpServletResponse.SC_SERVICE_UNAVAILABLE);
            httpResponse.getWriter().write("Service is stopping, please try again later.");
            return;
        }
        chain.doFilter(request, response);
    }
}

对应Controller逻辑:

@PostMapping("/stopRunningJobs")
public ResponseEntity<String> stopRunningJobs() {
    RequestBlockFilter.setStopModeActive(true);
    try {
        // 执行停止所有Spring Batch任务的逻辑
        stopAllBatchJobs();
        return ResponseEntity.ok("All jobs stopped successfully");
    } finally {
        RequestBlockFilter.setStopModeActive(false);
    }
}

实现方式2:操作Servlet容器(以Tomcat为例)

如果需要彻底阻止容器接收新请求,可以直接控制Tomcat的连接器:

@Autowired
private ServletWebServerApplicationContext webServerApplicationContext;

private void pauseConnector() {
    TomcatWebServer tomcatWebServer = (TomcatWebServer) webServerApplicationContext.getWebServer();
    for (Connector connector : tomcatWebServer.getTomcat().getService().findConnectors()) {
        connector.pause();
    }
}

private void resumeConnector() {
    TomcatWebServer tomcatWebServer = (TomcatWebServer) webServerApplicationContext.getWebServer();
    for (Connector connector : tomcatWebServer.getTomcat().getService().findConnectors()) {
        connector.resume();
    }
}

在/stopRunningJobs接口中,先调用pauseConnector()暂停接收新请求,任务处理完成后调用resumeConnector()恢复。注意这种方式会拦截所有请求,包括/stopRunningJobs本身,需确保该接口的请求已进入处理流程后再执行暂停。


方案2:将新请求排队,待/stopRunningJobs处理完成后恢复

可行,核心是用异步队列缓存请求,待停止操作完成后批量处理:

实现思路

  1. 同样用全局开关标记停止模式
  2. 编写拦截器,开关激活时将请求的AsyncContext存入阻塞队列,暂不处理
  3. 停止模式结束后,启动线程从队列中取出请求,继续执行原有逻辑

代码示例:

@Component
public class RequestQueueFilter implements Filter {
    private static final AtomicBoolean STOP_MODE_ACTIVE = new AtomicBoolean(false);
    private static final BlockingQueue<AsyncContext> REQUEST_QUEUE = new LinkedBlockingQueue<>();

    public static void setStopModeActive(boolean active) {
        STOP_MODE_ACTIVE.set(active);
        if (!active) {
            // 停止模式结束,批量处理队列中的请求
            new Thread(() -> {
                AsyncContext ctx;
                while ((ctx = REQUEST_QUEUE.poll()) != null) {
                    try {
                        ctx.dispatch();
                    } catch (Exception e) {
                        ctx.getResponse().setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
                        ctx.complete();
                    }
                }
            }).start();
        }
    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        HttpServletRequest httpRequest = (HttpServletRequest) request;
        if (STOP_MODE_ACTIVE.get() && !"/stopRunningJobs".equals(httpRequest.getRequestURI())) {
            AsyncContext asyncContext = request.startAsync();
            // 设置超时时间,避免客户端无限等待
            asyncContext.setTimeout(30000);
            REQUEST_QUEUE.offer(asyncContext);
            return;
        }
        chain.doFilter(request, response);
    }
}

Controller逻辑与方案1一致,在finally块中调用RequestQueueFilter.setStopModeActive(false)触发队列处理。

注意事项

  • 根据业务场景设置队列容量,避免内存溢出
  • 配置合理的请求超时时间,防止客户端长时间等待
  • 高并发场景下建议结合线程池处理队列请求,避免单线程瓶颈

内容的提问来源于stack exchange,提问作者Harish Dalmia

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.25 09:06:35