从直接通道流返回值并在Spring Integration中继续执行异步流

时间:2016-03-20 20:14:52

标签: java spring spring-integration

我的网络应用程序中有以下集成配置:

@Bean
IntegrationFlow giraFlow() {
    return IntegrationFlows.from(
            MessageChannels.direct("gira.input"))
            .split()
            .transform(transformer)
            .handle(parserService)
            .channel(routerChannel())
            .get();
}

@Bean
MessageChannel routerChannel() {
    return MessageChannels.queue("routerChannel", 10)
            .get();
}


@Bean
IntegrationFlow routerChannelFlow() {
    return IntegrationFlows.from(
            routerChannel())
            .route(p -> p.getKind().name(),
                    m -> m.suffix("Channel")
                            .channelMapping(TaskKind.CREATE.name(), "create")
                            .channelMapping(TaskKind.RELOAD.name(), "reload")
            .get();
}

和一个网关:

@MessagingGateway
public interface GW {

    @Gateway(requestChannel = "gira.input")
    Task gira(Collection<Request> messages);

}

parserService

@Service
@Slf4j
public class ParserService {

    public Task handle(IssueTrackerTask task) {
        log.info("Parser service handling task {}", task);
        return task;
    }
}

我从Spring MVC控制器调用网关方法,我希望它返回一个Task对象,parserService返回它的body方法。重要的是我希望控制器被阻塞,直到它从parserService获得值。获得此值后,我希望我的集成流与routerChannelFlow异步进行,以便Web控制器方法尽可能快地返回,并且routerChannelFlow中的所有繁重操作都将在不阻塞的情况下完成控制器。

这是具有此网关方法调用的控制器的一部分:

...
Task gira = gw.gira(messages);
log.info("Result {}", gira);
...

问题是永远不会到达log.info并且永久阻止gira()网关。

我如何实现我想要的行为?

P.S。我的应用程序实际上不需要parserService,这正是我认为可以帮助我为我的网关定义返回值,但它实际上没有帮助:(

更新

所以我在Gary Russell的评论之后得到的是:

@Bean
public ThreadPoolTaskExecutor executor() {
    ThreadPoolTaskExecutor pool = new ThreadPoolTaskExecutor();
    pool.setCorePoolSize(10);
    pool.setMaxPoolSize(10);
    pool.setWaitForTasksToCompleteOnShutdown(true);
    return pool;
}

@Bean
MessageChannel routerChannel() {
    return MessageChannels
            .publishSubscribe("routerChannel", executor())
            .get();
}

@Bean
IntegrationFlow routerChannelFlow() {
    return IntegrationFlows
            .from(routerChannel())
            .publishSubscribeChannel(s -> s
                 .subscribe(f -> f
                         .bridge(null))
                 .subscribe(process()))
            .get();
}

@Bean
IntegrationFlow process() {
    return f ->
            f.<IssueTrackerTask, String>route(p -> p.getKind().name(),
                    m -> m.suffix("Channel")
                            .channelMapping(TaskKind.CREATE.name(), "create")
                            .channelMapping(TaskKind.RELOAD.name(), "reload")

}

当我尝试使用此管道时,我收到以下错误Dispatcher has no subscribers for channel 'application:development:9000.dummy'。这绝对是一个配置错误的问题,但我无法弄清楚我做错了什么。

更新

channel("dummy")更改为bridge(null)

2 个答案:

答案 0 :(得分:1)

createreload频道的下游是什么?

您如何处理控制器中的Task结果(除了记录它)?

如果您不需要结果,请将网关返回更改为void并在网关的下游添加执行程序通道。

如果你想要返回Task个对象,你需要routerChannel是一个发布/订阅通道,有一个执行者和两个订阅者 - 一个通往无处的桥梁(输入通道和没有输出通道)将Task返回到网关和路由器,它将在单独的线程上路由任务;来自路由器的下游流不能返回结果(网关将在很久之前停止等待结果)。

不是将执行程序添加到routerChannel,而是可以改为使用两个路由器通道执行通道。

答案 1 :(得分:1)

您的上一个解决方案几乎就在那里,您只需要.channel("dummy")使用.bridge(null),而.publishSubscribeChannel()的第一个子流订阅者只需replyChannel

您需要的是将消息发送回网关的TemporaryReplyChannel,即邮件标题中的BridgeHandler

replyChannel是做“无”的最佳方式,只是从标题中向相应的executor发送消息。

如果您的.split().transform()逻辑足够重,请考虑在.hanlde()之后将Error in vector(typeof(x$v), nr * nc) : vector size cannot be NA In addition: Warning message: In nr * nc : NAs produced by integer overflow 添加到频道。