微服务项目收获和总结---第5天(定时发布)

news/2024/7/24 21:33:37/文章来源:https://blog.csdn.net/qq_62366797/article/details/139199400

延迟任务

目录

  • 延迟任务
  • 技术对比: 
  •  Redis实现定时任务:​编辑
  • 新增任务:
  • 取消任务:
  • 拉取任务:
  • Zset定时刷新数据到List中:
  • 分布式锁实现定时任务只刷新一次:

技术对比: 

 

 Redis实现定时任务:

 问题1:为什么任务需要存储在数据库中?

问题2:为什么使用两种Redis的数据结构(List和Zset)?

 问题3:添加Zset数据时,为什么需要预加载?

        

新增任务:

添加任务到数据库进行持久化----->添加任务到Redis队列中------>如果任务的执行时间小于等于当前时间,则添加到当前任务List队列中------>如果任务的执行时间大于当前时间并且小于预设时间,就把其放到未来队列Zset中

@Service
@Transactional
@Slf4j
public class TaskServiceImpl implements TaskService {/*** 添加延迟任务** @param task* @return*/@Overridepublic long addTask(Task task) {//1.添加任务到数据库中boolean success = addTaskToDb(task);if (success) {//2.添加任务到redisaddTaskToCache(task);}return task.getTaskId();}@Autowiredprivate CacheService cacheService;/*** 把任务添加到redis中** @param task*/private void addTaskToCache(Task task) {String key = task.getTaskType() + "_" + task.getPriority();//获取5分钟之后的时间  毫秒值Calendar calendar = Calendar.getInstance();calendar.add(Calendar.MINUTE, 5);long nextScheduleTime = calendar.getTimeInMillis();//2.1 如果任务的执行时间小于等于当前时间,存入listif (task.getExecuteTime() <= System.currentTimeMillis()) {cacheService.lLeftPush(ScheduleConstants.TOPIC + key, JSON.toJSONString(task));} else if (task.getExecuteTime() <= nextScheduleTime) {//2.2 如果任务的执行时间大于当前时间 && 小于等于预设时间(未来5分钟) 存入zset中cacheService.zAdd(ScheduleConstants.FUTURE + key, JSON.toJSONString(task), task.getExecuteTime());}}@Autowiredprivate TaskinfoMapper taskinfoMapper;@Autowiredprivate TaskinfoLogsMapper taskinfoLogsMapper;/*** 添加任务到数据库中** @param task* @return*/private boolean addTaskToDb(Task task) {boolean flag = false;try {//保存任务表Taskinfo taskinfo = new Taskinfo();BeanUtils.copyProperties(task, taskinfo);taskinfo.setExecuteTime(new Date(task.getExecuteTime()));taskinfoMapper.insert(taskinfo);//设置taskIDtask.setTaskId(taskinfo.getTaskId());//保存任务日志数据TaskinfoLogs taskinfoLogs = new TaskinfoLogs();BeanUtils.copyProperties(taskinfo, taskinfoLogs);taskinfoLogs.setVersion(1);taskinfoLogs.setStatus(ScheduleConstants.SCHEDULED);taskinfoLogsMapper.insert(taskinfoLogs);flag = true;} catch (Exception e) {e.printStackTrace();}return flag;}
}

取消任务:

把数据库的任务删除----->更新任务的日志------>删除redis队列中的数据

/*** 取消任务* @param taskId* @return*/
@Override
public boolean cancelTask(long taskId) {boolean flag = false;//删除任务,更新日志Task task = updateDb(taskId,ScheduleConstants.EXECUTED);//删除redis的数据if(task != null){removeTaskFromCache(task);flag = true;}return false;
}/*** 删除redis中的任务数据* @param task*/
private void removeTaskFromCache(Task task) {String key = task.getTaskType()+"_"+task.getPriority();if(task.getExecuteTime()<=System.currentTimeMillis()){cacheService.lRemove(ScheduleConstants.TOPIC+key,0,JSON.toJSONString(task));}else {cacheService.zRemove(ScheduleConstants.FUTURE+key, JSON.toJSONString(task));}
}/*** 删除任务,更新任务日志状态* @param taskId* @param status* @return*/
private Task updateDb(long taskId, int status) {Task task = null;try {//删除任务taskinfoMapper.deleteById(taskId);//更新日志TaskinfoLogs taskinfoLogs = taskinfoLogsMapper.selectById(taskId);taskinfoLogs.setStatus(status);taskinfoLogsMapper.updateById(taskinfoLogs);task = new Task();BeanUtils.copyProperties(taskinfoLogs,task);task.setExecuteTime(taskinfoLogs.getExecuteTime().getTime());}catch (Exception e){log.error("task cancel exception taskid={}",taskId);}return task;
}

 

拉取任务:

 /*** 按照类型和优先级拉取任务* @return*/
@Override
public Task poll(int type,int priority) {Task task = null;try {String key = type+"_"+priority;//从List中取出任务String task_json = cacheService.lRightPop(ScheduleConstants.TOPIC + key);if(StringUtils.isNotBlank(task_json)){task = JSON.parseObject(task_json, Task.class);//更新数据库信息,删除任务并且更新日志updateDb(task.getTaskId(),ScheduleConstants.EXECUTED);}}catch (Exception e){e.printStackTrace();log.error("poll task exception");}return task;
}

Zset定时刷新数据到List中+分布式锁实现定时任务只刷新一次:

如何获取Zset中所有的key。方案一:keys()获取,不推荐。方案二:scan()获取。

通过定时任务,使用redis管道,把Zset中的数据往List中传输 

 
/*** 未来数据定时刷新*/
@Scheduled(cron = "0 */1 * * * ?")
public void refresh(){//获取锁String token = cacheService.tryLock("FUTURE_TASK_SYNC", 1000 * 30);if(StringUtils.isNotBlank(token)){log.info("未来数据定时刷新---定时任务");//获取所有未来数据的集合keySet<String> futureKeys = cacheService.scan(ScheduleConstants.FUTURE + "*");for (String futureKey : futureKeys) {//future_100_50//获取当前数据的key  topicString topicKey = ScheduleConstants.TOPIC+futureKey.split(ScheduleConstants.FUTURE)[1];//按照key和分值查询符合条件的数据Set<String> tasks = cacheService.zRangeByScore(futureKey, 0, System.currentTimeMillis());//同步数据if(!tasks.isEmpty()){cacheService.refreshWithPipeline(futureKey,topicKey,tasks);log.info("成功的将"+futureKey+"刷新到了"+topicKey);}}}
}

数据库同步到Redis中:

 清除缓存----->查询出小于未来5分钟的所有任务------>新增任务到Redis中

 
@Scheduled(cron = "0 */5 * * * ?")
@PostConstruct
public void reloadData() {clearCache();log.info("数据库数据同步到缓存");Calendar calendar = Calendar.getInstance();calendar.add(Calendar.MINUTE, 5);//查看小于未来5分钟的所有任务List<Taskinfo> allTasks = taskinfoMapper.selectList(Wrappers.<Taskinfo>lambdaQuery().lt(Taskinfo::getExecuteTime,calendar.getTime()));if(allTasks != null && allTasks.size() > 0){for (Taskinfo taskinfo : allTasks) {Task task = new Task();BeanUtils.copyProperties(taskinfo,task);task.setExecuteTime(taskinfo.getExecuteTime().getTime());addTaskToCache(task);}}
}private void clearCache(){// 删除缓存中未来数据集合和当前消费者队列的所有keySet<String> futurekeys = cacheService.scan(ScheduleConstants.FUTURE + "*");// future_Set<String> topickeys = cacheService.scan(ScheduleConstants.TOPIC + "*");// topic_cacheService.delete(futurekeys);cacheService.delete(topickeys);
}

其他微服务通过Fegin远程调用Schedule服务 :
@FeignClient("leadnews-schedule")
public interface IScheduleClient {/*** 添加任务* @param task   任务对象* @return       任务id*/@PostMapping("/api/v1/task/add")public ResponseResult  addTask(@RequestBody Task task);/*** 取消任务* @param taskId        任务id* @return              取消结果*/@GetMapping("/api/v1/task/cancel/{taskId}")public ResponseResult cancelTask(@PathVariable("taskId") long taskId);/*** 按照类型和优先级来拉取任务* @param type* @param priority* @return*/@GetMapping("/api/v1/task/poll/{type}/{priority}")public ResponseResult poll(@PathVariable("type") int type,@PathVariable("priority")  int priority);
}

文章发布和审核:

 发布:
 
@Autowired
private WmNewsTaskService wmNewsTaskService;/*** 发布修改文章或保存为草稿* @param dto* @return*/
@Override
public ResponseResult submitNews(WmNewsDto dto) {//0.条件判断if(dto == null || dto.getContent() == null){return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID);}//1.保存或修改文章WmNews wmNews = new WmNews();//属性拷贝 属性名词和类型相同才能拷贝BeanUtils.copyProperties(dto,wmNews);//封面图片  list---> stringif(dto.getImages() != null && dto.getImages().size() > 0){//[1dddfsd.jpg,sdlfjldk.jpg]-->   1dddfsd.jpg,sdlfjldk.jpgString imageStr = StringUtils.join(dto.getImages(), ",");wmNews.setImages(imageStr);}//如果当前封面类型为自动 -1if(dto.getType().equals(WemediaConstants.WM_NEWS_TYPE_AUTO)){wmNews.setType(null);}saveOrUpdateWmNews(wmNews);//2.判断是否为草稿  如果为草稿结束当前方法if(dto.getStatus().equals(WmNews.Status.NORMAL.getCode())){return ResponseResult.okResult(AppHttpCodeEnum.SUCCESS);}//3.不是草稿,保存文章内容图片与素材的关系//获取到文章内容中的图片信息List<String> materials =  ectractUrlInfo(dto.getContent());saveRelativeInfoForContent(materials,wmNews.getId());//4.不是草稿,保存文章封面图片与素材的关系,如果当前布局是自动,需要匹配封面图片saveRelativeInfoForCover(dto,wmNews,materials);//审核文章//        wmNewsAutoScanService.autoScanWmNews(wmNews.getId());wmNewsTaskService.addNewsToTask(wmNews.getId(),wmNews.getPublishTime());return ResponseResult.okResult(AppHttpCodeEnum.SUCCESS);}
 消费:
@Autowired
private WmNewsAutoScanServiceImpl wmNewsAutoScanService;/*** 消费延迟队列数据*/
@Scheduled(fixedRate = 1000)
@Override
@SneakyThrows
public void scanNewsByTask() {log.info("文章审核---消费任务执行---begin---");ResponseResult responseResult = scheduleClient.poll(TaskTypeEnum.NEWS_SCAN_TIME.getTaskType(), TaskTypeEnum.NEWS_SCAN_TIME.getPriority());if(responseResult.getCode().equals(200) && responseResult.getData() != null){String json_str = JSON.toJSONString(responseResult.getData());Task task = JSON.parseObject(json_str, Task.class);byte[] parameters = task.getParameters();WmNews wmNews = ProtostuffUtil.deserialize(parameters, WmNews.class);System.out.println(wmNews.getId()+"-----------");wmNewsAutoScanService.autoScanWmNews(wmNews.getId());}log.info("文章审核---消费任务执行---end---");
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.luyixian.cn/news_show_1053118.aspx

如若内容造成侵权/违法违规/事实不符,请联系dt猫网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

软考数据库系统工程师试题及答案,分享几个实用搜题和学习工具 #媒体#知识分享#知识分享

以下分享的软件提供了各种实用的功能&#xff0c;如数学公式计算、语文阅读辅助等&#xff0c;让大学生们在学习过程中更加高效和便利。 1.众课帮 这是搜题app 一款考试找答案工具 &#xff0c;支持拍照、语音、文字三种搜题方式。拥有海量题库&#xff0c;覆盖了大学生网课…

二零二四充能必读 | 618火热来袭,编程书单助你提升代码力

文章目录 &#x1f4d8; Java领域的经典之作&#x1f40d; Python学习者的宝典&#x1f310; 前端开发者的权威指南&#x1f512; 并发编程的艺术&#x1f916; JVM的深入理解&#x1f3d7; 构建自己的编程语言&#x1f9e0; 编程智慧的结晶&#x1f31f; 代码效率的提升 亲爱的…

Spring系列-02-Bean类型, 作用域, 实例化, 生命周期

Bean类型, 作用域, 实例化, 生命周期 Bean类型 在 SpringFramework 中,对于 Bean 的类型,一般有两种设计: 普通BeanFactoryBean 普通Bean 三种方式 Component注解配置类Beanxml <bean> Component public class Child {}Bean public Child child() {return new Ch…

mars3d实现geojson文件xxx.json格式等实现贴地效果

说明&#xff1a; 1.mars3d.js我们的这个sdk内部参数clampToGround是异步计算贴地效果的&#xff0c;最好的贴地方式是&#xff0c;给json数据准确的带高度的经纬度值。 补充前置知识说明&#xff0c;本身的geojson数据格式每个字段代表的意思需要掌握&#xff0c; GeoJSON …

Java super关键字

super代表父类的引用&#xff0c;用于访问父类的属性、方法和构造器。 1、super的访问不限于直接父类&#xff1a; 若爷爷类和本类有同名的成员&#xff0c;也可以使用super去访问。 若多个上级类都有同名成员&#xff0c;使用super则遵循就近原则。 2、super和this比较&…

弘君资本炒股技巧:股票定向增发是什么意思?是好是坏?

股票定向增发是指已上市的公司向指定的组织或者个人投资者额外发行股份募集资金的融资方法&#xff0c;发行价格为发行前某一阶段的平均价的必定比例&#xff0c;增发的价格不得低于前二十个买卖日股票均价的80&#xff05;。 例如&#xff0c;个股定增前二十个买卖股票平均价为…

Generate Anything Anywhere in Any Scene #论文阅读

URL https://arxiv.org/pdf/2306.17154 TD;DR 2023 年 6 月 Wisconsin 的文章。围绕 ip 保持做的扩展任务&#xff0c;核心目标是对指定 ip 可以生成任意大小的&#xff08;指定 ip&#xff09;、任意背景的图片&#xff0c;同时可以通过 bbox 控制物体位置和多物体生成。主…

外卖系统源码解读:校园外卖APP开发全攻略

外卖系统源码解读&#xff1a;校园外卖APP开发全攻略 今天&#xff0c;小编将深入解读外卖系统的源码&#xff0c;详细介绍如何开发一款功能齐全的校园外卖APP&#xff0c;帮助开发者快速上手&#xff0c;打造出高质量的外卖应用。 一、需求分析 应具备以下基本功能&#xff…

vue中的$nextTick和过渡与动画

一.vue中的$nextTick 简述与用法&#xff1a;这是一个生命周期钩子 1.语法&#xff1a;this.$nextTick(回调函数) 2.作用&#xff1a;在下一次DOM更新结束后执行其指定的回调 3.什么时候用&#xff1a;当修改数据后&#xff0c;要基于更新后的新dom进行某些操作时&#xff0c;…

学习笔记之——2D Gaussian Splatting(2DGS)

3DGS在辐射场重建中取得了巨大的成就&#xff0c;实现高质量的新视图合成和快速渲染。最近新出了3DGS的升级版本&#xff0c;2DGS。写下本博文记录本人学习及测试2DGS的过程&#xff0c;本博文仅为本人学习记录用~ Project WebsiteGithub CodeOriginal paper 原理解读 由于3D…

汽车短视频怎么拍?成都科成博通文化传媒公司

汽车短视频怎么拍&#xff1f; 随着短视频平台的兴起&#xff0c;汽车爱好者们纷纷将自己的汽车生活、驾驶体验以及车辆评测等内容以短视频的形式呈现给大众。汽车短视频不仅满足了观众对汽车文化的好奇心&#xff0c;也为汽车品牌和汽车相关行业提供了宣传和推广的新渠道。那…

【机器学习】机器学习基础概念与初步探索

❀机器学习 &#x1f4d2;1. 引言&#x1f4d2;2. 机器学习概述&#x1f4d2;3. 机器学习基础概念&#x1f389;2.1 机器学习的分类&#x1f389;2.2 数据预处理&#x1f308;数据清洗与整合&#x1f308; 特征选择和特征工程&#x1f308;数据标准化与归一化 &#x1f4d2;4. …

Mesa Gallium框架入门初探

Mesa Gallium框架入门初探 MESA Gallium框架 MESA源码里面有2套架构&#xff0c;现在驱动主要基于Gallium架构。 这里我们重点来看看Gallium架构: 经典架构 Gallium架构 Gallium展开 Gallium中主要包含下面几块&#xff1a; Auxiliary模块&#xff1a;一些公共函数或者辅助…

菜鸟的JavaSE学习之旅5

这是一个目录 面向对象类和对象类对象类的定义一个对象的内存成员变量和局部变量定义位置不同作用范围不同默认值不同内存位置不同生命周期不同 关键字this关键字 构造方法标准的类 面向对象 当需要实现一个功能的时候&#xff0c;不关心具体的步骤&#xff0c;而是找一个具有…

Python考试复习--day4

1.三角函数计算 import math aeval(input()) beval(input()) x(-bpow(2*a*math.sin(math.pi/3)*math.cos(math.pi/3),0.5))/(2*a) print(x) math库 2.分段函数B import math xeval(input()) if -6<x<0:yabs(x)5 elif 0<x<3:ymath.factorial(x) elif 3<x<6:y…

JMM 理解

JMM&#xff1a; Java Memory Model (JAVA内存模型) 【JMM】 允许编译器和缓存以数据在处理器特定的缓存(或寄存器)和主存之间的移动次序拥有重要的特权。 非程序员使用了volatitle 或 synchronized明确请求了某些可见性的保证。 从几个方面学习 1、什么是JMM&#xff1f; 答…

素数判断的奥秘与编程实践

新书上架~&#x1f447;全国包邮奥~ python实用小工具开发教程http://pythontoolsteach.com/3 欢迎关注我&#x1f446;&#xff0c;收藏下次不迷路┗|&#xff40;O′|┛ 嗷~~ 目录 一、素数定义的深入理解 二、非素数的例子与思考 三、素数判断的编程实现 1. 穷举法判断素…

什么是知识中台?为什么企业需要知识中台?

如今市面上的企业数不胜数&#xff0c;企业的任何一个小细节都会产生很大的影响。近几年来一直很热门的知识中台备受企业关注。关于如何高效地管理、整合和运用知识&#xff0c;成为了每一家企业都在重点关注的问题。而知识中台&#xff0c;就是为了解决这一问题而诞生的一个全…

Java整合EasyExcel实战——2 导出复杂表头

详情代码 实体类 Data public class ComplexHeadData {ExcelProperty({"主标题", "字符串标题"})private String string;ExcelProperty({"主标题", "日期标题"})private Date date;ExcelProperty({"主标题", "数字标…

Zigbee +PC上位机 无线控制二维云台开发笔记

今日尝试开发一款简单好学的PC上位机无线控制二维云台的小试验品&#xff1a; 主要开发环境与工具介绍&#xff1a; 单片机 STM32F103C8T6 使用标准库函数编程 Visual Studio 2022软件C# Winform 开发 上位机控制软件 DL_20 无线串口模块 &#xff0b; USB-TTL 模块 实现无线通…