我正在做类似
的事情 from(rabbitmq:pollingQueue?prefetchSize=1&concurrentConsumer=10)
.process(pollingRequestStatus) // check status of the request, if not ready, requeue = true
.Choice
.when(requeue == true) // request not ready
.to(rabbitmq:pollingQueue)//back to the same queue
.endChoice
.otherwise
.to(proceedToSomethingElse)
.endChoice.end;
当重新发生重新排队时,消息会重复,这是将消息发送回同一队列时的预期行为吗?
我也按照建议尝试了类似下面的内容,但它不起作用,消息似乎只是被消耗而且不会重新排队
from(rabbitmq:pollingQueue? prefetchSize=1&concurrentConsumer=10)
.onException(NotReadyException.class)
.handled(true)
.setHeader(RabbitMQConstants.REQUEUE, constant(true))
.end()
.process(pollingRequestStatus) // check status of the request, if not ready, throw NotReadyEception
.to(proceedToSomethingElse);
我试过的另外两种方法至少不会产生重复,
1。)在NotReadyExeption上,将消息发送回pollingQueue
from(rabbitmq:pollingQueue? prefetchSize=1&concurrentConsumer=10)
.onException(NotReadyException.class)
.to(rabbitmq:pollingQueue)
//.delay(constant(8000)) //not sure why it throws error if i set delay
.end
.process(pollingRequestStatus); // check status of the request, if not ready, throw NotReadyEception
然而,它的运行速度太快,就像瞬间一样。 如果我设置延迟(常数(数字)),则抛出以下错误,
Exception in thread "main" org.apache.camel.FailedToCreateRouteException: Failed to create route route13 at: >>> From [bla bla bla...]
at org.apache.camel.model.RouteDefinition.addRoutes(RouteDefinition.java:1062)
at org.apache.camel.model.RouteDefinition.addRoutes(RouteDefinition.java:196)
at org.apache.camel.impl.DefaultCamelContext.startRoute(DefaultCamelContext.java:984)
at org.apache.camel.impl.DefaultCamelContext.startRouteDefinitions(DefaultCamelContext.java:3401)
at org.apache.camel.impl.DefaultCamelContext.doStartCamel(DefaultCamelContext.java:3132)
at org.apache.camel.impl.DefaultCamelContext.access$000(DefaultCamelContext.java:183)
at org.apache.camel.impl.DefaultCamelContext$2.call(DefaultCamelContext.java:2961)
at org.apache.camel.impl.DefaultCamelContext$2.call(DefaultCamelContext.java:2957)
at org.apache.camel.impl.DefaultCamelContext.doWithDefinedClassLoader(DefaultCamelContext.java:2980)
at org.apache.camel.impl.DefaultCamelContext.doStart(DefaultCamelContext.java:2957)
at org.apache.camel.support.ServiceSupport.start(ServiceSupport.java:61)
at org.apache.camel.impl.DefaultCamelContext.start(DefaultCamelContext.java:2924)
at com.mbww.ithink.runner.Main.main(Main.java:174)
Caused by: java.lang.IllegalArgumentException: Route route13 has no output processors. You need to add outputs to the route such as to("log:foo").
at org.apache.camel.model.RouteDefinition.addRoutes(RouteDefinition.java:1060)
2.。)在NotReadyException上,基于redeliveryPolicy的重新发送
from(rabbitmq:pollingQueue? prefetchSize=1&concurrentConsumer=10)
.onException(NotReadyException.class)
.setFaultBody(constant(false))
.maximumRedeliveries(-1) // -1 = redeliver forever
.redeliveryDelay(10000)
.end
.process(pollingRequestStatus); // check status of the request, if not ready, throw NotReadyEception
最初重新排队的想法是,如果请求没有准备就绪,请将消息重新排队回队列,设置延迟并检查下一个请求的状态,并避免出现像Ratelimit这样的错误。 似乎重新交付政策是现在的方式。
由于
答案 0 :(得分:4)
为了能够重新排列消息,您必须关闭RabbitMQ的自动确认。在这种情况下,您必须手动将ack
,nack
或reject
消息发送回发布商。 (https://www.rabbitmq.com/confirms.html)
这意味着您必须在当前basicAck
实施中手动调用其中一个basicNack
,basicReject
或Channel
函数。
要启用自动确认功能,请将autoAck=false
添加到端点参数。
AFAIK,Camel Endpoint的底层频道无法访问(source),因此您无法直接调用频道的basicReject(long deliveryTag, boolean requeue)
功能,但Camel会在交换失败时调用它(在此期间发生异常)路由)。
解决方法可能如下:(伪编码,我没有尝试过,但是基于检查camel-rabbitmq
端点的来源,特别是this部分)
from("rabbitmq://localhost:5672/first?queue=test&concurrentConsumers=10prefetchSize=1&autoAck=false&autoDelete=false")
.onException(NotReadyException.class)
.log("Error for ${body}! Requeue")
.asyncDelayedRedelivery().redeliveryDelay(5000) // wait 5 secs to redeliver and requeue
.maximumRedeliveries(1)
.setHeader(RabbitMQConstants.REQUEUE, constant(true))
.handled(true)
.setFaultBody(constant(true))
.end()
.log("Received: ${body}")
.process((e) -> {
if(notReady(e))
throw new NotReadyException(); // create a new Exception and throw it if the status is not ready
}
})
.to("direct:somethingElse");
我还创建了一个gist,它实现了几乎相同的场景。 希望它有所帮助!
答案 1 :(得分:0)
您不需要再次发送消息,只需将rabbitmq.REQUEUE属性设置为true即可。如果设置了此属性,rabbitmq组件将自动重新排队消息而不是丢弃它。来自the docs:
Camel 2.14.2:消费者使用它来控制拒绝 信息。当消费者完成处理交换时,如果 交换失败,然后消费者将拒绝该消息 来自RabbitMQ经纪人。此标头的值控制了这一点 行为。如果值为false(默认情况下),则消息为 丢弃/死字母。如果值为true,则消息为 重新排队。
因此,在处理器内部,您可以执行以下操作:
exchange.getIn().setHeader("rabbitmq.REQUEUE", true);
然后在您的路线中检查REQUEUE header == false以致电proceedToSomethingElse
。