最近几个月,现网总是出现定时器不执行的情况,或者定时器卡死的情况,而又不方便排查,只能依靠quartz的debug日志以及错误日志来监控定时器的执行情况,并且随着我们系统中job越来越多,而使得job问题越来越难以跟踪,所以我们才需要一个能过对定时器进行监控的功能,并能实现线程阻塞告警,以及杀死阻塞线程的功能。

监控job有几种方案:

方案一:通过jmx远程或者直接在应用内部定时获取quartz执行信息,可以新增、修改job、job触发器以及执行情况,但是无法对以前执行的job进行跟踪。

方案二:在job的实现类中记录日志,这个方案太麻烦,因为系统目前有很多job实现类,不可能每个都去添加日志。

方案三:代理job执行类,在初始化时使用代理job执行器。

最后我选择了方案三。

先让我们来分析下源码,目前只针对quartz1.6.0:

首先查看JobRunShell类,这个是定时器的执行类实现了Runnable接口,它有两个空方法如下:

public class JobRunShell implements Runnable {
public void run() {
//省略若干代码
try {
begin();
} catch (SchedulerException se) {
qs.notifySchedulerListenersError("Error executing Job ("
+ jec.getJobDetail().getFullName()
+ ": couldn't begin execution.", se);
break;
}
//省略若干代码
try {
complete(true);
} catch (SchedulerException se) {
qs.notifySchedulerListenersError("Error executing Job ("
+ jec.getJobDetail().getFullName()
+ ": couldn't finalize execution.", se);
continue;
}
}
protected void begin() throws SchedulerException {
} protected void complete(boolean successfulExecution)
throws SchedulerException {
} }

很明显,这里预留了两个方法来监控job的执行情况。

所以我们创建了一个其子类来代理它,在开始时记录日志,结束时更新日志,

public class MonitorJobRunShell extends JobRunShell {

    /**
* 创建一个新的实例 JobRunShellImpl.
* @param jobRunShellFactory
* @param scheduler
* @param schdCtxt
*/
public MonitorJobRunShell(JobRunShellFactory jobRunShellFactory, Scheduler scheduler, SchedulingContext schdCtxt) {
super(jobRunShellFactory, scheduler, schdCtxt);
} @Override
protected void begin() throws SchedulerException {
super.begin();
try {
JobDetail jobDetail = jec.getJobDetail();
quartzLog=getService().insert(jobDetail.getName());
} catch (Exception e) {
logger.error("记录job开始时间异常",e);
}catch (Throwable e) {
logger.error("记录job开始时间出错",e);
} } @Override
protected void complete(boolean successfulExecution) throws SchedulerException {
super.complete(successfulExecution);
try {
quartzLog.setExeTime(jec.getJobRunTime());
getService().update(quartzLog);
} catch (Exception e) {
logger.error("记录job结束时间异常",e);
}catch (Throwable e) {
logger.error("记录job结束时间出错",e);
}
}
}

创建了该类,必须要让quartz使用我们创建的代理类,这里quartz使用了简单工厂模式,如下

public interface JobRunShellFactory {
/**
* <p>
* Called by the <code>{@link org.quartz.core.QuartzSchedulerThread}</code>
* to obtain instances of <code>{@link JobRunShell}</code>.
* </p>
*/
JobRunShell borrowJobRunShell() throws SchedulerException; }

我们只需要实现该接口,代理原有的std工厂类:

public class StdJobRunShellFactoryProxy implements JobRunShellFactory{

    /**
* <p>
* Called by the <class>{@link org.quartz.core.QuartzSchedulerThread}
* </code> to obtain instances of <code>
* {@link org.quartz.core.JobRunShell}</code>.
* </p>
*/
public JobRunShell borrowJobRunShell() throws SchedulerException {
return new MonitorJobRunShell(this, scheduler, schedCtxt);
} /**
* <p>
* Called by the <class>{@link org.quartz.core.QuartzSchedulerThread}
* </code> to return instances of <code>
* {@link org.quartz.core.JobRunShell}</code>.
* </p>
*/
public void returnJobRunShell(JobRunShell jobRunShell) {
jobRunShell.passivate();
}
}

进行到这里,需要使用到我们的工厂代理类,这时候则需要代理入口,即StdSchedulerFactory,

public class StdSchedulerFactoryProxy extends StdSchedulerFactory {

    /**
* 初始化Scheduler
* 同时,替换JobRunShellFactory,并启动清理job日志线程
* @see org.quartz.impl.StdSchedulerFactory#instantiate(org.quartz.core.QuartzSchedulerResources, org.quartz.core.QuartzScheduler)
*/
protected Scheduler instantiate(QuartzSchedulerResources rsrcs, QuartzScheduler qs) {
SchedulingContext schedCtxt = new SchedulingContext();
schedCtxt.setInstanceId(rsrcs.getInstanceId());
Scheduler scheduler = new StdScheduler(qs, schedCtxt);
try {
JobRunShellFactory jobFactory=new StdJobRunShellFactoryProxy();
jobFactory.initialize(scheduler, schedCtxt);
rsrcs.setJobRunShellFactory(jobFactory);
} catch (SchedulerConfigException e) {
logger.error("初始化MonitorStdJobRunShellFactory出错",e);
}
return scheduler;
}
}

最后在初始化Scheduler时使用我们代理的Scheduler工厂类就行,实例如下:

StdSchedulerFactory factory = new StdSchedulerFactoryProxy();

这里我们就实现了自己的quartz监控程序,日志记录方式可以自己扩展。这样可以有效方便的监控job的执行情况,日志中可以记录job的执行时长、线程id等,可以配置阈值如果超时可以在界面上kill该线程。

