[英]Error handling practices in spring integration flow
我有一個Spring集成流程,涉及異步執行,從網關返回值到控制器,返回值后繼續集成流程。
這是網關:
@MessagingGateway
public interface GW {
@Gateway(requestChannel = "f.input")
Task input(Collection<MessengerIncomingRequest> messages);
}
這是流程:
@Bean
IntegrationFlow jFlow() {
return IntegrationFlows.from(
MessageChannels.executor("f.input", executor()))
.split()
.channel(MessageChannels.executor(executor()))
.transform(transformer)
.channel(routerChannel())
.get();
}
@Bean
ThreadPoolTaskExecutor executor() {
ThreadPoolTaskExecutor pool = new ThreadPoolTaskExecutor();
...
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.route(p -> p.getKind().name(),
m -> m.suffix("Channel")
.channelMapping(TaskKind.CREATE.name(), "create")
....
}
@Bean
IntegrationFlow createFlow() {
return IntegrationFlows.from(
MessageChannels.direct("createChannel"))
.handle(routerService)
.get();
}
如何為整個流程定義錯誤處理程序? 什么是最佳做法? 我知道我可以為網關方法調用設置一個try / catch塊,但是它只會捕獲jFlow
流中出現的異常,這些異常發生在channel(routerChannel())
。
如何處理其余流程的錯誤? 還是整個流程?
UPDATE
我為publishSubscribeChannel
添加了錯誤處理程序
@Bean
IntegrationFlow routerChannelFlow() {
return IntegrationFlows
.from(routerChannel())
.publishSubscribeChannel(s -> s
.subscribe(f -> f.bridge(null))
.subscribe(process())
.errorHandler(errorHandler))
.get();
}
但它似乎沒有幫助,因為如果出現異常,我會收到以下錯誤:
cMessagingTemplate$TemporaryReplyChannel : Reply message received but the receiving thread has already received a reply:ErrorMessage [payload=org.springframework.messaging.MessageHandlingException:
並且我的錯誤處理程序不會被調用。
UPDATE
根據Gary的回答,我嘗試了這段代碼:
@Bean
IntegrationFlow jFLow() {
return IntegrationFlows.from(
MessageChannels.executor("f.input", executor()))
.split()
.channel(MessageChannels.executor(executor()))
.transform(transformer)
.channel(routerChannel())
.get();
}
@Bean
IntegrationFlow exceptionOrErrorFlow() {
return IntegrationFlows.from(
MessageChannels.direct("exceptionChannel"))
.handle(errorHandler, "handleError")
.get();
}
@Bean
MessageChannel exceptionChannel() {
return MessageChannels.direct("exceptionChannel")
.get();
}
@Bean
IntegrationFlow process() {
return f ->
f.enrichHeaders((spec) ->
spec.header("errorChannel", "exceptionChannel", true))
f.route(p -> p.getKind().name(),
m -> m.suffix("Channel")
.channelMapping(TaskKind.CREATE.name(), "create")
....
}
@MessagingGateway(errorChannel = "exceptionChannel")
在另一次編輯之后,我將exceptionChannel
添加到網關,並將富集標題移動到我的流的第二段(異步)。 如果在流的同步部分拋出異常,則控制器被阻塞。
首先,讓我解釋網關的工作原理 - 它應該有助於理解下面的解決方案。
請求消息獲得唯一的臨時回復通道,該通道被添加為replyChannel
標頭。 即使網關具有顯式的replyChannel
,它也只是橋接到請求的replyChannel
- 這就是網關如何將回復與請求相關聯。
現在,網關還將請求的errorChannel
標頭設置為相同的回復通道。 這樣,即使流是異步的,也可以將異常路由回網關,並將其拋出到調用者或路由到網關的錯誤通道(如果指定)。 此路由由MessagePublishingErrorHandler
執行,該MessagePublishingErrorHandler
連接到ErrorHandlingTaskExecutor
,它包裝您的執行程序。
因為您將結果返回到網關然后繼續; 網關交互是“花費”的,沒有任何東西會收到發送到replyChannel
標頭的消息(包括異常)。 因此,您看到的日志消息。
因此,一種解決方案是在發送到獨立流的消息上修復errorChannel
頭。 使用.enrichHeaders
替換(確保將覆蓋設置為true)網關設置的errorChannel
標頭。 這應該在流程中盡快完成,因此任何異常都將路由到該通道(然后您可以在那里訂閱您的錯誤處理程序)。
另一種解決方案是連接您自己的錯誤處理執行程序,在其MessagePublishingErrorHandler
上顯式設置defaultErrorChannel
並刪除errorChannel
標頭。
異步錯誤路由首先查找標頭; 如果存在,則錯誤消息在那里路由; 如果沒有標題,MPEH沒有默認的錯誤通道; 消息將被路由到默認的errorChannel
,其中(通常)訂閱了LoggingChannelAdapter
。 默認的errorChannel
是一個發布/訂閱者通道,因此您可以為其訂閱其他端點。
編輯
您正在更改pub / sub之前的頻道。
獲得至少一個網關響應非常重要; 您應該將錯誤通道單獨留在pub / sub的一條腿上,並在第二條腿上更新它。 這樣,第一條腿上的異常將被拋給調用者(如果你想在那里采取一些動作,你可以向網關添加一個errorChannel
,例如路由到你的異常處理程序)。 您必須只更新第二個分支上的標題,以便它的異常直接發送到您的錯誤處理程序。
如果您將網關上的errorChannel
設置為exceptionChannel
那么兩條腿上的異常將會出現在那里。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.