Rabbit Template确认回调不起作用

时间:2019-04-03 06:09:55

标签: spring-boot spring-amqp

我有订阅者和发布者订阅者收集邮件,一旦达到指定的邮件收集数量,它将控制权传递给发布者 我需要将消息发布到其他队列,成功发布每个消息后,我需要手动确认已订阅的队列以删除消息。 我已经使用过return回调并在Rabbit模板上确认了回调,但是在成功发布消息时未调用回调函数。

我想问题是发布者和消费者都使用相同的连接,这就是为什么不调用callback的原因,但我不确定。

    @SpringBootApplication
    @ComponentScan(basePackages={"com.comp.dftp.scrubber.configuration","com.comp.dftp.scrubber.container",
                                  "com.comp.dftp.scrubber.subscriber","com.comp.dftp.scrubber.publisher"})
    @EnableAutoConfiguration(exclude=RabbitAutoConfiguration.class)
    @EnableRabbit
    public class DftpEppScrubberApplication {

        private static final Logger LOGGER = LoggerFactory.getLogger(DftpEppScrubberApplication.class);

        RabbitListenerEndpointRegistrar registrar;

        AppConfig appConfig;

         public static void main(String[] args) {
             SpringApplication app = new SpringApplication(DftpEppScrubberApplication.class);
             ConfigurableApplicationContext appContext = app.run(args);
            }

         @PreDestroy 
          public void graceFullExit() { 
              LOGGER.info("----------- Stopping Scrubber Container--------------");
              if(registrar!= null && registrar.getEndpointRegistry() != null ) {
                  registrar.getEndpointRegistry().stop(); 
              }

              LOGGER.info("Container Stopped Sucessfully!");
              /*
               * If Application is not ready to exit safely we will weight for 30 sec
               * and re-check again, This will be continued until the flag  ReadyToGraccefullyExit
               * is set true be process which has not completed Yet, Once publisher completed the process
               * and reader ack back to publisher.
               */
              while(!appConfig.isReadyToGraccefullyExit()) {
                  try{
                      Thread.sleep(30 * 1000);
                      appConfig.setReadyToGraccefullyExit(true); /* this is just for testing*/
                  } catch (InterruptedException e) {
                    LOGGER.error("Some error in gracefully exiting the application!", e);
                }
              }
            LOGGER.info("###STOP FROM THE LIFECYCLE###");
          }
    }

