栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

设计定时任务自动检查解决方案(基于esJob)

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

设计定时任务自动检查解决方案(基于esJob)

前沿

我们在开发大型项目或者是业务比较复杂的项目,例如金融项目、仓储系统,项目中会使用大量的定时任务,来处理业务,有时候定时任务会有几十上百个,每天都要去检查,这些定时任务是否都执行了,这也是一个很浪费时间工作,但是我们有时候不得不做,这时候是不是需要一个方案来解放这部分人力成本呢?

正文

针对上述的问题,设计一个设计文档:

一、需求背景

1、现状

1.1   定时任务总共好几十个,每天都要花一定时间检查其执行情况,重复做相同的事,基于上述原因,急切需要一个项目对这些定时任务进行统一的 自动检查。

2、需求

2.1  设计一个方案对定时任务自动检查

二、整体流程

自动检查定时任务执行流程

三、功能设计

1、定时任务接入流程

1)定义定时任务父类 EsJobExecuter,实现SimpleJob接口,增加一些protected属性,比如注入自动检查自动检查定时任务执行记录Bean

EsJobExecuter类核心代码


public class EsJobExecutor implements SimpleJob {

    protected Logger logger = LoggerFactory.getLogger(getClass());



    protected String warnEmail;



    protected RedisService redisService;



    protected EmailHelper emailHelper;



    protected JsonUtils jsonUtil = JsonUtils.buildNormalBinder();



    protected NormalJob normalEsJob;



    //注入插入记录表bean

    protected IAutoJobCheckRecord autoJobCheckRecord;



    @Override

    public void execute(ShardingContext shardingContext) {



        long st = System.currentTimeMillis();



        String redisLockedKey = null;

        String redisLockId = null;

        Long redisLockTime = null;

        try {



            Map jobParameterMap = null;

            if (StringUtils.isNotBlank(shardingContext.getJobParameter())) {

                try {

                    jobParameterMap = jsonUtil.fromJson(StringUtils.trim(shardingContext.getJobParameter()), Map.class);

                } catch (Throwable e) {

                    logger.warn("can't trans shardingContext.getJobParameter():{} to map", shardingContext.getJobParameter(), e);

                }

            }

            if (jobParameterMap == null) {

                jobParameterMap = Maps.newHashMap();

            }



            redisLockedKey = normalEsJob.genLockJobKey(jobParameterMap);

            redisLockId = normalEsJob.genLockIdUseDefIfNeed(jobParameterMap);

            redisLockTime = normalEsJob.genLockTimeUseDefIfNeed(jobParameterMap);

            if (StringUtils.isNotBlank(redisLockedKey)) {

                try {

                    if (!redisService.tryGetDistributedLock(redisLockedKey, redisLockId, redisLockTime)) {

                        logger.info("{}:execute get redis lock failed, return.", normalEsJob.getJobName());

                        return;

                    }

                } catch (Throwable e) {

                    logger.error("{}:execute redisService.tryGetDistributedLock for redisKey:{} error", normalEsJob.getJobName(), redisLockedKey, e);

                    return;

                }

            }


            if (normalEsJob.canDoJob(jobParameterMap)) {

                normalEsJob.doJob(jobParameterMap);

                //todo 增加记录

                autoJobCheckRecord.insert();

                System.out.println("我是增加正确处理日志的记录");

            } else {

                logger.info("execute {} , but do not job", normalEsJob.getJobName());

            }



        } catch (Throwable ex) {

            logger.error("execute {} error", normalEsJob.getJobName(), ex);

            //todo 增加错误异常记录

             autoJobCheckRecord.insert();

            try {

                 //发送定时任务失败邮件

                emailHelper.send();

                logger.info("{} execute send error email end.", normalEsJob.getJobName());

            } catch (Exception ex2) {

                logger.error("{} execute send error email error.", normalEsJob.getJobName(), ex2);

            }

        } finally {

            // 删除锁

            if (StringUtils.isNotEmpty(redisLockedKey)) {

                try {

                    redisService.releaseDistributedLock(redisLockedKey, redisLockId);

                } catch (Throwable e) {

                    logger.warn("execute {} releaseDistributedLock redisKey:{} error", normalEsJob.getJobName(), redisLockedKey, e);

                }
            }

        }

    }

   //省略get set方法
}

2)NormalJob只是一个接口,就不列举了

3)所有的定时任务都继承EsJobExecuter类,例如下面的例子

@Component

@ElasticSimpleJob(cron = "0 34 * * * ?", shardingTotalCount = 1, description = "TestJob")

