Apache Camel:异步操作和背压

时间:2017-05-31 08:29:06

标签: java asynchronous apache-camel

在Apache Camel 2.19.0中,我想生成消息并在并发seda队列上异步使用结果,同时阻塞seda队列上的执行程序是否已满。 它背后的用例:我需要处理包含许多行的大型文件,并且需要为它创建批处理,因为每个单独行的单个消息开销太大,而我无法将整个文件放入堆中。但最后,我需要知道我触发的所有批次是否已成功完成。 如此有效,我需要一个反压机制来垃圾队列,同时又想利用多线程处理。

这是Camel和Spring的一个简单示例。我配置的路线:

package com.test;

import org.apache.camel.builder.RouteBuilder;
import org.springframework.stereotype.Component;

@Component
public class AsyncCamelRoute extends RouteBuilder {

    public static final String ENDPOINT = "seda:async-queue?concurrentConsumers=2&size=2&blockWhenFull=true";

    @Override
    public void configure() throws Exception {
        from(ENDPOINT)
                .process(exchange -> {
                    System.out.println("Processing message " + (String)exchange.getIn().getBody());
                    Thread.sleep(10_000);
                });
    }
}

制作人看起来像这样:

package com.test;

import org.apache.camel.ProducerTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Component;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CompletableFuture;

@Component
public class AsyncProducer {

    public static final int MAX_MESSAGES = 100;

    @Autowired
    private ProducerTemplate producerTemplate;

    @EventListener
    public void handleContextRefresh(ContextRefreshedEvent event) throws Exception {
        new Thread(() -> {
            // Just wait a bit so everything is initialized
            try {
                Thread.sleep(5_000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            List<CompletableFuture> futures = new ArrayList<>();

            System.out.println("Producing messages");
            for (int i = 0; i < MAX_MESSAGES; i++) {
                CompletableFuture future = producerTemplate.asyncRequestBody(AsyncCamelRoute.ENDPOINT, String.valueOf(i));
                futures.add(future);
            }
            System.out.println("All messages produced");

            System.out.println("Waiting for subtasks to finish");
            futures.forEach(CompletableFuture::join);
            System.out.println("Subtasks finished");
        }).start();

    }
}

此代码的输出如下:

Producing messages
All messages produced
Waiting for subtasks to finish
Processing message 6
Processing message 1
Processing message 2
Processing message 5
Processing message 8
Processing message 7
Processing message 9
...
Subtasks finished

因此,似乎忽略了blockIfFull,并且在处理之前创建了所有消息并将其放入队列。

有没有办法创建消息,以便我可以在camel中使用异步处理,同时确保如果有太多未处理的元素,将元素放入队列会阻塞?

1 个答案:

答案 0 :(得分:0)

我通过使用流媒体和自定义分割器解决了这个问题。通过执行此操作,我可以使用迭代器将源行拆分为块,该迭代器仅返回行列表而不是单行。有了这个,在我看来,我可以根据需要使用Camel。

因此该路线包含以下部分:

.split().method(new SplitterBean(), "splitBody").streaming().parallelProcessing().executorService(customExecutorService)

使用具有上述行为的定制分割器。