项目背景:
前一阶段接到一个需求,是工作移交,设置好移交时间段之后,到结束时间需要将工作返回给移交之前的人。
刚开始设计了三种方案
- 定时任务,缺点:实时性不高,高可用的话定时任务是一个要解决的问题,qurazt 和 阿里开源的两种方案这里就不详细展开
- 基于工作流:工作流有一个时间边界时间到时间之后会执行下一个节点,缺点:耦合性太高,需要修改工作流的流程图
- RabbitMQ:延迟插件 (最后采用的方案)
1.MQ安装延迟插件:
在rabbitmq 3.5.7及以上的版本提供了一个插件(rabbitmq-delayed-message-exchange)来实现延迟队列功能。同时插件依赖Erlang/OPT 18.0及以上。
插件下载地址: http://www.rabbitmq.com/community-plugins.html
在 rabbitmq_delayed_message_exchange 一栏中选择,根据自己RabbitMQ的版本下载适合自己版本的插件,将插件放在RabbitMQ安装目录下plugins目录中,将名字改为: rabbitmq_delayed_message_exchange-0.0.1.ez
或 rabbitmq_delayed_message_exchange-3.7.7.ez (我的版本是3.7.7) 。
关闭RabbitMQ服务,打开命令窗口,到sbin目录中, 执行命令:(根据自己的安装目录调整)
"{RabbitMQ 安装目录}\sbin\rabbitmq-plugins.bat" enable rabbitmq_delayed_message_exchange
然后再开启服务。 OK,环境配置完成。
2.Spring Boot 结合RabbitMQ
- 添加依赖
<!--mq--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-amqp</artifactId> </dependency>
- 在applicaion.yml中添加参数
rabbitmq: host: 127.0.0.1 port: 5672 username: guest password: guest virtual-host: / connection-timeout: 15000
-
通过@Configuration创建MQ连接
import lombok.extern.slf4j.Slf4j; import org.springframework.amqp.rabbit.connection.CachingConnectionFactory; import org.springframework.amqp.rabbit.connection.ConnectionFactory; import org.springframework.amqp.rabbit.core.RabbitTemplate; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Scope; /** * @Author: dushiyu * @Date: 2019-04-17 17:37 * @Version 1.0 */ @Slf4j @Configuration public class RabbitMqConfig { @Value("${spring.rabbitmq.host}") private String host; @Value("${spring.rabbitmq.port}") private int port; @Value("${spring.rabbitmq.username}") private String userName; @Value("${spring.rabbitmq.password}") private String password; @Bean public ConnectionFactory connectionFactory(){ log.info("当前链接RabbitMQ HOST:================>{} ",host); CachingConnectionFactory cachingConnectionFactory = new CachingConnectionFactory(host,port); cachingConnectionFactory.setUsername(userName); cachingConnectionFactory.setPassword(password); cachingConnectionFactory.setVirtualHost("/"); cachingConnectionFactory.setPublisherConfirms(true); cachingConnectionFactory.setChannelCacheSize(100); cachingConnectionFactory.setRequestedHeartBeat(1000); return cachingConnectionFactory; } }
-
通过@Configuration创建Exchange、Routing、Queue
import com.jdf.dfp.taskworker.common.TaskWorkerConstants; import org.springframework.amqp.core.*; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import java.util.HashMap; import java.util.Map; /** * @author dushiyu */ @Configuration public class QueueConfig { @Bean public CustomExchange taskExchange() { //x-consistent-hash Map<String, Object> args = new HashMap<>(); args.put("x-delayed-type", "direct"); //创建延迟队列的必要参数 return new CustomExchange(TaskWorkerConstants.TASK_WORK_EXCHANGE, "x-delayed-message",true, false,args); } @Bean public Queue taskQueue() { Queue queue = new Queue(TaskWorkerConstants.TASK_WORK_QUEUE, true); return queue; } @Bean public Binding taskBinding() { return BindingBuilder.bind(taskQueue()).to(taskExchange()).with(TaskWorkerConstants.TASK_WORK_ROUTING).noargs(); } }