1

我並沒有發現能促進這個問題的解決方案的企業集成模式或配方:如何在Apache Camel中的重新獲取耗盡後調用Web服務?

重新傳送嘗試後已經用盡,我需要發送Web服務請求回到始發源,以通知發送失敗的發件人。

在耗盡所有重新發送嘗試後,我應該將消息移至死信隊列嗎?然後創建一個新的使用者在該DL隊列上偵聽?我的每個源消息隊列都需要一個獨特的死信隊列嗎?在我將它移動到死信隊列之前,我應該添加一個消息頭,注意源隊列嗎?如果所有消息都發送到單個死信隊列,那麼我的消費者應該如何知道發送Web服務請求的位置?

你能指點我一本書,博客文章或文章嗎?規定的方法是什麼?

我在Fuse ESB的一個非常舊的版本中工作,但我期望ServiceMix中的解決方案同樣適用。

或者,我所要求的是反模式或代碼異味。請指教。

回答

1

如果您是駱駝的新手,並且真的想深入瞭解它,我會推薦Camel in Action, a book by Claus Ibsen。有a second edition in the works,19個章節中有14個已經完成了,所以你也可以給出一個答案。

如果這有點太多,在線文檔是非常好的,你可以從中找到基本的東西。對於錯誤處理,我建議從general error handling page開始,然後移動到error handler docsexception policy documentation

一般來說,dead letter channel是要走的路 - 在重試完畢後駱駝會自動發送給DLC,您只需自己定義DLC。它的名字暗示,這是一個渠道,並不需要成爲一個隊列 - 您可以寫入文件,調用Web服務,將消息提交給消息隊列或僅寫入日誌,這完全取決於您。

// error-handler DLC, will send to HTTP endpoint when retries are exhausted 
errorHandler(deadLetterChannel("http4://my.webservice.hos/path") 
    .useOriginalMessage() 
    .maximumRedeliveries(3) 
    .redeliveryDelay(5000)) 

// exception-clause DLC, will send to HTTP endpoint when retries are exhausted 
onException(NetworkException.class) 
    .handled(true) 
    .maximumRedeliveries(5) 
    .backOffMultiplier(3) 
    .redeliveryDelay(15000) 
    .to("http4://my.webservice.hos/otherpath"); 

我自己一直喜歡有一個消息隊列,然後從那裏消耗任何其他恢復或報告。我通常包括交換ID和路由ID,消息頭,錯誤消息,有時甚至是堆棧跟蹤等故障細節。正如您可以想象的那樣,生成的消息會增長很多,但它極大地簡化了故障排除和調試工作,特別是在您擁有大量組件和服務的環境中。下面是一個我的樣板項目DLC消息:

public class DeadLetterChannelMessage { 
    private String timestamp = Times.nowInUtc().toString(); 
    private String exchangeId; 
    private String originalMessageBody; 
    private Map<String, Object> headers; 
    private String fromRouteId; 
    private String errorMessage; 
    private String stackTrace; 

    @RequiredByThirdPartyFramework("jackson") 
    private DeadLetterChannelMessage() { 
    } 

    @SuppressWarnings("ThrowableResultOfMethodCallIgnored") 
    public DeadLetterChannelMessage(Exchange e) { 
    exchangeId = e.getExchangeId(); 
    originalMessageBody = e.getIn().getBody(String.class); 
    headers = Collections.unmodifiableMap(e.getIn().getHeaders()); 
    fromRouteId = e.getFromRouteId(); 

    Optional.ofNullable(e.getProperty(Exchange.EXCEPTION_CAUGHT, Exception.class)) 
     .ifPresent(throwable -> { 
     errorMessage = throwable.getMessage(); 
     stackTrace = ExceptionUtils.getStackTrace(throwable); 
     }); 
    } 

    // getters 
} 

當從死信隊列消耗,路由標識可以告訴你的失敗源於這樣你就可以實現了特定於從那裏傳來遞錯誤路線:

// general DLC handling route 
from("{{your.dlc.uri}}") 
    .routeId(ID_REPROCESSABLE_DLC_ROUTE) 
    .removeHeaders(Headers.ALL) 
    .unmarshal().json(JsonLibrary.Jackson, DeadLetterChannelMessage.class) 
    .toD("direct:reprocess_${body.fromRouteId}"); // error handling route 

// handle errors from `myRouteId` 
from("direct:reprocess_myRouteId") 
    .log("Error: ${body.errorMessage} for ${body.originalMessageBody}"); 
    // you'll probably do something better here, e.g. 
    // .convertBodyTo(WebServiceErrorReport.class) // requires a converter 
    // .process(e -> { //do some pre-processing, like setting headers/properties }) 
    // .toD("http4://web-service-uri/path"); // send to web-service 


// for routes that have no DLC handling supplied 
onException(DirectConsumerNotAvailableException.class) 
    .handled(true) 
    .useOriginalMessage() 
    .removeHeaders(Headers.ALL) 
    .to({{my.unreprocessable.dlc}}); // errors that cannot be recovered from 
相關問題