简体   繁体   English

如何在 Spring 集成流程中正确实现延迟

[英]How to correctly implement delay in Spring Integration Flow

I am trying to implement a delay in a Spring Integration Flow.我正在尝试在 Spring 集成流程中实现延迟。
I have one flow that is starting a process on another server and then I am checking after a delay if that process is completed or not.我有一个流程正在另一台服务器上启动一个进程,然后我在延迟后检查该进程是否完成。
When completed the flow should move to the next phase.完成后,流程应进入下一阶段。
This seems to work it also shows in logs (and, clearly, in the flow itself), a long list of repetitions in the runexampleScriptWaiting channel.这似乎有效,它也显示在日志中(很明显,在流程本身中), runexampleScriptWaiting通道中的一长串重复。

I tried removing that channel change but then the flow gets stuck in that phase forever, never moving to completion.我尝试删除该频道更改,但随后流程永远停留在该阶段,永远不会完成。

How can I implement this so that a single runexampleScriptWaiting is shown / executed (something similar to a non-blocking while loop, I guess)?如何实现这一点,以便显示/执行单个 runexampleScriptWaiting(我猜类似于非阻塞 while 循环)?

I considered keeping it as is and just update my monitoring application (a very small frontend that shows which channels are in the payload's history) in order to get rid of duplicated channel lines but I also wondered if there is a better / more robust way to do this.我考虑保持原样并仅更新我的监控应用程序(一个非常小的前端,显示有效负载历史中的哪些通道)以消除重复的通道行,但我也想知道是否有更好/更强大的方法来做这个。

Here's a simplified example:这是一个简化的示例:

@Bean
public IntegrationFlow exampleIntegrationFlow() {
    return IntegrationFlows
            .from(exampleConfig.runexampleScript.get())
            .<ExamplePayload>handle((payload, messageHeaders) -> examplePayloadService
                    .changeExampleServiceRequestStatus(payload, ExampleServiceStatus.STARTED))
            .<ExamplePayload>handle(
                    (payload, messageHeaders) -> exampleScriptService.runexample(payload))
            .channel(exampleConfig.runexampleScriptWaiting.get())
            .<ExamplePayload, Boolean>route(jobStatusService::areJobsFinished,
                    router -> router
                            .subFlowMapping(true, exampleSuccessSubflow())
                            .subFlowMapping(false, exampleWaitSubflow())
                            .defaultOutputToParentFlow()
            )
            .get();
}

@Bean
public IntegrationFlow exampleWaitSubflow() {
    return IntegrationFlows
            .from(exampleConfig.runexampleScriptWaiting.get())
            .<ExamplePayload>handle(
                    (payload, messageHeaders) -> {
                        interruptIgnoringSleep(1000);
                        return payload;
                    })
            .channel(exampleConfig.runexampleScriptWaiting.get()) // Commenting this gets the process stuck
            .get();

}

It is not clear what is your exampleConfig.runexampleScriptWaiting.get() , but what you have so far in the config is not OK.目前尚不清楚您的exampleConfig.runexampleScriptWaiting.get()是什么,但是到目前为止您在配置中的内容还不行。 You have two subscribers to the same channel:同一频道有两个订阅者:

  1. .channel(exampleConfig.runexampleScriptWaiting.get()) and the next route() .channel(exampleConfig.runexampleScriptWaiting.get())和下一个route()

  2. .from(exampleConfig.runexampleScriptWaiting.get()) and the next handle() .from(exampleConfig.runexampleScriptWaiting.get())和下一个handle()

This may cause unexpected behavior, eg round-robin messages distribution.这可能会导致意外行为,例如循环消息分发。

I would do filter() and delay() instead in addition to an ExecutorChannel since you are asking about non-blocking retry:除了ExecutorChannel之外,我还会执行filter()delay() ,因为您询问的是非阻塞重试:

.channel(exampleConfig.runexampleScriptWaiting.get())
.filter(jobStatusService::areJobsFinished, 
            filter -> filter.discardFlow(
                          discardFlow -> discardFlow
                                            .delay(1000)
                                            .channel(exampleConfig.runexampleScriptWaiting.get())))

The exampleSuccessSubflow could go just after this filter() as part of this flow or via to(exampleSuccessSubflow()) . exampleSuccessSubflow可以 go 在此filter()之后作为此流的一部分或通过to(exampleSuccessSubflow())

Pay attention to that discardFlow : we delay non-finished message a little bit and produce it back to that runexampleScriptWaiting channel for calling this filter again.注意那个discardFlow :我们稍微延迟未完成的消息并将其生成回那个runexampleScriptWaiting通道以再次调用此过滤器。 If you make this channel as an ExecutorChannel (or QueueChannel ), your wait functionality is going to be non-blocking.如果您将此通道设为ExecutorChannel (或QueueChannel ),您的等待功能将是非阻塞的。 But at the same time your main flow is still going to be blocked for this request since you continue waiting for reply.但与此同时,由于您继续等待回复,您的主要流程仍将被此请求阻塞。 Therefore it might not make too much sense to make this filtering logic as non-blocking and you can still use that Thread.sleep() instead of delay() .因此,将此过滤逻辑设为非阻塞可能没有太大意义,您仍然可以使用Thread.sleep()而不是delay()

The router solution also may work, but you cannot use that runexampleScriptWaiting channel as an input of that sub-flow.路由器解决方案也可能有效,但您不能使用该runexampleScriptWaiting通道作为该子流的输入。 Probably that's the reason behind that your problem with "process stuck".可能这就是您的“进程卡住”问题背后的原因。

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

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