├── .gitignore ├── README.md ├── pom.xml └── src ├── main ├── java │ └── com │ │ └── joy │ │ ├── DelayQueueApplication.java │ │ ├── config │ │ ├── QueueConfiguration.java │ │ └── WaitQueueConfig.java │ │ ├── entity │ │ └── WaitQueueInfo.java │ │ └── queue │ │ ├── AbstractWaitQueueExecutor.java │ │ ├── DefaultWaitQueueExecutor.java │ │ ├── WaitQueueExecutor.java │ │ ├── WaitQueueProvider.java │ │ └── impl │ │ └── WaitQueueProviderImpl.java └── resources │ ├── application.yml │ └── logback-spring.xml └── test └── java └── com └── joy └── DelayQueueApplicationTest.java /.gitignore: -------------------------------------------------------------------------------- 1 | .idea 2 | target -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 基于Redis实现延时队列 2 | 3 | ## 集成方式 4 | 5 | ### 1、实现`com.joy.queue.AbstractWaitQueueExecutor` 6 | 7 | ```java 8 | 9 | @Setter 10 | @Getter 11 | @Slf4j 12 | @Component 13 | public class DefaultWaitQueueExecutor extends AbstractWaitQueueExecutor { 14 | 15 | private BiFunction consumer; 16 | 17 | public DefaultWaitQueueExecutor(ThreadPoolTaskExecutor taskExecutor) { 18 | super(taskExecutor); 19 | } 20 | 21 | @Override 22 | public boolean processByQueueName(String queueName, String subject, Object extData) { 23 | log.debug("队列运行程序 queueName:{} subject:{}", queueName, subject); 24 | if (null != getConsumer()) { 25 | return getConsumer().apply(queueName, subject); 26 | } 27 | return false; 28 | } 29 | } 30 | ``` 31 | 32 | ### 2.调用`com.joy.queue.WaitQueueProvider#enqueue`入列 33 | 34 | ```java 35 | WaitQueueInfo waitQueueInfo1 = waitQueueProvider.enqueue(QUEUE_NAME, "test1"); 36 | ``` 37 | 38 | ### 3.调用任意队列名的`com.joy.queue.WaitQueueProvider#query`即可启动队列 39 | 40 | ```java 41 | WaitQueueInfo waitQueueInfo = waitQueueProvider.query(QUEUE_NAME, "test1"); 42 | ``` 43 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | org.springframework.boot 7 | spring-boot-starter-parent 8 | 3.3.5 9 | 10 | 11 | com.joy 12 | delay-queue 13 | 0.0.1-SNAPSHOT 14 | delay-queue 15 | delay-queue 16 | 17 | 17 18 | 19 | 20 | 21 | org.springframework.boot 22 | spring-boot-starter 23 | 24 | 25 | org.projectlombok 26 | lombok 27 | 28 | 29 | org.springframework.boot 30 | spring-boot-starter-data-redis 31 | 32 | 33 | org.springframework.boot 34 | spring-boot-starter-test 35 | test 36 | 37 | 38 | 39 | 40 | 41 | 42 | org.springframework.boot 43 | spring-boot-maven-plugin 44 | 45 | 46 | 47 | 48 | 49 | -------------------------------------------------------------------------------- /src/main/java/com/joy/DelayQueueApplication.java: -------------------------------------------------------------------------------- 1 | package com.joy; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | /** 7 | * @author Joy 8 | */ 9 | @SpringBootApplication 10 | public class DelayQueueApplication { 11 | public static void main(String[] args) { 12 | SpringApplication.run(DelayQueueApplication.class, args); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/main/java/com/joy/config/QueueConfiguration.java: -------------------------------------------------------------------------------- 1 | package com.joy.config; 2 | 3 | import com.joy.queue.DefaultWaitQueueExecutor; 4 | import com.joy.queue.WaitQueueProvider; 5 | import com.joy.queue.impl.WaitQueueProviderImpl; 6 | import org.springframework.context.annotation.Bean; 7 | import org.springframework.context.annotation.Configuration; 8 | import org.springframework.data.redis.connection.RedisConnectionFactory; 9 | import org.springframework.data.redis.core.RedisTemplate; 10 | 11 | /** 12 | * @author Joy 13 | */ 14 | @Configuration 15 | public class QueueConfiguration { 16 | 17 | @Bean 18 | public WaitQueueProvider waitQueueProvider(RedisTemplate redisTemplate,DefaultWaitQueueExecutor defaultWaitQueueExecutor) { 19 | return new WaitQueueProviderImpl(redisTemplate, defaultWaitQueueExecutor); 20 | } 21 | 22 | @Bean 23 | public RedisTemplate redisTemplate(RedisConnectionFactory redisConnectionFactory) { 24 | RedisTemplate redisTemplate = new RedisTemplate<>(); 25 | redisTemplate.setConnectionFactory(redisConnectionFactory); 26 | return redisTemplate; 27 | } 28 | 29 | 30 | } -------------------------------------------------------------------------------- /src/main/java/com/joy/config/WaitQueueConfig.java: -------------------------------------------------------------------------------- 1 | package com.joy.config; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Builder; 5 | import lombok.Data; 6 | import lombok.NoArgsConstructor; 7 | 8 | /** 9 | * @author Joy 10 | */ 11 | @Data 12 | @Builder 13 | @NoArgsConstructor 14 | @AllArgsConstructor 15 | public class WaitQueueConfig { 16 | /** 17 | * 是否启动时间查询 18 | */ 19 | private Boolean searchTimeEnabled = true; 20 | 21 | /** 22 | * 队列裂隙 23 | */ 24 | private String waitQueueType = ""; 25 | } -------------------------------------------------------------------------------- /src/main/java/com/joy/entity/WaitQueueInfo.java: -------------------------------------------------------------------------------- 1 | package com.joy.entity; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Builder; 5 | import lombok.Data; 6 | import lombok.NoArgsConstructor; 7 | 8 | import java.io.Serializable; 9 | 10 | /** 11 | * @author Joy 12 | */ 13 | @Data 14 | @AllArgsConstructor 15 | @NoArgsConstructor 16 | @Builder 17 | public class WaitQueueInfo implements Serializable { 18 | 19 | private Long rank; 20 | 21 | private Long fromTime; 22 | } 23 | -------------------------------------------------------------------------------- /src/main/java/com/joy/queue/AbstractWaitQueueExecutor.java: -------------------------------------------------------------------------------- 1 | package com.joy.queue; 2 | 3 | import lombok.Setter; 4 | import lombok.extern.slf4j.Slf4j; 5 | import org.springframework.beans.factory.annotation.Qualifier; 6 | import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; 7 | 8 | import java.util.LinkedList; 9 | import java.util.List; 10 | import java.util.Map; 11 | import java.util.concurrent.ConcurrentHashMap; 12 | import java.util.concurrent.CountDownLatch; 13 | import java.util.concurrent.Future; 14 | import java.util.concurrent.TimeUnit; 15 | 16 | /** 17 | * @author Joy 18 | */ 19 | @Slf4j 20 | public abstract class AbstractWaitQueueExecutor implements WaitQueueExecutor { 21 | 22 | 23 | private final Map queueSet = new ConcurrentHashMap<>(); 24 | 25 | private final ThreadPoolTaskExecutor taskExecutor; 26 | 27 | private volatile boolean isRunning = false; 28 | 29 | @Setter 30 | private Long waitInterval = 30 * 1000L; 31 | 32 | @Setter 33 | private Integer failFitCount = 100; 34 | 35 | private Future threadFuture; 36 | 37 | 38 | private WaitQueueProvider waitQueueProvider; 39 | 40 | protected String getServiceName() { 41 | return "排队监听线程处理程序"; 42 | } 43 | 44 | public AbstractWaitQueueExecutor(@Qualifier("taskExecutor") ThreadPoolTaskExecutor taskExecutor) { 45 | this.taskExecutor = taskExecutor; 46 | } 47 | 48 | @Override 49 | public void init(WaitQueueProvider waitQueueProvider) { 50 | this.waitQueueProvider = waitQueueProvider; 51 | } 52 | 53 | @Override 54 | public void checkStatus(String queueName) { 55 | queueSet.put(queueName, 0); 56 | notifySingle(); 57 | start(); 58 | } 59 | 60 | @Override 61 | public void remove(String queueName) { 62 | queueSet.remove(queueName); 63 | } 64 | 65 | @Override 66 | public synchronized void stop() { 67 | this.isRunning = false; 68 | if (threadFuture != null) { 69 | try { 70 | threadFuture.cancel(true); 71 | } catch (Throwable throwable) { 72 | //do something 73 | } 74 | } 75 | } 76 | 77 | public synchronized void start() { 78 | if (null == waitQueueProvider) { 79 | return; 80 | } 81 | if (isRunning) { 82 | return; 83 | } 84 | this.isRunning = true; 85 | threadFuture = taskExecutor.submit(this::run); 86 | } 87 | 88 | public void run() { 89 | while (isRunning) { 90 | try { 91 | runInternalSingle(); 92 | } catch (Throwable throwable) { 93 | //do something 94 | } 95 | } 96 | } 97 | 98 | protected void notifySingle() { 99 | synchronized (this) { 100 | this.notifyAll(); 101 | } 102 | } 103 | 104 | protected void waitSingle() throws InterruptedException { 105 | synchronized (this) { 106 | this.wait(getWaitInterval()); 107 | } 108 | } 109 | 110 | private void runInternalSingle() throws InterruptedException { 111 | List tmpList = new LinkedList<>(queueSet.keySet()); 112 | if (tmpList.isEmpty()) { 113 | this.waitSingle(); 114 | return; 115 | } 116 | if (tmpList.size() == 1) { 117 | String queueName = tmpList.get(0); 118 | if (peekAndProcess(queueName, null)) { 119 | TimeUnit.MILLISECONDS.sleep(10L); 120 | } 121 | return; 122 | } 123 | log.debug("{}线程数据获取 队列名称长度:{}", getServiceName(), tmpList.size()); 124 | CountDownLatch startCount = new CountDownLatch(tmpList.size()); 125 | boolean hasFetch = false; 126 | for (String queueName : tmpList) { 127 | if (peekAndProcess(queueName, startCount)) { 128 | hasFetch = true; 129 | } 130 | } 131 | if (!hasFetch) { 132 | this.waitSingle(); 133 | } else { 134 | TimeUnit.MILLISECONDS.sleep(10L); 135 | } 136 | } 137 | 138 | protected boolean peekAndProcess(String queueName, CountDownLatch startCount) throws InterruptedException { 139 | boolean hasFetch = false; 140 | try { 141 | String subject = waitQueueProvider.peek(queueName); 142 | log.debug("{}线程数据获取 队列名称:{} 队列第一个元素:{}", getServiceName(), queueName, subject); 143 | if (null != subject) { 144 | hasFetch = true; 145 | if (processByQueueName(queueName, subject, null)) { 146 | waitQueueProvider.remove(queueName, subject); 147 | } else { 148 | TimeUnit.MILLISECONDS.sleep(100L); 149 | } 150 | } else { 151 | checkFaitCount(queueName); 152 | } 153 | } catch (Exception e) { 154 | //do something 155 | } finally { 156 | if (null != startCount) { 157 | startCount.countDown(); 158 | } else if (!hasFetch) { 159 | this.waitSingle(); 160 | } 161 | } 162 | return hasFetch; 163 | } 164 | 165 | public boolean processByQueueName(String queueName, String subject, Object extData) { 166 | return false; 167 | } 168 | 169 | protected void checkFaitCount(String queueName) { 170 | Integer count = queueSet.get(queueName); 171 | log.debug("{} 暂无排队数据,发生次数:{}", queueName, count); 172 | if (null == count) { 173 | count = 0; 174 | } 175 | if (count > getFailFitCount()) { 176 | queueSet.remove(queueName); 177 | } else { 178 | queueSet.put(queueName, count + 1); 179 | } 180 | } 181 | 182 | public Long getWaitInterval() { 183 | if (waitInterval == null || waitInterval <= 0L) { 184 | waitInterval = 5000L; 185 | } 186 | return waitInterval; 187 | } 188 | 189 | public Integer getFailFitCount() { 190 | if (failFitCount == null || failFitCount == 0) { 191 | failFitCount = 10; 192 | } 193 | return failFitCount; 194 | } 195 | } -------------------------------------------------------------------------------- /src/main/java/com/joy/queue/DefaultWaitQueueExecutor.java: -------------------------------------------------------------------------------- 1 | package com.joy.queue; 2 | 3 | import lombok.Getter; 4 | import lombok.Setter; 5 | import lombok.extern.slf4j.Slf4j; 6 | import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; 7 | import org.springframework.stereotype.Component; 8 | 9 | import java.util.function.BiFunction; 10 | 11 | /** 12 | * @author Joy 13 | */ 14 | @Setter 15 | @Getter 16 | @Slf4j 17 | @Component 18 | public class DefaultWaitQueueExecutor extends AbstractWaitQueueExecutor { 19 | 20 | private BiFunction consumer; 21 | 22 | public DefaultWaitQueueExecutor(ThreadPoolTaskExecutor taskExecutor) { 23 | super(taskExecutor); 24 | } 25 | 26 | @Override 27 | public boolean processByQueueName(String queueName, String subject, Object extData) { 28 | log.debug("队列运行程序 queueName:{} subject:{}", queueName, subject); 29 | if (null != getConsumer()) { 30 | return getConsumer().apply(queueName, subject); 31 | } 32 | return false; 33 | } 34 | } -------------------------------------------------------------------------------- /src/main/java/com/joy/queue/WaitQueueExecutor.java: -------------------------------------------------------------------------------- 1 | package com.joy.queue; 2 | 3 | /** 4 | * @author Joy 5 | */ 6 | public interface WaitQueueExecutor { 7 | /** 8 | * 初始化轮训服务 9 | * 10 | * @param waitQueueProvider 11 | */ 12 | void init(WaitQueueProvider waitQueueProvider); 13 | 14 | /** 15 | * 验证队列状态 16 | * 17 | * @param queueName 18 | */ 19 | void checkStatus(String queueName); 20 | 21 | /** 22 | * 删除队列 23 | * 24 | * @param queueName 25 | */ 26 | void remove(String queueName); 27 | 28 | void stop(); 29 | } -------------------------------------------------------------------------------- /src/main/java/com/joy/queue/WaitQueueProvider.java: -------------------------------------------------------------------------------- 1 | package com.joy.queue; 2 | 3 | import com.joy.entity.WaitQueueInfo; 4 | 5 | /** 6 | * @author Joy 7 | */ 8 | public interface WaitQueueProvider { 9 | 10 | /** 11 | * 入列 12 | * 13 | * @param queueName 队列名称 14 | * @param subject 排队数据 15 | * @return 排队情况 16 | */ 17 | default WaitQueueInfo enqueue(String queueName, String subject) { 18 | return enqueue(queueName, subject, null); 19 | } 20 | 21 | /** 22 | * 入列 23 | * 24 | * @param queueName 队列名称 25 | * @param subject 排队数据 26 | * @param extData 扩展数据 27 | * @return 排队情况 28 | */ 29 | WaitQueueInfo enqueue(String queueName, String subject, Object extData); 30 | 31 | /** 32 | * 查询排队情况 33 | * 34 | * @param queueName 队列名称 35 | * @param subject 排队数据 36 | * @return 排队情况 37 | */ 38 | WaitQueueInfo query(String queueName, String subject); 39 | 40 | /** 41 | * 获取排队主题 42 | * 43 | * @param queueName 队列名称 44 | * @return 需要处理的业务 45 | */ 46 | String peek(String queueName); 47 | 48 | /** 49 | * 移除指定排队信息 50 | * 51 | * @param queueName 队列名称 52 | * @param subject 排队数据 53 | */ 54 | void remove(String queueName, String subject); 55 | 56 | /** 57 | * 删除队列 58 | * 59 | * @param queueName 队列名称 60 | */ 61 | void delete(String queueName); 62 | 63 | /** 64 | * 获取队列长度 65 | * 66 | * @param queueName 队列名称 67 | * @return 队列长度 68 | */ 69 | Integer getSize(String queueName); 70 | } 71 | -------------------------------------------------------------------------------- /src/main/java/com/joy/queue/impl/WaitQueueProviderImpl.java: -------------------------------------------------------------------------------- 1 | package com.joy.queue.impl; 2 | 3 | import com.joy.config.WaitQueueConfig; 4 | import com.joy.entity.WaitQueueInfo; 5 | import com.joy.queue.WaitQueueExecutor; 6 | import com.joy.queue.WaitQueueProvider; 7 | import org.springframework.data.redis.core.RedisTemplate; 8 | import org.springframework.data.redis.core.ZSetOperations; 9 | 10 | import java.util.Iterator; 11 | import java.util.Set; 12 | 13 | /** 14 | * @author Joy 15 | */ 16 | public class WaitQueueProviderImpl implements WaitQueueProvider { 17 | 18 | private ZSetOperations zSetOperations; 19 | private final RedisTemplate redisTemplate; 20 | private final WaitQueueExecutor waitQueueExecutor; 21 | private final WaitQueueConfig waitQueueConfig; 22 | 23 | public WaitQueueProviderImpl(RedisTemplate redisTemplate, WaitQueueExecutor waitQueueExecutor) { 24 | this(redisTemplate, waitQueueExecutor, WaitQueueConfig.builder().searchTimeEnabled(false).build()); 25 | } 26 | 27 | public WaitQueueProviderImpl(RedisTemplate redisTemplate, WaitQueueExecutor waitQueueExecutor, WaitQueueConfig waitQueueConfig) { 28 | this.redisTemplate = redisTemplate; 29 | this.waitQueueExecutor = waitQueueExecutor; 30 | this.waitQueueExecutor.init(this); 31 | this.waitQueueConfig = waitQueueConfig; 32 | if (null != redisTemplate) { 33 | this.zSetOperations = redisTemplate.opsForZSet(); 34 | } 35 | } 36 | 37 | @Override 38 | public WaitQueueInfo enqueue(String queueName, String subject, Object extData) { 39 | if (null == zSetOperations || null == queueName || null == subject) { 40 | return noneQueueInfo(); 41 | } 42 | String key = getZsetKey(queueName); 43 | WaitQueueInfo queueInfo = this.query(queueName, subject); 44 | if (queueInfo.getRank() != null && queueInfo.getRank() > -1) { 45 | //已入列 46 | return queueInfo; 47 | } 48 | long fromTime = System.currentTimeMillis(); 49 | Boolean flag = zSetOperations.add(key, subject, (double) fromTime); 50 | if (Boolean.FALSE.equals(flag)) { 51 | return noneQueueInfo(); 52 | } 53 | Long rank = zSetOperations.rank(key, subject); 54 | if (null == rank) { 55 | rank = 0L; 56 | } 57 | return WaitQueueInfo.builder().rank(rank).fromTime(fromTime).build(); 58 | } 59 | 60 | private WaitQueueInfo noneQueueInfo() { 61 | return WaitQueueInfo.builder().rank(-1L).build(); 62 | } 63 | 64 | @Override 65 | public WaitQueueInfo query(String queueName, String subject) { 66 | if (zSetOperations == null || queueName == null || subject == null) { 67 | return noneQueueInfo(); 68 | } 69 | this.waitQueueExecutor.checkStatus(queueName); 70 | String key = getZsetKey(queueName); 71 | Long rank = zSetOperations.rank(key, subject); 72 | if (null == rank) { 73 | return noneQueueInfo(); 74 | } 75 | long fromTime = System.currentTimeMillis(); 76 | if (getSearchTimeEnabled()) { 77 | Double score = zSetOperations.score(key, subject); 78 | if (null != score && score > 0) { 79 | fromTime = score.longValue(); 80 | } 81 | } 82 | return WaitQueueInfo.builder().rank(rank).fromTime(fromTime).build(); 83 | } 84 | 85 | @Override 86 | public String peek(String queueName) { 87 | if (zSetOperations == null || queueName == null) { 88 | return null; 89 | } 90 | Set list = zSetOperations.range(getZsetKey(queueName), 0L, 0); 91 | if (list == null || list.isEmpty()) { 92 | return null; 93 | } 94 | Iterator iterator = list.iterator(); 95 | if (iterator.hasNext()) { 96 | Object key = iterator.next(); 97 | return null != key ? key.toString() : null; 98 | } 99 | return null; 100 | } 101 | 102 | @Override 103 | public void remove(String queueName, String subject) { 104 | if (zSetOperations == null || queueName == null || subject == null) { 105 | return; 106 | } 107 | zSetOperations.remove(getZsetKey(queueName), subject); 108 | } 109 | 110 | @Override 111 | public void delete(String queueName) { 112 | if (zSetOperations == null || queueName == null) { 113 | return; 114 | } 115 | this.waitQueueExecutor.remove(queueName); 116 | redisTemplate.delete(getZsetKey(queueName)); 117 | } 118 | 119 | @Override 120 | public Integer getSize(String queueName) { 121 | if (zSetOperations == null || queueName == null) { 122 | return 0; 123 | } 124 | Long value = zSetOperations.count(getZsetKey(queueName), 0, -1); 125 | return value == null ? 0 : value.intValue(); 126 | } 127 | 128 | private String getZsetKey(String queueName) { 129 | if (null != waitQueueConfig && null != waitQueueConfig.getWaitQueueType()) { 130 | return waitQueueConfig.getWaitQueueType() + "_" + queueName; 131 | } 132 | return queueName; 133 | } 134 | 135 | public Boolean getSearchTimeEnabled() { 136 | if (null != waitQueueConfig) { 137 | return waitQueueConfig.getSearchTimeEnabled(); 138 | } 139 | return true; 140 | } 141 | } -------------------------------------------------------------------------------- /src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | spring: 2 | data: 3 | redis: 4 | host: localhost 5 | port: 6379 6 | password: 123456 -------------------------------------------------------------------------------- /src/main/resources/logback-spring.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | %clr(%d{${LOG_DATEFORMAT_PATTERN:-HH:mm:ss.SSS}}){faint}%clr(${LOG_LEVEL_PATTERN:-%5p}) %clr(-){faint} %clr([%X{requestId}]){faint} %clr(%-40.40logger{30}){cyan} %clr(:){faint} %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx} 17 | 18 | 19 | 20 | 21 | 22 | ${LOG_PATH}/${APP_NAME}.log 23 | 24 | 25 | ${LOG_PATH}/${APP_NAME}-%d{yyyyMMdd}-%i.log.gz 26 | 27 | 30 28 | 29 | 30MB 30 | 31 | 32 | 33 | %d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} : %msg%n 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | -------------------------------------------------------------------------------- /src/test/java/com/joy/DelayQueueApplicationTest.java: -------------------------------------------------------------------------------- 1 | package com.joy; 2 | 3 | import com.joy.entity.WaitQueueInfo; 4 | import com.joy.queue.DefaultWaitQueueExecutor; 5 | import com.joy.queue.WaitQueueProvider; 6 | import jakarta.annotation.Resource; 7 | import org.junit.jupiter.api.Assertions; 8 | import org.junit.jupiter.api.DisplayName; 9 | import org.junit.jupiter.api.Tag; 10 | import org.junit.jupiter.api.Test; 11 | import org.springframework.boot.test.context.SpringBootTest; 12 | 13 | /** 14 | * @author Joy 15 | */ 16 | @SpringBootTest 17 | @DisplayName("延迟队列测试") 18 | public class DelayQueueApplicationTest { 19 | @Resource 20 | private WaitQueueProvider waitQueueProvider; 21 | @Resource 22 | private DefaultWaitQueueExecutor defaultWaitQueueExecutor; 23 | 24 | private static final String QUEUE_NAME = "test_queue"; 25 | 26 | @Test 27 | @Tag("入列测试") 28 | public void testEnqueue() { 29 | WaitQueueInfo waitQueueInfo1 = waitQueueProvider.enqueue(QUEUE_NAME, "test1"); 30 | WaitQueueInfo waitQueueInfo2 = waitQueueProvider.enqueue(QUEUE_NAME, "test2"); 31 | WaitQueueInfo waitQueueInfo3 = waitQueueProvider.enqueue(QUEUE_NAME, "test3"); 32 | Assertions.assertNotNull(waitQueueInfo1); 33 | Assertions.assertNotNull(waitQueueInfo2); 34 | Assertions.assertNotNull(waitQueueInfo3); 35 | } 36 | 37 | @Test 38 | @DisplayName("队列启动测试") 39 | public void testQuery() { 40 | defaultWaitQueueExecutor.setConsumer((queueName, subject) -> { 41 | System.out.println("queueName:" + queueName + " subject:" + subject); 42 | return true; 43 | }); 44 | WaitQueueInfo waitQueueInfo = waitQueueProvider.query(QUEUE_NAME, "test1"); 45 | Assertions.assertNotNull(waitQueueInfo); 46 | } 47 | } 48 | --------------------------------------------------------------------------------