Java生鲜电商平台-定时器,定时任务quartz的设计与架构
Java生鲜电商平台-定时器,定时任务quartz的设计与架构
说明:任何业务有时候需要系统在某个定点的时刻执行某些任务,比如:凌晨2点统计昨天的报表,早上6点抽取用户下单的佣金。
对于Java开源生鲜电商平台而言,有定时推送客户备货,定时计算卖家今日的收益,定时提醒每日的提现金额等等
对于Java定时器而言,我们采用spring+quartz来进行技术解决方案:
对于业务而言,需要满足以下几个方面:
1. 对定时任务需要可以手动启动,手动停止,手动删除等。
2. 对定时任务的结果需要记录,什么时候执行,执行的结果如何,是否存在异常,是否有异常的记录。
3. 对定时器的错误,如果是级别很重要,是否有短信提醒来让运营人员或者技术人员手工处理呢?
类似这样:

为了满足业务的需求,根据quartz的技术选型,设计一下基础架构:
1. 任务记录信息表:
CREATE TABLE `t_job` (
`JOB_ID` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '任务id',
`BEAN_NAME` varchar(100) NOT NULL COMMENT 'spring bean名称',
`METHOD_NAME` varchar(100) NOT NULL COMMENT '方法名',
`PARAMS` varchar(200) DEFAULT NULL COMMENT '参数',
`CRON_EXPRESSION` varchar(100) NOT NULL COMMENT 'cron表达式',
`STATUS` char(2) NOT NULL COMMENT '任务状态 0:正常 1:暂停',
`REMARK` varchar(200) DEFAULT NULL COMMENT '备注',
`CREATE_TIME` datetime DEFAULT NULL COMMENT '创建时间',
PRIMARY KEY (`JOB_ID`)
) ENGINE=InnoDB AUTO_INCREMENT=12 DEFAULT CHARSET=utf8;
2. 任务操作日志记录表:
CREATE TABLE `t_job_log` (
`LOG_ID` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '任务日志id',
`JOB_ID` bigint(20) NOT NULL COMMENT '任务id',
`BEAN_NAME` varchar(100) NOT NULL COMMENT 'spring bean名称',
`METHOD_NAME` varchar(100) NOT NULL COMMENT '方法名',
`PARAMS` varchar(200) DEFAULT NULL COMMENT '参数',
`STATUS` char(2) NOT NULL COMMENT '任务状态 0:成功 1:失败',
`ERROR` text COMMENT '失败信息',
`TIMES` decimal(11,0) DEFAULT NULL COMMENT '耗时(单位:毫秒)',
`CREATE_TIME` datetime DEFAULT NULL COMMENT '创建时间',
PRIMARY KEY (`LOG_ID`)
) ENGINE=InnoDB AUTO_INCREMENT=2476 DEFAULT CHARSET=utf8;
说明:整个业务很简单,整个表设计与架构也很简单。
最终运营截图如下:


