2
votes

I am struggling hard to find out the way for scheduled/Delaying messages in Spring AMQP/Rabbit MQ and found solution in here.But i still with a prolem about Spring AMQP/Rabbit MQ which can not received any message.

My source as the following:

@Configuration
public class AmqpConfig {

    @Bean  
    public ConnectionFactory connectionFactory() {  
        CachingConnectionFactory connectionFactory = new CachingConnectionFactory();  
        connectionFactory.setAddresses("172.16.101.14:5672");  
        connectionFactory.setUsername("admin");  
        connectionFactory.setPassword("admin"); 
        connectionFactory.setPublisherConfirms(true); 
        return connectionFactory;  
    }  


    @Bean  
    @Scope("prototype") 
    public RabbitTemplate rabbitTemplate() {  
        RabbitTemplate template = new RabbitTemplate(connectionFactory());  
        return template;  
    } 


    @Bean
    CustomExchange delayExchange() {
        Map<String, Object> args = new HashMap<String, Object>();
        args.put("x-delayed-type", "direct");
        return new CustomExchange("my-exchange", "x-delayed-message", true, false, args);
    }

    @Bean  
    public Queue queue() {  
        return new Queue("spring-boot-queue", true);   

    }  

    @Bean
    Binding binding(Queue queue, Exchange delayExchange) {
        return BindingBuilder.bind(queue).to(delayExchange).with("spring-boot-queue").noargs();
    }

    @Bean  
    public SimpleMessageListenerContainer messageContainer() {  
        SimpleMessageListenerContainer container = new SimpleMessageListenerContainer(connectionFactory());  
        container.setQueues(queue());  
        container.setExposeListenerChannel(true);  
        container.setMaxConcurrentConsumers(1);  
        container.setConcurrentConsumers(1);  
        container.setAcknowledgeMode(AcknowledgeMode.MANUAL); 

        container.setMessageListener(new ChannelAwareMessageListener() {  

            public void onMessage(Message message, Channel channel) throws Exception {  
                byte[] body = message.getBody();  
                System.err.println("receive msg : " + new String(body));  
                channel.basicAck(message.getMessageProperties().getDeliveryTag(), false); //确认消息成功消费  

            }  
        });  

        return container;  
    }  


}

@Component
public class Send implements RabbitTemplate.ConfirmCallback{

    private RabbitTemplate rabbitTemplate;  

    @Autowired  
    public Send(RabbitTemplate rabbitTemplate) {  
        this.rabbitTemplate = rabbitTemplate; 
        this.rabbitTemplate.setConfirmCallback(this);
        rabbitTemplate.setMandatory(true);
    }  

    public void sendMsg(String content) {  

        CorrelationData correlationId = new CorrelationData(UUID.randomUUID().toString()); 

        rabbitTemplate.convertAndSend("my-exchange", "", content, new MessagePostProcessor() {
            @Override
            public Message postProcessMessage(Message message) throws AmqpException {
                message.getMessageProperties().setHeader("x-delay", 6000);
                return message;
            }
        },correlationId);

        System.err.println("delay message send ................");

    }

    /**  
     * 回调  
     */  
    @Override  
    public void confirm(CorrelationData correlationData, boolean ack, String cause) {  

        System.err.println(" callback id :" + correlationData);  

        if (ack) {  
            System.err.println("ok");  
        } else {  
            System.err.println("fail:" + cause);  
        }  
    }  
}

Is there someone could give a help.

Thanks all.

1

1 Answers

2
votes

Delay messaging is nothing to do with Spring amqp, it's a library which will reside with your code, so the library can't hold any message as such. There are two approaches you can try:

Old Approach: Set the TTL(time to live) header in each message/queue(policy) and then introduce a DLQ to handle it. once the ttl expired your messages will move from DLQ to main queue so that your listener can process it.

Latest Approach: Recently RabbitMQ came up with RabbitMQ Delayed Message Plugin , using which you can achieve the same and this plugin support available since RabbitMQ-3.5.8.

You can declare an exchange with the type x-delayed-message and then publish messages with the custom header x-delay expressing in milliseconds a delay time for the message. The message will be delivered to the respective queues after x-delay milliseconds

Details: To use the delayed-messaging feature, declare an exchange with the type x-delayed-message:

Map<String, Object> args = new HashMap<String, Object>();
args.put("x-delayed-type", "direct");
channel.exchangeDeclare("my-exchange", "x-delayed-message", true, false, args);

Note that we pass an extra header called x-delayed-type, more on it under the Routing section.

Once we have the exchange declared we can publish messages providing a header telling the plugin for how long to delay our messages:

byte[] messageBodyBytes = "delayed payload".getBytes("UTF-8");
Map<String, Object> headers = new HashMap<String, Object>();
headers.put("x-delay", 5000);
AMQP.BasicProperties.Builder props = new AMQP.BasicProperties.Builder().headers(headers);
channel.basicPublish("my-exchange", "", props.build(), messageBodyBytes);

byte[] messageBodyBytes2 = "more delayed payload".getBytes("UTF-8");
Map<String, Object> headers2 = new HashMap<String, Object>();
headers2.put("x-delay", 1000);
AMQP.BasicProperties.Builder props2 = new AMQP.BasicProperties.Builder().headers(headers2);
channel.basicPublish("my-exchange", "", props2.build(), messageBodyBytes2);

In the above example we publish two messages, specifying the delay time with the x-delay header. For this example, the plugin will deliver to our queues first the message with the body "more delayed payload" and then the one with the body "delayed payload".

If the x-delay header is not present, then the plugin will proceed to route the message without delay.

More here: git