```java
    @Component
    @Configuration
    public class EPPQ2ListenerConfigurer implements RabbitListenerConfigurer{

        public EPPQ2ListenerConfigurer(ConfigurableApplicationContext ctx) {
            // TODO Auto-generated constructor stub
        }

        @Override
        public void configureRabbitListeners(RabbitListenerEndpointRegistrar registrar) {
            registrar.setMessageHandlerMethodFactory(messageHandlerMethodFactory());
        }

        @Bean
        MessageHandlerMethodFactory messageHandlerMethodFactory() {
            DefaultMessageHandlerMethodFactory messageHandlerMethodFactory = new DefaultMessageHandlerMethodFactory();
            messageHandlerMethodFactory.setMessageConverter(consumerJackson2MessageConverter());
            return messageHandlerMethodFactory;
        }

        @Bean
        public MappingJackson2MessageConverter consumerJackson2MessageConverter() {
            return new MappingJackson2MessageConverter();
        }

    }

```java
    @Configuration
    public class ListenerContainerFactory {

        static final Logger logger = LoggerFactory.getLogger(ListenerContainerFactory.class);

        @Autowired
        RabbitMqConfig rabbitMqConfig;

        @Autowired
        EPPQ2Subscriber receiver;



         public ListenerContainerFactory(ConfigurableApplicationContext ctx) {
            printContainerStartMsg();
        }
        private void printContainerStartMsg() {
            logger.info("----------- Scrubber Container Starts   --------------");
        }

        @Bean
        public CachingConnectionFactory subscriberConnectionFactory() {
            CachingConnectionFactory subsCachingConnectionFactory = new CachingConnectionFactory(rabbitMqConfig.getSubscriberHosts(),
                    rabbitMqConfig.getSubscriberPort());
            subsCachingConnectionFactory.setUsername(rabbitMqConfig.getSubscriberUsername());
            subsCachingConnectionFactory.setPassword(rabbitMqConfig.getSubscriberPassword());
            subsCachingConnectionFactory.setVirtualHost("hydra.services");
            subsCachingConnectionFactory.setConnectionNameStrategy(f -> "subscriberConnection");
            return subsCachingConnectionFactory;
        }


    @Bean
    public SimpleRabbitListenerContainerFactory queueListenerContainer(
            @Qualifier("subscriberConnectionFactory") CachingConnectionFactory subscriberConnectionFactory,
            MessageListenerAdapter listenerAdapter) { 
        connectionFactory.setAddresses(rabbitMqConfig.getSubscriberHosts());
        connectionFactory.setVirtualHost("hydra.services");
        connectionFactory.setPort(rabbitMqConfig.getSubscriberPort());
        connectionFactory.setUsername(rabbitMqConfig.getSubscriberUsername());
        connectionFactory.setPassword(rabbitMqConfig.getSubscriberPassword());
        SimpleRabbitListenerContainerFactory factory = new SimpleRabbitListenerContainerFactory();
        factory.setAcknowledgeMode(AcknowledgeMode.MANUAL);
        factory.setConnectionFactory(subscriberConnectionFactory);
        factory.setErrorHandler(errorHandler());
        return factory;
    }

     @Bean
     MessageListenerAdapter listenerAdapter(EPPQ2Subscriber receiver) {
         return new MessageListenerAdapter(receiver, "receiveMessage");
     }

     @Bean
        public ErrorHandler errorHandler() {
            return new ConditionalRejectingErrorHandler(fatalExceptionStrategy());
        }

     @Bean
     public  ScrubberFatalExceptionStrategy fatalExceptionStrategy() {
         return new ScrubberFatalExceptionStrategy();
     }
}