quartz监控日志(一)的更多相关文章

  1. 学习总结 之 WebApi服务监控 log4net记录监控日志

    在请求WebApi 的时候,我们更想知道在请求数据的时候,调用了哪个接口传了什么参数过来,调用这个Action花了多少时间,有没有人恶意请求.我们可以通过记录日志,对Action进行优化,可以通过日志 ...

  2. log4net 记录MVC监控日志

    由于MVC自身的特点,可以让我们记录每一个Controller下Action的执行时间以及View视图渲染完成的时间,本文采用log4net记录MVC每个Action的执行时间和View视图渲染完成时 ...

  3. zabbix监控日志文件

    环境: 操作系统:centos 6.8  ,zabbix软件版本:zabbix 3.0.1 前提条件:zabbix客户端已经配置了主动模式,如何配置主动模式,请参考此文 监控日志keys 首先要了解k ...

  4. linux 判断文件最后更新时间 实现监控日志是否有输出功能

    linux 判断文件最后更新时间 实现监控日志是否有输出功能. 需求:监控log.txt日志文件,超过一分钟没输出内容就认为是停了,则自动启动程序. 用stat 可以看文件的更新时间stat -c % ...

  5. zabbix 3.x 监控日志文件

    1.启用zabbix主动模式 在zabbix agent端,修改/etc/zabbix/zabbix_agentd.conf ServerActive=服务端IP Hostname=tspnginx0 ...

  6. C# 面向切面编程--监控日志记录方案

    背景:现在公司整体在做监控平台,要求把各个部分的细节都记录下来,在前台页面上有所显示,所以现在需要做的就是一个监控日志的记录工作,今天讲的就是渲染监控日志的例子. 现状:当前的渲染程序没有为监控日志记 ...

  7. (72)zabbix监控日志文件 MySQL日志为例

    一般情况下,日志最先反映出应用当前的问题,在海量日志里面找到我们异常记录,然后记录下来,并且根据情况报警,大家可以监控系统日志.nginx.Apache.业务日志. 这边我拿常见的MySQL日志做监控 ...

  8. 1.8-1.10 大数据仓库的数据收集架构及监控日志目录日志数据,实时抽取之hdfs系统上

    一.数据仓库架构 二.flume收集数据存储到hdfs 文档:http://flume.apache.org/releases/content/1.9.0/FlumeUserGuide.html#hd ...

  9. 基于sentry的前端错误监控日志系统(部署sentry服务器/前端项目部署)-让前端最快的定位到生产问题

    背景 在这越来越发达的网络时代,web应用也是越来越复杂,尤其是前端的开发,也是越来越受重视. 所以在我们前端开发完成后,会有一些列的web应用的上线验证,如自测.QA测试.code review 等 ...

  10. 写一个nginx监控日志

    下面的代码是实现一个nginx监控日志功能,是不是很好玩呢.

随机推荐

  1. 准入控制器(Admission Controller):ResourceQuota,ImagePolicyWebhook

    目录 一.系统环境 二.前言 三.准入控制器简介 四.为什么需要准入控制器 五.启用/禁用ResourceQuota资源配额 5.1 查看默认启用/禁用的准入控制器插件 5.2 ResourceQuo ...

  2. 将PaddleOCR 转为 ONNX 运行

    PaddleOCR 是目前最好的开源OCR框架, 但paddle框架的兼容性实在不怎么好, 部署的时候容易出现各种各样的问题. 如果能把PaddleOCR转成ONNX, 就可以跳过paddle框架坑的 ...

  3. Linux 时间 与 定时器

    背景 在学习 Linux 信号 有关知识中,提到了 alarm函数. 进程时间 (原文地址:https://www.cnblogs.com/clover-toeic/p/3845210.html) 进 ...

  4. 使用VS Code 学习算法(第四版)

    最近在学习算法(第四版),书中一直在使用命令行来执行Java程序,而使用Eclipse时,很难使用命令行,或者说我根本就不会用,于是就想研究一下使用VS Code来编写代码,使用命令行来执行程序.看了 ...

  5. 1.Javascript 快速入门(主要)

    运算 &&运算是与运算,只有所有都为true,&&运算结果才是true: true && true; // 这个&&语句计算结果为tru ...

  6. 当一名有着 10w+ 听众的播客主播开始做 App

    名字: AAAny 开发者 / 团队: AAAny Team 平台: iOS 请简要介绍下这款产品 AAAny 是一个专为 AMA(我们称之为 AAA)设计的 App.多解释一下的话,其实 AAA 是 ...

  7. Using temporary与Using filesort

    Using temporary Using temporary表示由于排序没有走索引.使用union.子查询连接查询.使用某些视图等原因(详见https://dev.mysql.com/doc/ref ...

  8. njs最详细的入门手册:Nginx JavaScript Engine

    原文链接:https://hi.imzlh.top/2024/07/08.cgi 关于njs 首先,njs似乎在国内外都不受关注,资料什么的只有 官网参考手册,出了个问题只能看到Github Issu ...

  9. 题解:P10417 [蓝桥杯 2023 国 A] 第 K 小的和

    分析 这道题不是板子么. 先对序列排序,然后二分答案,设当前答案为 \(x\),枚举 \(a\) 中的数,然后二分查找 \(b\) 中不大于 \(x-a\) 的元素个数,累加判断是否不大于 \(k\) ...

  10. k8s(3) 集群运行

    Master下面执行 mkdir -p $HOME/.kube 执行的脚本,需要读取的配置文件 cp -i /etc/kubernetes/admin.conf $HOME/.kube/config ...