简体   繁体   English

在不同的事件循环上为不同的 webflux 端点提供服务

[英]Serving different webflux endpoints on different eventloops

I have ported a large spring-web codebase to spring-webflux.我已将一个大型 spring-web 代码库移植到 spring-webflux。 There two sets of endpoints, some critical endpoints that must be fast, and some others that are not vital if they end up blocking in production.有两组端点,一些关键端点必须很快,而另一些端点如果最终在生产中阻塞则不重要。 I can validate that none of the critical endpoints block on the eventloop thread, but validating all the other endpoints is not feasible.我可以验证 eventloop 线程上没有任何关键端点阻塞,但验证所有其他端点是不可行的。 I would like to run them on a different threadpool or eventloop, so if they block, they do not affect the critical endpoints.我想在不同的线程池或事件循环上运行它们,因此如果它们阻塞,它们不会影响关键端点。

How would I go about this?我该怎么办?

I've tried using reflection to find all the handlers that either should or shouldn't be on a secondary eventloop, but can't think of a way to assign them to it.我尝试使用反射来查找所有应该或不应该在辅助事件循环中的处理程序,但想不出将它们分配给它的方法。 Alternatively, is it possible to run both spring-web and spring-webflux, and have spring-web serve the non-critical endpoints?或者,是否可以同时运行 spring-web 和 spring-webflux,并让 spring-web 为非关键端点提供服务?

I've managed to get the handlers from the handler registry like so:我已经设法从处理程序注册表中获取处理程序,如下所示:

@Component
class HandlerFinder(val requestMappingHandlerMappings: List<RequestMappingHandlerMapping>) {

    @PostConstruct
    fun start() {
        for (rmhm : RequestMappingHandlerMapping in requestMappingHandlerMappings) {
            val handlerMethods: Map<RequestMappingInfo, HandlerMethod> = rmhm.handlerMethods

            for ((mapping, method) in handlerMethods) {
                for (urlPattern in mapping.patternsCondition.patterns) {
                    log.info("${method.beanType.name}#${method.method.name} <-- ${urlPattern}")
                }
            }
        }
    }

    companion object {
        private val log = LoggerFactory.getLogger(HandlerFinder::class.java)
    }
}

I think the next step would be to somehow change the handlers to be wrapped in something like below, but I'm not sure how to change this in the handler registry:我认为下一步是以某种方式将处理程序更改为包装在如下所示的内容中,但我不确定如何在处理程序注册表中更改它:

Mono.fromCallable(() -> { ... handler method goes here ...}).publishOn(Schedulers.elastic());

I know I can unregister the mapping with rmhm.ungreisterMapping(mapping) and then re-register it with something like rmhm.registerMapping(mapping, method.bean, method.method) , but I'll need to create new methods to wrap the existing ones somehow.我知道我可以注销与映射rmhm.ungreisterMapping(mapping) ,然后用像重新注册rmhm.registerMapping(mapping, method.bean, method.method)但我需要创造新的方法来包装以某种方式现有的。

my suggestion would be to take your critical endpoints, that you dont want blocking and set subscribeOn我的建议是采取您不想阻止并设置subscribeOn关键端点

as the documentation states for subscribeOn正如subscribeOn文档所述

Changes the Thread from which the whole chain of operators subscribes更改整个运算符链订阅的线程

Your choice publishOn will only change the context from where that has been declared, and forward.您选择的publishOn只会更改已声明和转发的上下文。 subscribeOn will set an entire subscription to a dedicated scheduler. subscribeOn会将整个订阅设置为专用调度程序。

This way you can split up how you want your endpoints should be handled on different schedulers internally in the application.通过这种方式,您可以拆分您希望如何在应用程序内部的不同调度程序上处理端点。

I solved this by creating a WebFilter and changing subscribeOn as Thomas' answer suggests.我通过创建一个 WebFilter 并按照 Thomas 的回答更改subscribeOn来解决这个问题。

@Component
class SchedulerWebFilter(): WebFilter {
    val executorService = Executors.newFixedThreadPool(32)
    private val pathsWhitelist: Set<String> = ...

    override fun filter(exchange: ServerWebExchange, chain: WebFilterChain): Mono<Void> {
        val path = exchange.request.path.toString()
        return if (!pathsWhitelist.contains(path)) {
            chain.filter(exchange).subscribeOn(Schedulers.fromExecutor(executorService))
        } else {
            chain.filter(exchange)
        }
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM