使用Grails 3.3.2 w/rabbitmq本机插件(3.4.4),prefetch=1的单个使用者在异常发生后停止使用消息
我已将重试设置为true。我的理解是,信息应该不断地反复传递给消费者。相反,它只是坐在那里,不使用重新查询的消息或任何新消息。我一路打开com.budjb、com.rabbitmq和org.springframework.amqp的日志进行跟踪,没有发现任何断开连接的情况。。。Heeelpp application.groovy使用Grails 3.3.2 w/rabbitmq本机插件(3.4.4),prefetch=1的单个使用者在异常发生后停止使用消息,grails,rabbitmq,grails3,grails-plugin-rabbitmq,Grails,Rabbitmq,Grails3,Grails Plugin Rabbitmq,我已将重试设置为true。我的理解是,信息应该不断地反复传递给消费者。相反,它只是坐在那里,不使用重新查询的消息或任何新消息。我一路打开com.budjb、com.rabbitmq和org.springframework.amqp的日志进行跟踪,没有发现任何断开连接的情况。。。Heeelpp application.groovy rabbitmq { uri = new URI(System.env.CLOUDAMQP_URL ?: "amqp://test:test@localhost/tes
rabbitmq {
uri = new URI(System.env.CLOUDAMQP_URL ?: "amqp://test:test@localhost/test")
username = uri.userInfo.split(":")[0]
password = uri.userInfo.split(":")[1]
connections = [
[name : 'main',
host : uri.host,
port : 5672,
username : username,
requestedHeartbeat: 10,
automaticReconnect: true,
virtualHost : uri.path.substring(1), //remove leading slash
password : password]
]
queues = [[name: com.coco.jms.RabbitQueues.INDEX_TRANSACTION.destinationName, autoDelete: false, durable: true, exclusive: false]]
消费者:
class IndexTransactionConsumer implements MessageConsumerEventHandler {
static rabbitConfig = [
connection: 'main',
consumers : 1,
queue : Boolean.valueOf((String) System.getProperty("is_amqp_consumer")) ? RabbitQueues.INDEX_TRANSACTION.destinationName : null,
transacted: true,
autoAck : AutoAck.POST,
retry : true
]
def handleMessage(Map body, MessageContext messageContext) {
log.info("RABBITMQ - *CONSUME* Received event to index transaction (Map). " + body)
throw new Exception("Force fail")
}
....
}
更新
当transact=true且autoAck=autoAck.POST时,在AbstractConsumerContext.groovy内部激发的txRollback()似乎正在阻止BasicObject nack到达RabbitMQ服务器
if (configuration.getTransacted()) {
context.getChannel().txRollback()
}
if (configuration.getAutoAck() == AutoAck.POST) {
context.getChannel().basicReject(context.getEnvelope().deliveryTag, configuration.getRetry())
}
我通过不允许异常逃逸侦听器和自己管理ack/nack来解决我的问题。我认为rabbitmq本机插件中有一个很大的漏洞,transact=true。在我看来,它就像是在回滚假设在捕获异常时触发的nack
def handleMessage(Map body, MessageContext context) {
log.info("RABBITMQ - *CONSUME* Received event. " + body)
try {
//ensure casting by JMS to Integer is reverted
body.conflictIDList = body.conflictIDList.collect { ((Number) it).toLong() }
//do work
context.channel.basicAck(context.envelope.deliveryTag, false)
} catch (Exception ex) {
ConsumerUtility.handleMessageException(rabbitMessagePublisher, body, context, ex)
}
}
从消费主义
def
static handleMessageException(RabbitMessagePublisher rabbitMessagePublisher, Map body, MessageContext context, Throwable ex) {
log.warn("E_ception caught attempting digest message sent to " + context.envelope.routingKey + ". body=" + body + ", reason=" + ex.message)
if (body.retryCount < 3) {
//pull current message off queue, sleep thread and republish onto back of queue
context.channel.basicAck(context.envelope.deliveryTag, false)
body.retryCount = body.retryCount + 1
//upon failure sleep for 3, 6, then 9 seconds
sleep(3000 * (Integer) body.retryCount)
rabbitMessagePublisher.send {
channel = context.channel
routingKey = context.envelope.routingKey
setBody(body)
}
} else {
log.error("Rejecting message after three failed tries onto DLQ. body=" + body, ex)
context.channel.basicReject(context.envelope.deliveryTag, false)
}
}
def
静态handleMessageException(RabbitMessagePublisher RabbitMessagePublisher,映射体,MessageContext上下文,Throwable ex){
log.warn(“试图将摘要消息发送到“+context.envelope.routingKey+”.body=“+body+”,reason=“+ex.message”)时被捕获)
如果(body.retryCount<3){
//将当前消息从队列中拉出,休眠线程并重新发布到队列的后面
context.channel.basicAck(context.envelope.deliveryTag,false)
body.retryCount=body.retryCount+1
//故障时,睡眠3、6、9秒
睡眠(3000*(整数)body.retryCount)
rabbitMessagePublisher.send{
channel=context.channel
routingKey=context.envelope.routingKey
立根盒体
}
}否则{
log.error(“在DLQ.body=“+body,ex”上尝试三次失败后拒绝消息)
context.channel.basicRequest(context.envelope.deliveryTag,false)
}
}
来自rabbitmq java客户端文档:“注意,确认实际上被发送到代理,然后被事务回滚取消”。。。苏欧。。。。如果通道的事务已经标记为回滚,那么BasicRequest调用如何影响代理。。。?