public class TestJob extends EsJobExecutor {

    @Override

    @Resource

    public void setEmailHelper(EmailHelper emailHelper) {

        super.setEmailHelperv(emailHelper);

    }

    @Override

    @Resource

    public void setRedisService(RedisService redisService) {

        super.setRedisService(redisService);

    }

    @Override

    @Value("${common.warn-email}")

    public void setWarnEmail(String warnEmail) {

        super.setWarnEmail(warnEmail);

    }

    private class Job implements NormalJob {

        @Override

        public void doJob(Map jobParameterMap) {

            logger.info("start AcAccountEventUseJob.......");

            //定时任务业务处理逻辑

            logger.info("end AcAccountEventUseJob.......");
        }

        @Override

        public String genLockJobKey(Map jobParameterMap) {

            return "TestJob";
        }


        @Override

        public String getJobName() {

            return "TestJob";
        }

    }

    public AopTestJob() {

        this.normalEsJob = new TestJob.Job();

    }
2、增加自动检查定时任务bean

增加一个定时检查任务,查询自动检查定时任务配置表和记录表,核对数量是否一致,具体流程可查看二

这里有一个技术点,如何根据cron表达式确定昨天定时任务执行的次数,假如某个定时任务是每个月12号跑一次,今天是13号,那么今天我做自动检查的时候,要确定该定时任务执行的数量肯是一次,明天我再做自动检查的时候,计算该定时任务的次数就是0次。所以计算昨天定时任务执行次数很重要,下面计算方式作为参考:

try {

            CronTriggerImpl cronTriggerImpl = new CronTriggerImpl();

            cronTriggerImpl.setCronexpression(cron);

            Date yesterday = DateUtil.getYesterday(new Date());

            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd 00:00:00");

            Date dateStart = DateUtils.parseDate(sdf.format(yesterday), "yyyy-MM-dd HH:mm:ss");

            SimpleDateFormat sdfEnd = new SimpleDateFormat("yyyy-MM-dd 23:59:59");

            Date date2 = DateUtils.parseDate(sdfEnd.format(yesterday), "yyyy-MM-dd HH:mm:ss");

            List dates = TriggerUtils.computeFireTimesBetween(cronTriggerImpl, null, dateStart,date2);

        } catch (ParseException e) {

        }

dates 集合就是昨天执行的时间点。

四、需求开发

1、涉及配置

数据库配置:

新建自动检查定时任务配置表:auto_check_job_config

create table auto_check_job_config
(
    id                   bigint auto_increment comment '自动job检测配置ID'  primary key,
    job_name             varchar(64) default '' not null comment 'job名称即Bean的名称',
    job_desc             varchar(128) default '' not null comment 'job描述',
     cron                 varchar(20)  default ''                not null comment 'cron表达式',
    retry_type           tinyint(1)   default 0  not null comment '是否重试 0- 否 1-是',
    retry_parameter_json varchar(128) default '' not null comment '重试参数',
    created_at           timestamp   default CURRENT_TIMESTAMP not null comment '配置创建时间',
    updated_at           timestamp   default CURRENT_TIMESTAMP not null on update CURRENT_TIMESTAMP comment '配置更新时间'
)comment '自动检查定时任务配置表'
alter table auto_check_job_config add unique index uni_job_name(job_name) comment 'job名称唯一索引'

新建 自动检查定时任务执行记录表  auto_job_check_record

create table auto_check_job_record
(
   id                   bigint auto_increment comment '自动job检测配置ID'  primary key,
   job_name             varchar(64) default '' not null comment 'job名称即Bean的名称',
   handle_result        tinyint(1)  default 0  not null comment '执行结果 0-成功 1-失败',
   handle_error_des     longtext                   null comment '处理失败描述',       
   created_at           timestamp   default CURRENT_TIMESTAMP not null comment '插入时间',
   updated_at           timestamp   default CURRENT_TIMESTAMP not null on update CURRENT_TIMESTAMP comment '插入更新时间',
)comment '自动检查定时任务执行记录表'

alter table auto_check_job_record add index idx_job_name_created_at(job_name,created_at) comment 'job名称、插入时间联合索引'

 定时任务配置:

新建自动检查定时任务 类名称 AutoCheckJob , cron 可根据待检查定时任务执行情况来定,例如需要检查昨天的定时任务,那么这个时间可以定时今天凌晨

MQ配置:


其他配置:

2、涉及项目

序号

项目名称

git地址

开发分支

部署地址

升级jar包

备注

1

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/777805.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号