简体   繁体   English

为什么在使用 Java DSL 时,我必须在入站 webflux 网关上使用.fluxTransform(f -> f)?

[英]Why do I have to use .fluxTransform(f -> f) on an inbound webflux gateways when using Java DSL?

I've run into failed replies when using the webflux gateway Java DSL in Spring Integration.在 Spring 集成中使用 webflux 网关 Java DSL 时,我遇到了失败的回复。 It only works for the first few requests (<8 to be specific), I'm getting reply errors afterwards:它仅适用于前几个请求(具体为<8),之后我收到回复错误:

org.springframework.integration.MessageTimeoutException: failed to receive JMS response within timeout of: 5000ms
    at org.springframework.integration.jms.JmsOutboundGateway.handleRequestMessage(JmsOutboundGateway.java:741) ~[spring-integration-jms-5.3.2.RELEASE.jar:5.3.2.RELEASE]
    Suppressed: reactor.core.publisher.FluxOnAssembly$OnAssemblyException:

When I use .fluxTransform(f -> f) on the inbound gateway OR when I use the non-reactive http outbound gateway , I don't get the errors, even on a jmeter benchmark with thousands of requests.当我在入站网关上使用.fluxTransform(f -> f)当我使用非反应式http 出站网关时,即使在具有数千个请求的 jmeter 基准测试中,我也不会收到错误。

  • Why do I have to call fluxTransform(f -> f) in the first flow to make it work?为什么我必须在第一个流程中调用fluxTransform(f -> f)才能使其工作?
  • Why does it work without fluxTransform(f -> f) when I use Http.outboundGateway in the second flow ?当我在第二个流程中使用Http.outboundGateway时,为什么它在没有fluxTransform(f -> f)的情况下工作?

Scenario设想
I've created a route using four gateways for a rather complex setup to make a web request on a remote machine, but I'm我已经使用四个网关创建了一个路由,以进行相当复杂的设置,以便在远程机器上发出 web 请求,但我

Integration Flow 1:整合流程一:

inbound webflux gateway -> outbound jms gateway入站 webflux 网关 -> 出站 jms 网关

  @Bean
  public IntegrationFlow step1() {
    // request-reply pattern using the jms outbound gateway
    var gateway = Jms.outboundGateway(jmsConnectionFactory)
        .requestDestination("inboundWebfluxQueue")
        .replyDestination("outboundWebfluxQueue")
        .correlationKey("JMSCorrelationID");

    // send a request to jms, wait for the reply and return message payload as response
    return IntegrationFlows.from(webfluxServer("/example/webflux"))
        // won't work consistently without the next line
        .fluxTransform(f -> f)
        .handle(gateway).get();
  }

Integration Flow 2:集成流程 2:

inbound jms gateway -> outbound webflux gateway入站 jms 网关 -> 出站 webflux 网关

  @Bean
  public IntegrationFlow step2_using_webflux() {
    var gateway = WebFlux.outboundGateway("http://localhost:8080/actuator/health")
        .httpMethod(HttpMethod.GET)
        .expectedResponseType(String.class)
        // ignore headers
        .mappedResponseHeaders();

    return IntegrationFlows.from(jmsInboundGateway())
        // use webflux outbound gateway to send the request to the TEST_URL
        .handle(gateway).get();
  }

The complete route looks like this:完整的路线如下所示:

client web request -> flow 1 -> (message broker) -> flow 2 -> server web request客户端 web 请求 -> 流 1 ->(消息代理)-> 流 2 -> 服务器 web 请求

Another way is to use a .channel(MessageChannels.flux()) instead of that .fluxTransform(f -> f) .另一种方法是使用.channel(MessageChannels.flux())而不是.fluxTransform(f -> f) This way we really bring a back-pressure to the the WebFlux container making it waiting for available slot in the request event loop.通过这种方式,我们真正为 WebFlux 容器带来了背压,使其等待请求事件循环中的可用插槽。

With that we just send to JMS queue not-honoring back-pressure and and your JMS consumer on the other side can't keep up.有了这个,我们只是向 JMS 队列发送不尊重背压,而另一端的 JMS 使用者无法跟上。 Plus we send a request to the same Netty server internally acquiring an event loop slot again for those internal requests.另外,我们向同一个 Netty 服务器内部发送一个请求,再次为这些内部请求获取一个事件循环槽。

If you are interested I wrote a unit test like this to see what is going on:如果你有兴趣,我写了一个这样的单元测试来看看发生了什么:

@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.DEFINED_PORT)
public class IntegrationApplicationTests {


    @Autowired
    private TestRestTemplate template;

    @Test
    void testSpringIntegrationWebFlux() {
        var executor = new ThreadPoolTaskExecutor();
        executor.setCorePoolSize(100);
        executor.setWaitForTasksToCompleteOnShutdown(true);
        executor.setAwaitTerminationSeconds(10);
        executor.afterPropertiesSet();

        var numberOfExecutions = new AtomicInteger();

        for (var i = 0; i < 100; i++) {
            executor.execute(() -> {
                var responseEntity = this.template.getForEntity("/example/webflux", String.class);
                if (responseEntity.getStatusCode().is2xxSuccessful()) {
                    numberOfExecutions.getAndIncrement();
                }
            });
        }

        executor.shutdown();

        assertThat(numberOfExecutions.get()).isEqualTo(100);
    }

}

暂无
暂无

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

相关问题 为什么我在使用 Spring Security + WebFlux 时对身份验证端点有双重请求 - Why do I have double request to authentication endpoint when I use Spring Security + WebFlux 为什么在使用float时Java强制我添加f? - Why does java force me to add f when I use float? 你好,我怎样才能将 hexString 转换为 int。 我有“F3A4”,我想编写一个方法或使用 Java_API 来获取 int。 请问我如何编码? - Hallo , how can I convert a hexString to int . I have "F3A4" and i want to write a method or use Java_API to get the int. How code I do it please? 为什么我打印的时候f的值总是0? - Why is the value of f when I print it always 0? Java L&amp;F 自定义:如何使用 synth 自定义 BorderFactory 边框? - Java L&F customization: How do I use synth to customize BorderFactory borders? 当我按Ctrl + F6来运行Java文件时,netbeans IDE会做什么? - What will netbeans IDE do when I press Ctrl+F6 to run a java file? 如何打印我的 Java object 而不会得到“SomeType@2f92e0f4”? - How do I print my Java object without getting "SomeType@2f92e0f4"? 为什么在 java 中的 for 循环中使用 f.length() 效率如此之低? - Why is using f.length() in a for loop so inefficient in java? 为什么 SongName[i]!= null 在它应该是 F 时评估为 T - Why does songName[i]!= null evaluates to T when it should be F 当我调用方法 f() 时,控制台中什么也没有出现。 为什么? - When i call the method f() nothing appears in the console. Why?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM