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. ...
随机推荐
- iOS 高效的分页加载(TableView、CollectionView)
一.tableview的分页加载的代码对比 没有优化之前的代码如下 [strongSelf.tableView.mj_footer endRefreshing]: [strongSelf.articl ...
- iOS 常用算法之设计一个算法,验证某字符是否为合法IPV4字符
浅析 : 一个IPV4字符由3个大于0小于255的数字 以及 3个点构成, 所有我们需要判断小数点数量是否满足条件, 以及小数点隔开的每部分是否满足条件即可. 思路: 1. 校验是否有3个小数点; 2 ...
- Python—虚拟环境的创建与管理(virtualenv与virtualenvwrapper)
virtualenv 1.安装virtualenv包 [root@localhost ~]# pip install virtualenv 2.创建虚拟环境,位置不固定,可以在项目的目录下,也可以不在 ...
- 连续线性空间排序 起泡排序(bubble sort),归并排序(merge sort)
连续线性空间排序 起泡排序(bubble sort),归并排序(merge sort) 1,起泡排序(bubble sort),大致有三种算法 基本版,全扫描. 提前终止版,如果发现前区里没有发生交换 ...
- 在C++工程上添加CUDA编译环境
1.直接在新建工程的时候选择CUDA,这样的工程既能编译C++也能编译CU 2.在已有的C++工程上添加CUDA编译环境 右键工程-->生成依赖项-->生成自定义-->勾选CUDA ...
- 解决springboot读取jar包中文件的问题
转载自: https://www.oschina.net/question/2272552_2269641 https://stackoverflow.com/questions/25869428/c ...
- 用背包问题思路解决 322. Coin Change(完全背包)
首先需要明白 0-1 背包问题中的放置表格,见 “玩转算法面试 从真题到思维全面提升算法思维” 9-5 节,本题思路类似表格纵向为:只考虑第 [0 …,… index] 种硬币(物品)表格横向为:需要 ...
- 题解:swj社会摇基础第一课
题目链接 思路:dp,f[i]表示构成i所需要的最小步数 //swj么么哒 #include<bits/stdc++.h> using namespace std; int n; cons ...
- CF1225A Forgetting Things
CF1225A Forgetting Things 洛谷评测传送门 题目描述 Kolya is very absent-minded. Today his math teacher asked him ...
- CF786B Legacy 线段树优化建图
问题描述 CF786B LG-CF786B 题解 线段树优化建图 线段树的一个区间结点代表 \([l,r]\) 区间点. 然后建立区间点的时候就在线段树上建边,有效减少点的个数,从而提高时空效率. 优 ...