Если вы новичок в Camel и действительно хотите получить глубокое знание об этом, я бы порекомендовал Camel in Action, a book by Claus Ibsen. Там a second edition in the works, с 14 из 19 глав уже сделано, чтобы вы могли также сделать это.
Если это слишком много, онлайн-документация в порядке, вы можете узнать об основных принципах. Для обработки ошибок я рекомендую начать с general error handling page, а затем перейти на error handler docs и exception 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");
Я сам всегда предпочитал иметь очередь сообщений, а затем потреблял оттуда для любого другого восстановления или отчетности. Я обычно включаю данные об отказе, такие как идентификатор обмена и идентификатор маршрута, заголовки сообщений, сообщение об ошибке, а иногда даже stacktrace. Получающееся сообщение, как вы можете себе представить, растет совсем немного, но оно значительно упрощает поиск и устранение неполадок и отладки, особенно в средах, где у вас есть довольно много компонентов и сервисов. Вот пример сообщение 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
}
При потреблении из очереди мертвой буквы, маршрут ID может сказать, где неудача возникла из так что вы можете реализовать маршруты, которые являются специфическими для ошибок вручая приходят оттуда :
// 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