相关的系统设置与配置说明:
相关的核心代码如下:(贴些核心的,不算很核心的,大家可以去我github下面下载即可)
/**
* 定时任务
*
* @author Administrator
*
*/
public class ScheduleJob extends QuartzJobBean {
private Logger logger = LoggerFactory.getLogger(this.getClass());
private ExecutorService service = Executors.newSingleThreadExecutor(); @Override
protected void executeInternal(JobExecutionContext context) throws JobExecutionException {
Job scheduleJob = (Job) context.getMergedJobDataMap().get(Job.JOB_PARAM_KEY); // 获取spring bean
JobLogService scheduleJobLogService = (JobLogService) SpringContextUtils.getBean("JobLogService"); JobLog log = new JobLog();
log.setJobId(scheduleJob.getJobId());
log.setBeanName(scheduleJob.getBeanName());
log.setMethodName(scheduleJob.getMethodName());
log.setParams(scheduleJob.getParams());
log.setCreateTime(new Date()); long startTime = System.currentTimeMillis(); try {
// 执行任务
logger.info("任务准备执行,任务ID:" + scheduleJob.getJobId());
ScheduleRunnable task = new ScheduleRunnable(scheduleJob.getBeanName(), scheduleJob.getMethodName(),
scheduleJob.getParams());
Future<?> future = service.submit(task);
future.get();
long times = System.currentTimeMillis() - startTime;
log.setTimes(times);
// 任务状态 0:成功 1:失败
log.setStatus("0"); logger.info("任务执行完毕,任务ID:" + scheduleJob.getJobId() + " 总共耗时:" + times + "毫秒");
} catch (Exception e) {
logger.error("任务执行失败,任务ID:" + scheduleJob.getJobId(), e);
long times = System.currentTimeMillis() - startTime;
log.setTimes(times);
// 任务状态 0:成功 1:失败
log.setStatus("1");
log.setError(StringUtils.substring(e.toString(), 0, 2000));
} finally {
scheduleJobLogService.saveJobLog(log);
}
}
}
/**
* 执行定时任务
*
* @author Administrator
*
*/
public class ScheduleRunnable implements Runnable {
private Object target;
private Method method;
private String params; public ScheduleRunnable(String beanName, String methodName, String params)
throws NoSuchMethodException, SecurityException {
this.target = SpringContextUtils.getBean(beanName);
this.params = params; if (StringUtils.isNotBlank(params)) {
this.method = target.getClass().getDeclaredMethod(methodName, String.class);
} else {
this.method = target.getClass().getDeclaredMethod(methodName);
}
} @Override
public void run() {
try {
ReflectionUtils.makeAccessible(method);
if (StringUtils.isNotBlank(params)) {
method.invoke(target, params);
} else {
method.invoke(target);
}
} catch (Exception e) {
e.printStackTrace();
}
} }
/**
* 执行定时任务
*
* @author Administrator
*
*/
public class ScheduleRunnable implements Runnable {
private Object target;
private Method method;
private String params; public ScheduleRunnable(String beanName, String methodName, String params)
throws NoSuchMethodException, SecurityException {
this.target = SpringContextUtils.getBean(beanName);
this.params = params; if (StringUtils.isNotBlank(params)) {
this.method = target.getClass().getDeclaredMethod(methodName, String.class);
} else {
this.method = target.getClass().getDeclaredMethod(methodName);
}
} @Override
public void run() {
try {
ReflectionUtils.makeAccessible(method);
if (StringUtils.isNotBlank(params)) {
method.invoke(target, params);
} else {
method.invoke(target);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
POM文件
<dependency>
<groupId>org.quartz-scheduler</groupId>
<artifactId>quartz</artifactId>
<version>2.2.1</version>
</dependency>
<dependency>
<groupId>org.quartz-scheduler</groupId>
<artifactId>quartz-jobs</artifactId>
<version>2.2.1</version>
</dependency>
org.quartz.scheduler.instanceName属性可为任何值,用在 JDBC JobStore 中来唯一标识实例,但是所有集群节点中必须相同。
org.quartz.scheduler.instanceId 属性为 AUTO即可,基于主机名和时间戳来产生实例 ID。
org.quartz.jobStore.class属性为 JobStoreTX,将任务持久化到数据中。因为集群中节点依赖于数据库来传播 Scheduler 实例的状态,你只能在使用 JDBC JobStore 时应用 Quartz 集群。这意味着你必须使用 JobStoreTX 或是 JobStoreCMT 作为 Job 存储;你不能在集群中使用 RAMJobStore。
org.quartz.jobStore.isClustered 属性为 true,你就告诉了 Scheduler 实例要它参与到一个集群当中。这一属性会贯穿于调度框架的始终,用于修改集群环境中操作的默认行为。
org.quartz.jobStore.clusterCheckinInterval 属性定义了Scheduler 实例检入到数据库中的频率(单位:毫秒)。Scheduler 检查是否其他的实例到了它们应当检入的时候未检入;这能指出一个失败的 Scheduler 实例,且当前 Scheduler 会以此来接管任何执行失败并可恢复的 Job。通过检入操作,Scheduler 也会更新自身的状态记录。clusterChedkinInterval 越小,Scheduler 节点检查失败的 Scheduler 实例就越频繁。默认值是 15000 (即15 秒)。
最终:系统架构设计图:

最后:很多人说系统功能很强大很好,但是我的一种思维方式是不一定,强大固然好,但是你需要通过这么多的系统数据中来分析出问题的关键,而不是所谓的代码堆积。
你所需要的是思考,再思考,最终思考。
Java生鲜电商平台-定时器,定时任务quartz的设计与架构的更多相关文章
- 33、生鲜电商平台-定时器,定时任务quartz的设计与架构
说明:任何业务有时候需要系统在某个定点的时刻执行某些任务,比如:凌晨2点统计昨天的报表,早上6点抽取用户下单的佣金. 对于Java开源生鲜电商平台而言,有定时推送客户备货,定时计算卖家今日的收益,定时 ...
- Java生鲜电商平台-会员积分系统的设计与架构
Java生鲜电商平台-会员积分系统的设计与架构 说明:互联网平台积分体系主要用于激励和回馈用户在平台的消费行为和活动行为,一个良好的积分体系可以很好的提升用户的粘性及活跃度. 一.互联网平台积分体系设 ...
- Java生鲜电商平台-RBAC系统权限的设计与架构
Java生鲜电商平台-RBAC系统权限的设计与架构 说明:根据上面的需求描述以及对需求的分析,我们得知通常的一个中小型系统对于权限系统所需实现的功能以及非功能性的需求,在下面我们将根据需求从技术角度上 ...
- Java开源生鲜电商平台-财务系统模块的设计与架构(源码可下载)
Java开源生鲜电商平台-财务系统模块的设计与架构(源码可下载) 前言:任何一个平台也好,系统也好,挣钱养活团队这个是无可厚非的,那么对于一个生鲜B2B平台盈利模式( 查看:http://www.cn ...
- 26、生鲜电商平台-RBAC系统权限的设计与架构
说明:根据上面的需求描述以及对需求的分析,我们得知通常的一个中小型系统对于权限系统所需实现的功能以及非功能性的需求,在下面我们将根据需求从技术角度上分析实现的策略以及基于目前两种比较流行的权限设计思想 ...
- Java生鲜电商平台-SpringCloud微服务架构中分布式事务解决方案
Java生鲜电商平台-SpringCloud微服务架构中分布式事务解决方案 说明:Java生鲜电商平台中由于采用了微服务架构进行业务的处理,买家,卖家,配送,销售,供应商等进行服务化,但是不可避免存在 ...
- Java生鲜电商平台-商城优惠券设计要点复盘与总结
Java生鲜电商平台-商城优惠券设计要点复盘与总结 Java生鲜电商平台本文将从优惠券设计用户端,需求端,业务流程全方案解析优惠券设计方案 为什么要设计优惠券 设计优惠券的核心:拉新和促活 新产品上线 ...
- Java生鲜电商平台-高并发的设计与架构
Java生鲜电商平台-高并发的设计与架构 说明:源码下载Java开源生鲜电商平台以及高并发的设计与架构文档 对于高并发的场景来说,比如电商类,o2o,门户,等等互联网类的项目,缓存技术是Java项目中 ...
- Java生鲜电商平台-生鲜系统中微服务架构设计与分析实战
Java生鲜电商平台-生鲜系统中微服务架构设计与分析实战 说明: Java生鲜系统中微服务的拆分应该如何架构设计与分析呢?以下是我的实战中的设计与经验分析. 目录 1. 微服务简介2. 当前现状3. ...
随机推荐
- 自学_CSS<二>
CSS CSS(层叠样式表)是用来美化页面用的,可以对页面元素进行更精细的设置,样式主要描述元素的字体颜色.背景颜色.边框等. CSS主要有元素内联.页面嵌入和外部引用三种使用方式.CSS是描述元素的 ...
- Clean Code
书名<代码整洁之道> 命名 有意义的命名,使人能读懂 类名和对象名应该是名称或名称短语 方法名应该是动词或动词短语 函数 短小,函数块不要超过一个屏幕 ...
- DQL---连接查询(内连接、外连接)、子查询、分页查询
一.连接查询 1.连接查询建立在有相互关系的两个表间,进行两个及两个以上的表或视图的查询. 2.对n张表进行查询,至少需要n-1个连接表的条件. 二.笛卡尔积(容易造成数据库宕机) 1.指表中每行元素 ...
- idea中git标签(tag)的创建与使用
1.什么是标签 通常,发布一个版本时,会在版本库中打一个标签(tag),这样,就唯一确定了打标签时刻的版本.将来无论什么时候,取某个标签的版本,就是把那个打标签的时刻的历史版本取出来. 所以,标签也是 ...
- Troubleshooting ORA-30013 Error (Doc ID 1578717.1)
Troubleshooting ORA-30013 Error (Doc ID 1578717.1) APPLIES TO: Oracle Database - Enterprise Edition ...
- Mysql双主加Keepalived+读写分离
一.MySQL于keepalived简介** 前言: 在企业中,数据库高可用一直是企业的重中之重,中小企业很多都是使用mysql主从方案,一主多从,读写分离等,但是单主存在单点故障,从库切换成主库需要 ...
- 3. Vue - 指令系统
一.vue指令 (1) v-if // 条件判断 如果条件成立就在页面上生成一个标签并显示出来 (2) v-show //DOM中都存在只是显示与否 (3) v-for //注意 v-bind:key ...
- VMware workstation安装centos7,无ifconfig命令
一.centos7默认未启动ifconfig,vi /etc/sysconfig/network-scripts/ifcfg-ens33,改成ONBOOT=yes: systemctl restart ...
- pugixml的简单使用
一.简介 pugixml的官方主页为:http://pugixml.org/ pugixml是一个很棒的XML操作库, 它很轻量,只有三个文件(pugiconfig.hpp pugixml.cpp ...
- 201271050130-滕江南-《面向对象程序设计(java)》第十五周学习总结
201271050130-滕江南-<面向对象程序设计(java)>第十五周学习总结 博文正文开头格式:(2分) 项目 内容 这个作业属于哪个课程 https://www.cnblogs.c ...