路由构建器的示例代码如下:
// For out of seq event state (reque)
onException(OutOfSeqStateException.class)
.logStackTrace(false).logExhaustedMessageHistory(false)
.setHeader("eventSource", constant(EventConstants.BACKEND))
.delay(30000)/*.method(DelayerBean.class , "computeDelayInMillis")*/.asyncDelayed().// delay should be asynchronously
.setBody().header(EventConstants.BE_STATE_EVENT)// send original event
.to("direct:requeue");// toendpoint: requeroute
// For handling other exceptions
onException(Exception.class)
.log("EXCEPTION OCCURED..... -> \"${exception.message}\"")
.setExchangePattern(ExchangePattern.InOnly)
.bean(KafkaErrorHandlerBean.class, "handle")
.handled(true);
// Backend Events Route
from(commonCamelConfig.getKafkaConsumerEndpoint())
.routeId("BackendStateIncomingRoute")
.id(routeId)
.to("log:" + fqClassName + "?showAll=true&level=" + logLevel)
.unmarshal(jdf)
.bean(MandatoryFieldCheckerBean.class, "performNullCheck")
// all context info must be present,if not, throw exception
.bean(ValidateEventHandlerBean.class, "validateIncomingEvents")
.choice()
.when().simple("${in.header.isValidEvent} == true",Boolean.class)//enter if valid event(backendstate/backenddata)
.choice()
.when(header("BEStateEvent").isNotNull())
.bean(EventTransformer.class, "getBackendTransformedEvent")
.bean(PaymentsService.class, "processMessage")
.bean(TransitionalStateHandlerBean.class,"handle")
.bean(AMQPProducer.class, "sendEventToMQ")
.setExchangePattern(ExchangePattern.InOnly)
.otherwise()
.bean(EventTransformer.class, "getBackendTransformedEvent")
.bean(PaymentsService.class, "processMessage")
.endChoice()
.setExchangePattern(ExchangePattern.InOnly)//acknowledge only valid events, doesnt expect a reply
.endChoice()
.end();
//Reque the original event in case of Retryable Exceptions
from("direct:requeue").routeId("BackendDirectRequeRoute")
.bean(RequestRetryHandlerBean.class, "doRetry")
.to(commonCamelConfig.getKafkaConsumerEndpoint())
.end();
使用者端点的Kafka配置如下:
public String getKafkaConsumerEndpoint() {
return properties.getJmsKafkaBroker()
+ ":" + properties.getKafkaPaymentsOtpTopic()
+ "?brokers="+ properties.getBootstrapServers()
+ "&groupId="+ properties.getGroupId()
+ "&autoOffsetReset="+ properties.getAutoOffsetReset()
+ "&autoCommitEnable=true"
+ "&keyDeserializer=org.apache.kafka.common.serialization.StringDeserializer"
+ "&valueDeserializer=org.apache.kafka.common.serialization.StringDeserializer";
}
关于上述代码,我有两个查询:
在整个路由的哪一点,kafka使用者是提交偏移量还是一项独立的任务,因为我尚未修改字段 autoCommitIntervalMs 的默认值5秒这是否意味着它会每5秒独立提交一次。
在发生序列外异常的情况下,我想处理请求场景,而我这样做的方法是通过创建另一个具有延迟模式逻辑的端点,该端点将在最大请求时间后将错误消息发送给DLQ。上述逻辑中有哪些漏洞,有没有更好的方法来处理?如果这个逻辑看起来不错,那么请查看我使用了 asyncdelayed()进行异步延迟,但是它似乎无法正常工作并阻止新消息,直到被请求为止。请帮助我实现异步延迟。
答案 0 :(得分:0)
1)如果使用的骆驼版本<2.22,则无法控制偏移提交,它发生在默认值为5秒且可以更改的另一个线程中。如果您使用的骆驼版本> = 2.22,则只有您可以控制消息的手动提交。要使用手动提交,请设置以下属性:
autoCommitEnable = false:关闭偏移量的自动提交,以便我们可以使用手动提交。 allowManualCommit = true:打开手动提交,使我们能够使用KafkaManualCommit功能。 下面是代码片段:
boost::lockfree::queue<std::string> message_queue;
void producer() {
//...
message_queue.push("A string to print!");
//...
}
void mexFunction( /*...*/ ) {
// ...
boost::thread producer_thread(producer);
boost::thread consumer_thread(consumer);
while(producer_thread.joinable()) {
join_for(boost::chrono::milliseconds(50));
std::string s;
while (message_queue.pop(s)) {
mexPrintf("%s\n", s.c_str());
}
}
producer_thread.join();
done = true;
consumer_thread.join();
// ...
}
2)在第二个问题中,您似乎想再次将消息放回kafka进行处理。但是从您的代码看来,您正在为消费者和生产者使用相同的终结点。当您想在kafka中生成消息时,需要指定消息中未显示的消息的“主题”,“分区”和“键”。讨论漏洞,因为您将消息再次放入kafka中,如果消息已损坏怎么办,因此您将继续获取相同的异常并将相同的消息再次放入kafka中。我建议以相同的路径重试该消息。下面是代码片段:
KafkaManualCommit manual =
exchange.getIn().getHeader(KafkaConstants.MANUAL_COMMIT, KafkaManualCommit.class);
if (manual != null) {
LOGGER.info("committing the offset manually");
manual.commitSync();
}