Redis延迟队列(简易版)

1,队列

@Slf4j
@Component
public class RedisMessageQueue {

    @Autowired
    private Jedis jedis;

    private String key = "redis-queue";

    public RedisMessageQueue() {
    }

    private static final String SCRIPT = "local table = redis.call('ZRANGEBYSCORE', KEYS[1], ARGV[1], ARGV[2]);\n" +
            "\n" +
            "local key = table[1];\n" +
            "\n" +
            "if key == nil then\n" +
            "\treturn nil;\n" +
            "else\n" +
            "\tredis.call('ZREM', KEYS[1], key);\n" +
            "\treturn key;\n" +
            "end";

    public void put(String message, long delayTime, TimeUnit unit) {
        long timeout = TimeUnit.MILLISECONDS.convert(delayTime, unit);
        jedis.zadd(key, Instant.now().toEpochMilli() + timeout, message);
    }

    public String poll() {
        List<String> argvs = Lists.newArrayList();
        argvs.add("0");
        argvs.add(String.valueOf(Instant.now().toEpochMilli()));
        Object result = jedis.eval(SCRIPT, Collections.singletonList(key), argvs);
        if (Objects.isNull(result)) {
            return null;
        }
        return String.valueOf(result);
    }
}

lua脚本

local table = redis.call('ZRANGEBYSCORE', KEYS[1], ARGV[1], ARGV[2]);

local key = table[1];

if key == nil then
	return nil;
else
	redis.call('ZREM', KEYS[1], key);
	return key;
end


2,消费者线程

@Slf4j
public class LoggerWorker implements Runnable {

    private RedisMessageQueue redisMessageQueue;

    public LoggerWorker(RedisMessageQueue redisMessageQueue) {
        this.redisMessageQueue = redisMessageQueue;
    }

    @Override
    public void run() {
        while (! Thread.interrupted()) {

            String message;

            if ((message = redisMessageQueue.poll()) != null) {
                log.info("{} 执行 {}", Thread.currentThread().getName(), message);
            } else {
                try {
                    Thread.sleep(500L);
                } catch (InterruptedException e) {
                    log.error("", e);
                    break;
                }
            }
        }
    }
}

3,调用示例


生产:

@PostMapping("/producer")
public void push(String message, long delay) {
    redisMessageQueue.put(message, delay, TimeUnit.MILLISECONDS);
}

消费:

@PostMapping("/consumer")
public void newThread() {
    Thread consumer = new Thread(new LoggerWorker(redisMessageQueue));
    consumer.setDaemon(true);
    consumer.start();
}




猜你喜欢

转载自blog.51cto.com/tianyiya/2307642