```java
    @Component
    public class EPPQ2Subscriber {
        private static final Logger LOGGER = LoggerFactory.getLogger(EPPQ2Subscriber.class);
        //@RabbitListener(queues = "#{queue.getName()}") @TODO I wann to use this in later point in time.. !
        @Autowired
        RabbitMqConfig rabbitMqConfig;

        @Autowired
        AppConfig appConfig;

        @Autowired
        EPPQ2PublisherImpl eppQ2Publisher;

        List<Message> messageList = new ArrayList<Message>();
        List<Long> deliveryTagList = new ArrayList<Long>();
        /**
         * Method is listener's receive message method , invoked when there is message ready to read  
         * @param message - Domain object of message encapsulated 
         * @param channel - rabitmq client channel 
         * @param messageId - @TODO Delete it later.
         * @param messageProperties - amqp message properties contains message properties such as delivery tag etc..
         */
        @RabbitListener(id="messageListener",queues = "#{rabbitMqConfig.getSubscriberQueueName()}",containerFactory="queueListenerContainer")
        public void receiveMessage(Message message, Channel channel, @Header("id") String messageId, 
                MessageProperties messageProperties) {

            LOGGER.info("Result:" + message.getClass() + ":" + message.toString());
            if(messageList.size() < appConfig.getSubscriberChunkSize() ) {
                messageList.add(message);
                LOGGER.info("For Test Size:"+messageList.size()+ "chunk size : "+appConfig.getSubscriberChunkSize());
                deliveryTagList.add(messageProperties.getDeliveryTag());
            } else {
                // call the service here to decrypt, read pan, call danger to scrub, encrypt pan and re-pack them in message again.
                //after this branch messageList should have scrubbed and encrypted message objects ready to publish.

                // Here is call for publish and ack messages..
                eppQ2Publisher.sendMessages(messageList, channel, deliveryTagList);
            }

        }
    }

````java
@Configuration
public class TopicConfiguration {

    private static final Logger LOGGER = LoggerFactory.getLogger(TopicConfiguration.class);

    @Autowired
    RabbitMqConfig rabbitMqConfig;

    @Autowired 
    EPPQ2Publisher eppQ2Publisher;


     /**
     * Caching connection factory 
     * @return CachingConnectionFactory
     */
    @Bean
    public CachingConnectionFactory cachingConnectionFactory() {
        CachingConnectionFactory cachingConnectionFactory = new CachingConnectionFactory(rabbitMqConfig.getPublisherHosts(),
                rabbitMqConfig.getPublisherPort());
        cachingConnectionFactory.setUsername(rabbitMqConfig.getPublisherUsername());
        cachingConnectionFactory.setPassword(rabbitMqConfig.getPublisherPassword());
        cachingConnectionFactory.setVirtualHost("hydra.services");
        cachingConnectionFactory.createConnection();
        cachingConnectionFactory.setConnectionNameStrategy(f -> "publisherConnection");
        return cachingConnectionFactory;
    }

    /**
     * Bean RabbitTemplate
     * @return RabbitTemplate
     */
    @Bean
    public RabbitTemplate template(
            @Qualifier("cachingConnectionFactory") CachingConnectionFactory cachingConnectionFactory) {
        final RabbitTemplate rabbitTemplate = new RabbitTemplate(cachingConnectionFactory);
        rabbitTemplate.setMessageConverter(producerJackson2MessageConverter());
        RetryTemplate retryTemplate = new RetryTemplate();
        ExponentialBackOffPolicy backOffPolicy = new ExponentialBackOffPolicy();
        backOffPolicy.setInitialInterval(500);
        backOffPolicy.setMultiplier(10.0);
        backOffPolicy.setMaxInterval(10000);
        retryTemplate.setBackOffPolicy(backOffPolicy);
        rabbitTemplate.setRetryTemplate(retryTemplate);
        rabbitTemplate.setExchange(rabbitMqConfig.getPublisherTopic());
        rabbitTemplate.setUsePublisherConnection(true);
        rabbitTemplate.setMandatory(true);

        rabbitTemplate.setConfirmCallback((correlation, ack, reason) -> {
            if (correlation != null) {
                LOGGER.info("Received " + (ack ? " ack " : " nack ") + "for correlation: " + correlation);
                if (ack) {
                    // this is confirmation received..
                    // here is code to ack Q1. correlation.getId() and ack it !!
                    eppQ2Publisher.ackMessage(new Long(correlation.getId().toString()));
                } else {
                    // no confirmation received and no need to do any thing for
                    // retry..
                }
            }

        });
        rabbitTemplate.setReturnCallback((message, replyCode, replyText, exchange, routingKey) -> {
            LOGGER.error("Returned: " + message + "\nreplyCode: " + replyCode + "\nreplyText: " + replyText
                    + "\nexchange/rk: " + exchange + "/" + routingKey);
        });
        return rabbitTemplate;
    }

    /**
     * Bean Jackson2JsonMessageConverter
     * @return Jackson2JsonMessageConverter
     */
    @Bean
    public Jackson2JsonMessageConverter producerJackson2MessageConverter() {
        return new Jackson2JsonMessageConverter();
    }

}



Here is some logs


----------
33morg.springframework.amqp.rabbit.listener.BlockingQueueConsumer[0;39m: Received message: (Body:'[B@1c63ef5(byte[2003])' MessageProperties [headers={}, contentLength=0, receivedDeliveryMode=NON_PERSISTENT, redelivered=true, receivedExchange=, receivedRoutingKey=hydra.Syphon.q1, deliveryTag=11, consumerTag=amq.ctag-VLCSea_a-FmED6I54TyM4w, consumerQueue=hydra.Syphon.q1])
SimpleAsyncTaskExecutor-1 org.springframework.amqp.rabbit.listener.adapter.MessagingMessageListenerAdapter[0;39m: Processing [GenericMessage [payload=byte[2003], headers={amqp_receivedDeliveryMode=NON_PERSISTENT, amqp_receivedRoutingKey=hydra.Syphon.q1, amqp_deliveryTag=11, amqp_consumerQueue=hydra.Syphon.q1, amqp_redelivered=true, id=2a24ec32-2576-a208-4cbf-f36e6170ac83, amqp_consumerTag=amq.ctag-VLCSea_a-FmED6I54TyM4w, timestamp=1554262675707}]]
SimpleAsyncTaskExecutor-1 com.discover.dftp.scrubber.subscriber.EPPQ2Subscriber[0;39m: Result:class com.discover.dftp.scrubber.domain.Message:Header [header={RETRY_COUNT=0, PUBLISH_EVENT_TYPE=AUTH}, payLoad={MTI=400, MTI_REQUEST=400, PAN=6011000000000000, PROCCODE=00, PROCCODE_REQUEST=00, FROM_ACCOUNT=00, TO_ACCOUNT=00, TRANSACTION_AMOUNT=000000000100, TRANSMISSION_MMDDHHMMSS=0518202930, STAN=000001, LOCALTIME_HHMMSS=010054, LOCALDATE_YYMMDD=180522, MERCHANT_TYPE=5311, ACQUIRING_COUNTRY_CODE=840, POS_ENTRY_MODE=02, POS_PIN_ENTRY_CAPABILITIES=0, FUNCTION_CODE=400, MESSAGE_REASON_CODE=06, ACQUIRING_ID_CODE=000000, FORWARDING_ID_CODE=000000, RETRIEVAL_REFERENCE_NUMBER=1646N472D597, APPROVAL_CODE=12345R, RESPONSE_CODE=00, MERCHANT_NUMBER=601100000000596, CARD_ACCEPTOR_NAME=Discover Acq Simulator, CARD_ACCEPTOR_CITY=Riverwoods, CARD_ACCEPTOR_STATE=IL, CARD_ACCEPTOR_COUNTRY=840, CARD_ACCEPTOR_COUNTRY_3NUMERIC=840, NRID=123456789012345, TRANSACTION_CURRENCY_CODE=840, POS_TERMINAL_ATTENDANCE_INDICATOR=0, POS_PARTIAL_APPROVAL_INDICATOR=0, POS_TERMINAL_LOCATION_INDICATOR=0, POS_TRANSACTION_STATUS_INDICATOR=0, POS_ECOMMERCE_TRAN_INDICATOR=0, POS_TYPE_OF_TERMINAL_DEVICE=0, POS_CARD_PRESENCE_INDICATOR=0, POS_CARD_CAPTURE_CAPABILITIES_INDICATOR=1, POS_TRANSACTION_SECURITY_INDICATOR=0, POS_CARD_DATA_TERMINAL_INPUT_CAPABILITY_INDICATOR=2, POS_CARDHOLDER_PRESENCE_INDICATOR=0, DFS_POS_DATA=0000010000200, GEODATA_STREET_ADDRESS=2500 LAKE COOK ROAD   , GEODATA_POSTAL_CODE=600150000, GEODATA_COUNTY_CODE=840, GEODATA_STORE_NUMBER=10001, GEODATA_MALL_NAME=DISCOVER FINANCIAL SR, VERSION_INDICATOR=03141, REVERSAL_FLAG=Y, ISS_REFERENCE_ID=72967956, ISS_PROCESSOR_REFERENCE_ID=123459875}]
SimpleAsyncTaskExecutor-1 org.springframework.retry.support.RetryTemplate[0;39m: Retry: count=0
SimpleAsyncTaskExecutor-1 org.springframework.amqp.rabbit.core.RabbitTemplate[0;39m: Executing callback RabbitTemplate$$Lambda$268/19900766 on RabbitMQ Channel: Cached Rabbit Channel: AMQChannel(amqp://dftp_publisher@10.15.190.18:5672/hydra.services,1), conn: Proxy@10fa93b Shared Rabbit Connection: SimpleConnection@6329d2 [delegate=amqp://dftp_publisher@10.15.190.18:5672/hydra.services, localPort= 62375]
SimpleAsyncTaskExecutor-1 org.springframework.amqp.rabbit.core.RabbitTemplate[0;39m: Publishing message (Body:'{"HEADER":{"RETRY_COUNT":0,"PUBLISH_EVENT_TYPE":"AUTH"},"PAYLOAD":{"MTI":"400","MTI_REQUEST":"400","PAN":"6011000000000000","PROCCODE":"00","PROCCODE_REQUEST":"00","FROM_ACCOUNT":"00","TO_ACCOUNT":"00","TRANSACTION_AMOUNT":"000000000100","TRANSMISSION_MMDDHHMMSS":"0518202930","STAN":"000001","LOCALTIME_HHMMSS":"010054","LOCALDATE_YYMMDD":"180522","MERCHANT_TYPE":"5311","ACQUIRING_COUNTRY_CODE":"840","POS_ENTRY_MODE":"02","POS_PIN_ENTRY_CAPABILITIES":"0","FUNCTION_CODE":"400","MESSAGE_REASON_CODE":"06","ACQUIRING_ID_CODE":"000000","FORWARDING_ID_CODE":"000000","RETRIEVAL_REFERENCE_NUMBER":"1646N472D597","APPROVAL_CODE":"12345R","RESPONSE_CODE":"00","MERCHANT_NUMBER":"601100000000596","CARD_ACCEPTOR_NAME":"Discover Acq Simulator","CARD_ACCEPTOR_CITY":"Riverwoods","CARD_ACCEPTOR_STATE":"IL","CARD_ACCEPTOR_COUNTRY":"840","CARD_ACCEPTOR_COUNTRY_3NUMERIC":"840","NRID":"123456789012345","TRANSACTION_CURRENCY_CODE":"840","POS_TERMINAL_ATTENDANCE_INDICATOR":"0","POS_PARTIAL_APPROVAL_INDICATOR":"0","POS_TERMINAL_LOCATION_INDICATOR":"0","POS_TRANSACTION_STATUS_INDICATOR":"0","POS_ECOMMERCE_TRAN_INDICATOR":"0","POS_TYPE_OF_TERMINAL_DEVICE":"0","POS_CARD_PRESENCE_INDICATOR":"0","POS_CARD_CAPTURE_CAPABILITIES_INDICATOR":"1","POS_TRANSACTION_SECURITY_INDICATOR":"0","POS_CARD_DATA_TERMINAL_INPUT_CAPABILITY_INDICATOR":"2","POS_CARDHOLDER_PRESENCE_INDICATOR":"0","DFS_POS_DATA":"0000010000200","GEODATA_STREET_ADDRESS":"2500 LAKE COOK ROAD   ","GEODATA_POSTAL_CODE":"600150000","GEODATA_COUNTY_CODE":"840","GEODATA_STORE_NUMBER":"10001","GEODATA_MALL_NAME":"DISCOVER FINANCIAL SR","VERSION_INDICATOR":"03141","REVERSAL_FLAG":"Y","ISS_REFERENCE_ID":"72967956","ISS_PROCESSOR_REFERENCE_ID":"123459875"}}' MessageProperties [headers={__TypeId__=com.discover.dftp.scrubber.domain.Message}, contentType=application/json, contentEncoding=UTF-8, contentLength=1705, deliveryMode=PERSISTENT, priority=0, deliveryTag=0])on exchange [hydra.test.exc], routingKey = [800]
SimpleAsyncTaskExecutor-1 org.springframework.retry.support.RetryTemplate[0;39m: Retry: count=0
SimpleAsyncTaskExecutor-1 org.springframework.amqp.rabbit.core.RabbitTemplate[0;39m: Executing callback RabbitTemplate$$Lambda$268/19900766 on RabbitMQ Channel: Cached Rabbit Channel: AMQChannel(amqp://dftp_publisher@10.15.190.18:5672/hydra.services,1), conn: Proxy@10fa93b Shared Rabbit Connection: SimpleConnection@6329d2 [delegate=amqp://dftp_publisher@10.15.190.18:5672/hydra.services, localPort= 62375]
SimpleAsyncTaskExecutor-1 org.springframework.amqp.rabbit.core.RabbitTemplate[0;39m: Publishing message (Body:'{"HEADER":{"RETRY_COUNT":0,"PUBLISH_EVENT_TYPE":"AUTH"},"PAYLOAD":{"MTI":"400","MTI_REQUEST":"400","PAN":"6011000000000000","PROCCODE":"00","PROCCODE_REQUEST":"00","FROM_ACCOUNT":"00","TO_ACCOUNT":"00","TRANSACTION_AMOUNT":"000000000100","TRANSMISSION_MMDDHHMMSS":"0518202930","STAN":"000001","LOCALTIME_HHMMSS":"010054","LOCALDATE_YYMMDD":"180522","MERCHANT_TYPE":"5311","ACQUIRING_COUNTRY_CODE":"840","POS_ENTRY_MODE":"02","POS_PIN_ENTRY_CAPABILITIES":"0","FUNCTION_CODE":"400","MESSAGE_REASON_CODE":"06","ACQUIRING_ID_CODE":"000000","FORWARDING_ID_CODE":"000000","RETRIEVAL_REFERENCE_NUMBER":"1646N472D597","APPROVAL_CODE":"12345R","RESPONSE_CODE":"00","MERCHANT_NUMBER":"601100000000596","CARD_ACCEPTOR_NAME":"Discover Acq Simulator","CARD_ACCEPTOR_CITY":"Riverwoods","CARD_ACCEPTOR_STATE":"IL","CARD_ACCEPTOR_COUNTRY":"840","CARD_ACCEPTOR_COUNTRY_3NUMERIC":"840","NRID":"123456789012345","TRANSACTION_CURRENCY_CODE":"840","POS_TERMINAL_ATTENDANCE_INDICATOR":"0","POS_PARTIAL_APPROVAL_INDICATOR":"0","POS_TERMINAL_LOCATION_INDICATOR":"0","POS_TRANSACTION_STATUS_INDICATOR":"0","POS_ECOMMERCE_TRAN_INDICATOR":"0","POS_TYPE_OF_TERMINAL_DEVICE":"0","POS_CARD_PRESENCE_INDICATOR":"0","POS_CARD_CAPTURE_CAPABILITIES_INDICATOR":"1","POS_TRANSACTION_SECURITY_INDICATOR":"0","POS_CARD_DATA_TERMINAL_INPUT_CAPABILITY_INDICATOR":"2","POS_CARDHOLDER_PRESENCE_INDICATOR":"0","DFS_POS_DATA":"0000010000200","GEODATA_STREET_ADDRESS":"2500 LAKE COOK ROAD   ","GEODATA_POSTAL_CODE":"600150000","GEODATA_COUNTY_CODE":"840","GEODATA_STORE_NUMBER":"10001","GEODATA_MALL_NAME":"DISCOVER FINANCIAL SR","VERSION_INDICATOR":"03141","REVERSAL_FLAG":"Y","ISS_REFERENCE_ID":"72967956","ISS_PROCESSOR_REFERENCE_ID":"123459875"}}' MessageProperties [headers={__TypeId__=com.discover.dftp.scrubber.domain.Message}, contentType=application/json, contentEncoding=UTF-8, contentLength=1705, deliveryMode=PERSISTENT, priority=0, deliveryTag=0])on exchange [hydra.test.exc], routingKey = [800]

2 个答案:

答案 0 :(得分:1)

您需要在var totalItems = $('.carousel-item').length; var currentIndex = $('.carousel-item.active').index() + 1; var down_index; $('.num').html(''+currentIndex+'/'+totalItems+''); $(".next").click(function(){ currentIndex_active = $('.carousel-item.active').index() + 2; if (totalItems >= currentIndex_active) { down_index= $('.carousel-item.active').index() + 2; $('.num').html(''+currentIndex_active+'/'+totalItems+''); } }); 配置中启用退货和确认。参见the documentation

  

此功能要求CachingConnectionFactory的PublisherReturns属性设置为true(请参阅发布者确认和返回)。

     

...

     

对于发布者确认(也称为发布者确认),模板需要一个CachingConnectionFactory,且其PublisherConfirm属性设置为true。

答案 1 :(得分:0)

按照@Gary Russell 的回答,我在我的代码中添加了下面的配置,然后 ConfirmCallback 开始工作。我使用 SpringBoot 2.5.2 和 RabbitMQ 3.8.18

cachingConnectionFactory.setPublisherReturns(true);
cachingConnectionFactory.setPublisherConfirmType(CachingConnectionFactory.ConfirmType.CORRELATED);

Rabbitmq-Batch-Rabbitmq-Publish-Subscribe