延时任务通知服务的设计及实现(一)-- 设计方案

一、背景

在日常编程中,总是会遇到延时执行的任务。比如:定期发送邮件,定时上架商品;再比如订单在一定时间内未支付,需要到期关闭订单。

你也许会借助分布式任务xxl-job来实现,不仅性能差,cron执行的间隔时长也影响了业务的准确性。

本文及下面的几个文章,将讨论如何实现一个通用的延时任务通知服务:

  • 设计方案
  • redisson的延迟队列RDelayedQueue
  • JDK的延迟队列DelayQueue
  • webhook执行任务

二、业务要求

  • 支持业务方对任务进行增删改查
  • 支持跨服务之间的调用
  • 延时任务通知服务,作为基础服务,不关心具体业务

三、技术要求

  • 回调时间的误差在2秒内
  • 数据需要持久化
  • 系统扩展性强:当任务量大的时候,可以横向扩展节点

四、设计方案

在这里插入图片描述

1、任务模块

业务服务通过http接口,对任务进行增删改改, 实时同步mysql数据库。

使用分布式缓存redis保存任务,提高任务的读取效率,redis 的key是任务的交易流水号。

作为任务的唯一标识,业务方需要生成一个交易流水号,保证全局唯一。

2、延迟队列模块

这是本文的重点,这里介绍两种实现。

  • redisson RDelayedQueue (分布式延迟队列)
  • Java DelayQueue (进程内的延迟队列)

后者是进程内的延迟队列,需要我们去解决分布式问题,相对会复杂一些。

任务模块会调用延迟队列模块,当任务被增删改的时候,需要同步至延迟队列。

3、webhook模块

定义一个延迟队列的消费者,监听到期的延迟任务。
得到延迟任务中的交易流水号,查询任务的回调地址和回调内容,执行http回调业务方。

五、数模设计

数据存储只需要一张表 ---- 任务表,见下:

CREATE TABLE `notify_task` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT,
  `task_code` varchar(64) NOT NULL COMMENT '任务编号',
  `trans_no` varchar(32) NOT NULL COMMENT '交易流水号',
  `notify_date` datetime NOT NULL COMMENT '通知时间',
  `notify_url` varchar(255) NOT NULL COMMENT '通知地址',
  `notify_params` varchar(4000) DEFAULT NULL COMMENT '通知内容,json格式',
  
  `is_retry` tinyint(1) DEFAULT 0 COMMENT '是否支持重试',
  `retry_times` int(11) DEFAULT 0 COMMENT '重试次数',
  
  `finished_gmt` datetime DEFAULT NULL COMMENT '完成时间',
  `is_finished` tinyint(1) NOT NULL DEFAULT 0 COMMENT '是否完成',
  
  `marked` tinyint(1) NOT NULL DEFAULT 0 COMMENT '是否已标记',
  
  `create_by` varchar(64) DEFAULT NULL COMMENT '创建人',
  `create_gmt` datetime DEFAULT current_timestamp() COMMENT '创建时间',
   `modified_by` varchar(64) DEFAULT NULL COMMENT '更新人',
  `modified_gmt` datetime DEFAULT current_timestamp() COMMENT '更新时间',
  PRIMARY KEY (`id`),
  UNIQUE KEY `UNQ_TRANS_NO` (`trans_no`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

在这里插入图片描述

六、生成任务的交易流水号

上面任务表的交易流水号生成规则是:md5(回调时间+回调地址+回调内容)。

要保证交易流水号唯一的方法有很多,但是业务方在创建任务的时候,可能不想或无法存储交易流水号,而在后面又可能修改任务的回调时间,再或者需要提前取消任务。

建议业务方只基于请求的信息进行Md5,把该值作为双方的交易流水号。

七、接口设计

在这里插入图片描述

1、新增任务

参数名称参数说明请求类型是否必须数据类型schema
requestrequestbodytrueTaskCreateRequestTaskCreateRequest
  isRetry是否支持重试falseboolean
  notifyDate通知时间,格式:yyyyMMddHHmmsstruestring
  notifyParams通知内容,json格式falsestring
  notifyUrl通知地址truestring
  taskCode任务编号truestring
  transNo交易流水号,由业务方生成并保存。删除和修改任务时,需要传递该值truestring
{
  "isRetry": true,
  "notifyDate": "20240426163900",
  "notifyParams": "{\"id\":2,\"name\":\"Jack\",\"position\":\"Assistant\"}",
  "notifyUrl": "https://webhook.site/76b884f7-ecf5-4821-9d98-4042ae776cd3",
  "taskCode": "webhooksite",
  "transNo": "123456089"
}

在这里插入图片描述

2、修改任务

参数名称参数说明请求类型是否必须数据类型schema
requestrequestbodytrueTaskEditRequestTaskEditRequest
  notifyDate通知时间,格式:yyyyMMddHHmmsstruestring
{
  "notifyDate": "20240426163400"
}

在这里插入图片描述

3、删除任务

在这里插入图片描述

限于篇幅,本文对延时任务通知的设计方案就整理到这里,后面将详细介绍延迟队列的实现。

附:相关系列文章链接

延时任务通知服务的设计及实现(一)-- 设计方案

延时任务通知服务的设计及实现(二)-- redisson的延迟队列RDelayedQueue

延时任务通知服务的设计及实现(三)-- JDK的延迟队列DelayQueue

延时任务通知服务的设计及实现(四)-- webhook执行任务

延时任务通知服务的设计及实现(五)-- Netty时间轮HashedWheelTimer

  • 25
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值