使用redis模拟延时队列
实际上通过mq实现延时队列更加方便,只是在实际业务中种种原因导致最终选择使用redis作为该业务实现的中间件,顺便记录一下。
该业务是用于日程短信提醒,用户添加日程后,就会被放入redis队列中等待被执行发送短信提醒业务。
本文介绍如何使用redis来实现一个简单的延时任务队列,通过这个示例,可以帮助你理解如何利用redis的有序集合特性来管理和执行延时任务。
设计思路
redis有序集合(sorted set)可以很好地用来实现延时队列的功能。通过将任务的执行时间作为分数(score)来存入有序集合中,并定期检查集合中小于等于当前时间的任务来触发执行。
代码实现
jediscluster连接初始化
首先,我们需要初始化jediscluster连接来与redis集群进行交互。
private static final string zset_key = "sms_delayed_tasks";
private jediscluster jediscluster;
public void redisclusterscheduler() {
set<hostandport> nodes = new hashset<>();
//从配置文件中读取redis集群配置
for (string node : acpcore.getprop("spring.redis.cluster.nodes").split(",")) {
string[] hostport = node.split(":");
nodes.add(new hostandport(hostport[0], integer.parseint(hostport[1])));
}
genericobjectpoolconfig<jedis> poolconfig = new genericobjectpoolconfig<>();
poolconfig.setmaxtotal(128);
poolconfig.setmaxidle(128);
poolconfig.setminidle(16);
jediscluster = new jediscluster(nodes, 2000, 2000, 5, acpcore.getprop("spring.redis.password"), poolconfig);
if (!iscalled) {
iscalled = true;
starttaskchecker();
}
}添加延时任务
我们可以通过指定任务和执行时间来添加延时任务。该方法将执行时间转换为时间戳,并将任务存储在redis有序集合中。
public void adddelayedtask(string task, string time) {
long executetime = converttotimestamp(time);
if (executetime > system.currenttimemillis() / 1000) {
jediscluster.zadd(zset_key, executetime, task);
log.info("添加任务: " + task + " 执行时间: " + executetime);
} else {
log.info("任务时间必须在当前时间之后: " + task);
}
}
private long converttotimestamp(string time) {
simpledateformat sdf = new simpledateformat("yyyy-mm-dd hh:mm:ss");
try {
return sdf.parse(time).gettime() / 1000;
} catch (parseexception e) {
e.printstacktrace();
return system.currenttimemillis() / 1000;
}
}检查和执行任务
通过一个定时任务不断检查当前时间之前的任务并执行。
private void starttaskchecker() {
executorservice.submit(() -> {
while (!thread.currentthread().isinterrupted()) {
try {
checkandexecutetasks();
thread.sleep(1000);
} catch (exception e) {
log.info(new date() + "发生异常但不中断,异常是:" + e);
}
}
});
}
private void checkandexecutetasks() {
long currenttime = system.currenttimemillis() / 1000;
set<string> tasks = jediscluster.zrangebyscore(zset_key, 0, currenttime);
for (string task : tasks) {
jediscluster.zrem(zset_key, task);
executetask(task);
}
}执行任务的逻辑
假设任务内容是一个json对象,执行逻辑在这里可以是任何操作,比如调用外部服务、发送消息等。
private void executetask(string taskjson) {
jsonobject task = jsonobject.parseobject(taskjson);
// 在此处添加具体的业务逻辑
log.info("执行任务: " + task);
}总结
通过redis的有序集合和简单的定时器,能够实现一个简洁有效的延时任务队列。
当然,这个示例是一个简化的模型,在生产环境中,你需要考虑任务的幂等性、系统崩溃后的恢复策略、任务的优先级等问题。希望本文能为你提供实现延时队列的思路和参考。
到此这篇关于redis模拟延时队列 实现日程提醒的文章就介绍到这了,更多相关redis延时队列内容请搜索代码网以前的文章或继续浏览下面的相关文章希望大家以后多多支持代码网!
发表评论