1

이 문제의 해결책을 장려하는 엔터프라이즈 통합 패턴이나 제조법을 찾지 못했습니다.Apache Camel에서 재 배달 한 후에 웹 서비스를 호출하는 방법은 무엇입니까?

재 배달 시도가 모두 끝난 후에는 웹 서비스 요청을 원래 소스로 보내야합니다. 보낸 사람에게 실패한 배달을 알립니다.

모든 재 배달 시도가 고갈되면 메시지를 배달 못 한 편지 대기열로 옮겨야합니까? 그런 다음 해당 DL 대기열에서 수신하는 새 소비자를 만드시겠습니까? 원본 메시지 대기열마다 고유 한 데드 레터 대기열이 필요합니까? 데드 레터 큐로 이동하기 전에 소스 큐를 주목하여 메시지 헤더를 추가해야합니까? 모든 메시지가 하나의 데드 레터 큐로 이동하는 경우 내 소비자는 웹 서비스 요청을 보낼 곳을 어떻게 알 수 있습니까?

책, 블로그 게시물 또는 기사를 가르쳐 줄 수 있습니까? 규정 된 접근 방식은 무엇입니까?

정말 오래된 버전의 Fuse ESB에서 작업하고 있지만 ServiceMix의 솔루션이 동등하게 적용될 것으로 기대합니다.

어쩌면, 내가 원하는 것은 안티 패턴 또는 코드 냄새입니다. 제발 조언.

답변

1

Camel을 처음 접했을 때 실제로 그것에 대해 깊이 알고 싶다면 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입니다. Camel은 재시도 횟수가 모두 소진되면 자동으로 DLC로 보내며, DLC를 직접 정의해야합니다. 그 이름은 채널이고 실제로 대기열 일 필요는 없음을 암시합니다. 파일에 쓸 수 있고, 웹 서비스를 호출하고, 메시지 대기열에 메시지를 제출하거나, 로그에 기록 할 수 있습니다. 이는 전적으로 사용자에게 달려 있습니다.

// 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, 메시지 헤더, 오류 메시지 및 때로는 스택 추적과 같은 오류 세부 정보를 포함합니다. 결과 메시지는 상상할 수 있듯이 꽤 많이 커지지 만 특히 구성 요소와 서비스가 상당히 많은 환경에서는 문제 해결과 디버깅이 매우 간단합니다. 실패하면 다음 나눠 오류가에서 오는에 대한 특정 경로를 구현할 수 있도록 어디에서 유래

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 
} 

죽은 편지 큐에서 소모, 경로 ID는 말할 수 있습니다 : 여기에 하나 개를 내 프로젝트의 샘플 DLC 메시지입니다 :

// 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