簡體   English   中英

Spring rabbitmq 如何在錯誤處理程序上手動確認,在拋出特定所需的異常時,只有在確認設置為 AUTO 時才會確認

[英]Spring rabbitmq how to do manually ack on Error handler , On throwing specific required exception, it only ack when Acknowledge is set to AUTO

我們正在使用 Spring rabbitmq 進行項目。 而目前對於監聽器,我們使用的是確認模式來手動。 在這種情況下,當發生異常時,我們無法向 rabbitMQ 發送確認。

我們的代碼是:包 com.highq.listener;

import java.io.IOException;
import org.springframework.amqp.core.AcknowledgeMode;
import org.springframework.amqp.core.Queue;
import org.springframework.amqp.rabbit.annotation.EnableRabbit;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.amqp.rabbit.config.DirectRabbitListenerContainerFactory;
import org.springframework.amqp.rabbit.connection.ConnectionFactory;
import org.springframework.amqp.rabbit.core.RabbitAdmin;
import org.springframework.amqp.rabbit.listener.RabbitListenerEndpoint;
import org.springframework.amqp.support.AmqpHeaders;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.messaging.handler.annotation.Header;
import org.springframework.util.ErrorHandler;
import com.highq.workflow.helper.RuleEngine;
import com.rabbitmq.client.Channel;
import lombok.extern.slf4j.Slf4j;

/**
 * The Class RabbitMQListenerConfig.
 */
@Configuration
@Slf4j
@EnableRabbit
public class RabbitMQListenerConfig
{

    /** The rule engine. */
    @Autowired
    RuleEngine ruleEngine;

    private RabbitAdmin currentQueueAdmin = null;

    public RabbitAdmin getRabbitAdmin()
    {
        return currentQueueAdmin;
    }

    /**
     * This method will listen message from rabbitmq.
     *
     * @param message the message
     * @param channel - Channel created for particular listener
     * @param queue - Specified queue to which this listener will listen message
     * @param deliveryTag - Delivery Tag to be used when sending acknowledgement
     * @throws IOException - Exception in case of sending acknowledgement
     */
    @RabbitListener(queues = "${queue.name}")
    public void listen(byte[] msg, Channel channel, @Header(AmqpHeaders.CONSUMER_QUEUE) String queue, @Header(AmqpHeaders.DELIVERY_TAG) long deliveryTag) throws IOException
    {
        try
        {
            String message = new String(msg, "UTF-8");
            log.info(message);
            ruleEngine.evaluateRule(message);
        }
        catch (Exception e)
        {
            log.error(e.toString());
            log.error(e.getMessage(), e);
        }
        finally
        {
            channel.basicAck(deliveryTag, false);
        }

    }

    /**
     * Error handler.
     *
     * @return the error handler
     */
    @Bean
    public ErrorHandler errorHandler()
    {
        return new RabbitExceptionHandler(new RabbitFatalExceptionStrategy(), this.currentQueueAdmin);
    }

    /**
     * Bean will create from this with given name.
     *
     * @param name - Queue name- will be instance id
     * @return the queue
     */
    @Bean
    public Queue queue(@Value("${queue.name}") String name)
    {
        return new Queue(name);
    }

    /**
     * Rabbit listener container factory.
     *
     * @param connectionFactory the connection factory
     * @return the direct rabbit listener container factory
     */
    @Bean
    public DirectRabbitListenerContainerFactory rabbitListenerContainerFactory(ConnectionFactory connectionFactory)
    {
        DirectRabbitListenerContainerFactory factory = new DirectRabbitListenerContainerFactory();
        factory.setPrefetchCount(1);
        factory.setAcknowledgeMode(AcknowledgeMode.MANUAL);
        factory.setConnectionFactory(connectionFactory);
        factory.setErrorHandler(errorHandler());
        return factory;
    }

    @Bean
    public RabbitListenerAroundAdvice rabbitListenerAroundAdvice()
    {
        return new RabbitListenerAroundAdvice();
    }

    /**
     * RabbitAdmin Instance will be created which is required to create new Queue.
     *
     * @param cf - Connection factory
     * @return the rabbit admin
     */
    @Bean
    public RabbitAdmin admin(ConnectionFactory cf)
    {
        this.currentQueueAdmin = new RabbitAdmin(cf);
        return this.currentQueueAdmin;
    }

}

@Slf4j 公共類 RabbitExceptionHandler 擴展 ConditionalRejectingErrorHandler { private RabbitAdmin rabbitAdmin;

public RabbitExceptionHandler()
{
    super();
}

/**
 * Create a handler with the supplied {@link FatalExceptionStrategy} implementation.
 * 
 * @param exceptionStrategy The strategy implementation.
 */
public RabbitExceptionHandler(FatalExceptionStrategy exceptionStrategy, RabbitAdmin rabbitAdmin)
{
    super(exceptionStrategy);
    this.rabbitAdmin = rabbitAdmin;
}

@Override
public void handleError(Throwable t)
{
    try
    {
        super.handleError(t);
    }
    catch (Exception e)
    {
        if (e instanceof AmqpRejectAndDontRequeueException)
        {
            Throwable t1 = new Throwable("Some message", e.getCause());
            log.error(e.getMessage(), e);
            ImmediateAcknowledgeAmqpException newAmqp = new ImmediateAcknowledgeAmqpException("Some message", t1);
            throw newAmqp;
        }
    }
}

}

package com.highq.listener;

import org.springframework.amqp.rabbit.connection.ConnectionFactory;
import org.springframework.amqp.rabbit.connection.ConnectionFactoryUtils;
import org.springframework.amqp.rabbit.listener.ConditionalRejectingErrorHandler;
import org.springframework.amqp.rabbit.listener.exception.ListenerExecutionFailedException;
import com.rabbitmq.client.Channel;
import lombok.extern.slf4j.Slf4j;

/**
 * The Class RabbitFatalExceptionStrategy.
 */
@Slf4j
public class RabbitFatalExceptionStrategy extends ConditionalRejectingErrorHandler.DefaultExceptionStrategy
{

    /*
     * (non-Javadoc)
     * @see org.springframework.amqp.rabbit.listener.ConditionalRejectingErrorHandler.DefaultExceptionStrategy#isFatal(java.lang.Throwable)
     */
    @Override
    public boolean isFatal(Throwable t)
    {
        boolean finalResult = super.isFatal(t);
        if (t instanceof ListenerExecutionFailedException)
        {
            ListenerExecutionFailedException lefe = (ListenerExecutionFailedException) t;

            lefe.getFailedMessage().getMessageProperties().getDeliveryTag());
            log.error("\n   Error occured while handling message with Queue named : "
                    + 
            lefe.getFailedMessage().getMessageProperties().getConsumerQueue() + "   Message not processed is FATAL or NOT : " + finalResult
                    + ";\n  Failed message: " + lefe.getFailedMessage());
        }
        if (!log.isWarnEnabled() || !finalResult)
        {
            log.error(t.getMessage(), t);
        }
        return true;
    }

}

在上面的例子中,我們沒有在異常處理程序中的任何地方獲取通道,所以我們如何在異常發生時手動確認。

你不能; 使用手動確認時,所有確認邏輯都需要在偵聽器中。

很少使用手動確認,因為容器通常提供您需要的所有靈活性 AUTO。

需要使用 MANUAL acks 的用例是什么?

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM