redisson延时队列的使用

779 阅读2分钟

1、延时队列操作类 RedisDelayQueue

import com.eshore.zhyl.common.util.JsonUtil;
import com.google.common.collect.Maps;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RBlockingQueue;
import org.redisson.api.RDelayedQueue;
import org.redisson.api.RedissonClient;
import org.springframework.stereotype.Component;

import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * @author cp
 * rediss 延时队列操作类
 */
@Component
@RequiredArgsConstructor
@Slf4j
public class RedisDelayQueue {


    private final RedissonClient redissonClient;

    private Map<String, RBlockingQueue<String>> blockingQueueMap = Maps.newHashMap();

    private Map<String, RDelayedQueue<String>> delayedQueueMap = Maps.newHashMap();

    /**
     * 销毁队列
     */
    void destroyQueue(String queueName) {
        RDelayedQueue<String> delayedQueue = delayedQueueMap.get(queueName);
        if (delayedQueue != null) {
            delayedQueue.destroy();
        }
    }

    /**
     * 获取阻塞队列
     *
     * @param queueName 队列名称
     * @return 队列
     */
    RBlockingQueue<String> getBlockingQueue(String queueName) {
        return blockingQueueMap.computeIfAbsent(queueName, k -> redissonClient.getBlockingQueue(queueName));
    }

    /**
     * 获取延时队列
     *
     * @param queueName 队列名称
     * @return 队列
     */
    RDelayedQueue<String> getDelayQueue(String queueName) {
        return delayedQueueMap.computeIfAbsent(queueName, k -> {
            RBlockingQueue<String> blockingQueue = blockingQueueMap.computeIfAbsent(queueName,
                    t -> redissonClient.getBlockingQueue(queueName));
            return redissonClient.getDelayedQueue(blockingQueue);
        });
    }

    /**
     * 向添加队列数据
     *
     * @param queueName 队列名称
     * @param t         DTO传输类
     * @param delay     时间数量
     * @param timeUnit  时间单位
     */
    public <T> void addQueue(String queueName, T t, long delay, TimeUnit timeUnit) {
        if (t == null) {
            return;
        }
        RDelayedQueue<String> delayedQueue = getDelayQueue(queueName);
        log.info("任务入队列,延时时间:{}({}), queueName:{}, task:{}", delay, timeUnit.name(), queueName, t);
        // 指定时间以后以后将消息发送到指定队列
        delayedQueue.offer(JsonUtil.toJson(t), delay, timeUnit);
    }

    /**
     * 移除队列数据(返回被移除的队列数据)
     *
     * @param queueName 队列名称
     * @param t         DTO传输类
     * @param <T>       泛型
     */
    public <T extends BaseTask> List<T> removeQueueByIdentity(String queueName, T t, Class<T> classType) {
        RDelayedQueue<String> delayedQueue = getDelayQueue(queueName);
        log.info("任务移除队列,queueName:{}, taskId:{}", queueName, t.taskIdentity());
        List<String> dataList = delayedQueue.stream().filter(data -> {
            T k = JsonUtil.fromJson(data, classType);
            if (k == null) {
                return false;
            }
            if (k.taskIdentity().equals(t.taskIdentity())) {
                log.info("匹配到需要删除的队列数据:{}", data);
                return true;
            }
            return false;
        }).collect(Collectors.toList());
        log.info("任务ID:{}匹配到删除的记录数:{}", t.taskIdentity(), dataList.size());
        delayedQueue.removeAllAsync(dataList);
        return dataList.stream().map(data -> JsonUtil.fromJson(data, classType)).collect(Collectors.toList());
    }

}

2、延时队列任务初始化


import com.eshore.zhyl.admin.service.impl.sys.SysUserUnlockHandler;
import com.eshore.zhyl.common.constant.RedisPrefixEnum;
import com.eshore.zhyl.common.delay.RedisDelayEngine;
import com.eshore.zhyl.common.delay.RedisDelayQueue;
import com.eshore.zhyl.common.dto.UserHandleDTO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import javax.annotation.Resource;

/**
 * 延时队列任务初始化
 *
 * @author cp
 */
@Configuration
@Slf4j
public class RedisDelayConfig {

    @Resource
    private RedisDelayQueue redisDelayQueue;
    
    //延时队列之后的操作
    @Resource
    private SysUserUnlockHandler sysUserUnlockHandler;



    /**
     * 取消用户锁定 延时队列
     * @return
     */
    @Bean(value = "userUnlockDelayEngine", destroyMethod = "destroy")
    public RedisDelayEngine<UserHandleDTO> userUnlockDelayEngine() {
        RedisDelayEngine<UserHandleDTO> redisDelayEngine = new RedisDelayEngine<>(redisDelayQueue,
                RedisPrefixEnum.USER_UNLOCK.toString(), sysUserUnlockHandler, UserHandleDTO.class);
        redisDelayEngine.setTryTimes(1);
        return redisDelayEngine;
    }

3、延时队列之后的操作


import com.eshore.zhyl.common.constant.Constants;
import com.eshore.zhyl.common.delay.DelayTaskListener;
import com.eshore.zhyl.common.dto.UserHandleDTO;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import java.util.Objects;

/**
 * 延时队列触发用户解锁
 * @author cp
 */
@Component
@RequiredArgsConstructor
@Slf4j
public class SysUserUnlockHandler implements DelayTaskListener<UserHandleDTO> {

    private final SysUserMapper sysUserMapper;
   // private RedisDelayQueue redisDelayQueue;

    @Override
    public void invoke(UserHandleDTO userHandleDTO) {
          System.out.println(" test "); 
    }
}

4、具体的调用

redisTemplate.delete(Constants.LOGIN_ERROR  + sysUserForm.getUsername());
//5次登录失败,锁定账户,加入延时队列
UserHandleDTO userHandleDTO = UserHandleDTO.builder()
        .username(sysUserForm.getUsername())
        .build();
log.info("[用户登录失败账户锁定-解锁] 放入加锁账号到延时队列,data:{} , 延时:{}min", userHandleDTO, DELAY_TIME);
redisDelayQueue.addQueue(RedisPrefixEnum.USER_UNLOCK.toString(),
        userHandleDTO,
        DELAY_TIME,
        TimeUnit.MINUTES);
throw new ApiException( "账户已锁定,请5分钟之后再试");