【Django+Apscheduler 开发定时任务模块】【三】

目录

    本文章要实现的是Django+Apscheduler 开发定时任务模块,并使用uwsgi+nginx模式部署,
    且能避免多进程下任务重复执行,且能够页面动态操作任务;

一、回顾

前两节我们已经创建好了django项目,并创建好了定时任务的model,请前往查看
【Django+Apscheduler 开发定时任务模块】【一】
【Django+Apscheduler 开发定时任务模块】【二】

二、开发apscheduler工具类

1、先贴上apscheduler官网链接,这里不做具体介绍:

官网
翻译版

2、选择调度器,apscheduler的调度器有多种,还是简单介绍吧:
这里借来的介绍

	BlockingScheduler: 如果调度器是你程序中唯一要运行的东西,请选择它
	BackgroundScheduler: 如果你想你的调度器可以在你的应用程序后台静默运行,同时也不打算使用以下任何 Python 框架,请选择它
	AsyncIOScheduler: 如果你的程序使用了 asyncio 库,请使用这个调度器
	GeventScheduler: 如果你的程序使用了 gevent 库,请使用这个调度器
	TornadoScheduler: 如果你打算构建一个 Tornado 程序,请使用这个调度器
	TwistedScheduler: 如果你打算构建一个 Twisted 程序,请使用这个调度器
	QtScheduler: 如果你打算构建一个 Qt 程序,请使用这个调度器
	
	由于我们是基于Django框架开发,所以这里使用支持后台静默运行的调度器:BackgroundScheduler

3、apscheduler的主要操作函数:

	1、添加任务:add_job
	2、修改任务:modify_job
	3、暂停任务:pause_job
	4、重启任务:resume_job
	5、删除任务:remove_job
	# 我们的项目中,主要使用了添加、修改和删除任务,主要围绕这三个函数来写

4、开始编写apscheduler工具类,注意看下面代码块中的注释:job_new.py:

# 首先定义一个函数和一个全局的apscheduler对象,便于在类中和外部函数调用
	def start_scheduler():
    	global scheduler
    	scheduler = BackgroundScheduler()
    	scheduler.start()
# 编写类 JobAction,这个class有点长,不知道能不能行
class JobAction:
# 这是类的一个初始化函数,初始化scheduler和监听函数
    def __init__(self):
        self.scheduler = scheduler
        self.scheduler.add_listener(self.my_listener, EVENT_JOB_ERROR | EVENT_JOB_MISSED | EVENT_JOB_EXECUTED)
# 上一节的截图中出现了两条记录,调度类型分别为date和cron,这里分为两个启动函数来写,实际还有第三个类型为:interval,本项目并没有使用;
# 大家应该看到了 eval(trigger),用这个是因为我们传过来的参数是字符串,但add_job()需要的是一个对象,所以eval的作用就体现出来了。
# 重要的是我们首先要在这个文件中将任务import进来,比如:
# from app.test_job import test
    @staticmethod
    def start_date_job(trigger, job_rate, id):
        trigger_id = trigger + '-' + id
        scheduler.add_job(eval(trigger), 'date', run_date=job_rate, id=trigger_id, args=[trigger_id, id, 'date'], coalesce=False)
        logger.info("%s start successfully" % trigger)
        logger.info('任务池:' + str(scheduler.get_jobs))

    @staticmethod
    def start_cron_job(trigger, job_rate, id):
        rate = job_rate.split()
        trigger_id = trigger + '-' + id
        # 秒 分 时 日 月 星期 年
        scheduler.add_job(eval(trigger), 'cron', second=rate[0], minute=rate[1], hour=rate[2], day=rate[3],
                          month=rate[4], day_of_week=rate[5], year=rate[6], id=trigger_id,
                          args=[trigger_id, id, 'cron'], coalesce=False)
        logger.info("%s start successfully" % trigger)
        logger.info('任务池:' + str(scheduler.get_jobs))

    # 停止任务
    @staticmethod
    def stop_job(trigger_id):
        if scheduler.get_job(trigger_id):
            scheduler.remove_job(trigger_id)
            logger.info('已启动的任务:' + str(scheduler.get_jobs()))

    # 暂停任务
    @staticmethod
    def pause_job(trigger_id):
        logger.info(trigger_id)
        scheduler.pause_job(trigger_id)

    # 重启任务
    @staticmethod
    def resume_job(trigger_id):
        scheduler.resume_job(trigger_id)

    # 修改任务
    @staticmethod
    def modify_job(trigger_id, job_value):
        if job_value[0] == 'cron':
            rate = job_value[1].split()
            scheduler.reschedule_job(trigger_id, trigger='cron', second=rate[0], minute=rate[1],hour=rate[2], day=rate[3], month=rate[4], day_of_week=rate[5], year=rate[6])
        elif job_value[0] == 'date':
            scheduler.reschedule_job(trigger_id, trigger='date', run_date=job_value[1])
	# 这里是监听函数
    @staticmethod
    def my_listener(event):  # 添加监听器
        job = scheduler.get_job(event.job_id)
        if not event.exception:
            pass
        else:
            logger.error("jobname=%s|jobtrigger=%s|errcode=%s|exception=[%s]|traceback=[%s]|scheduled_time=%s", job.name, job.trigger, event.code, event.exception, event.traceback, event.scheduled_run_time)
        # scheduler.shutdown(wait=False)
以上就是对apscheduler操作的一个整合,方便后续的调用,下面就使用这个类来执行定时任务

三、页面添加按钮

由上一节的截图可知,咱们的定时任务页面除了添加、删除,一共是三个按钮:启动任务、停止任务和保存,注意看代码块中的注释;
下面分别来介绍一下相应的实现的功能:

1、先说简单的 保存按钮,这个django admin自带的按钮,通过配置可实现,直接看代码吧

	# admin中有一行配置,加上这一行就会出现保存按钮,可以将展示页面的编辑信息通过后台保存到数据库
	list_editable = ('action_type', 'job_rate',)
	# 我们的项目中在点击保存按钮之后对数据就行了一定的处理,重写了save_model函数
	# 这里是在保存数据的时候,先判断任务状态是否是运行状态
	# 是的话,以任务触发器+‘_’+任务ID 为key,任务类型和新的策略存储在redis中;反之不进行操作。最后将修改后的数据存入数据库;
	def save_model(self, request, obj, form, change):
        from django.core.cache import cache
        if obj.job_state == 1:
            cache.set(obj.trigger_name + '-' + str(obj.id), (obj.action_type, obj.job_rate))
        obj.save()

2、接下来是 启动任务,这个按钮的功能就是将任务状态修改为启动,并且将该记录对应的触发器、执行频率和调度类型添加到apscheduler的任务池中

	# 这个函数就不全贴出来了,只写关键部分吧
	def start_job(self, request, queryset):
		# 这里省略一部分循环选择的页面数据的部分,根据下面代码可以还原出来
		# 就是将选中的任务循环添加到任务池中,并修改状态;若有错,返回错误信息
    	trigger_name = trigger.get('trigger_name')
        job_rate = rate.get('job_rate')
        job_id = id.get('id')
        job_name = name.get('job_name')
        job_type = type.get('action_type')
        if hasattr(JobAction(), 'start_%s_job' % job_type):
            func = getattr(JobAction(), 'start_%s_job' % job_type)
            func(trigger_name, job_rate, str(job_id))
            queryset.update(job_state=1)
        else:
            return messages.error(request, '【启动错误】 ' + job_name + ' 任务不存在!')

3、最后就是 停止任务 了,还是看代码吧

	# 这里也省略一部分循环选择的页面数据的部分,根据下面代码可以还原出来
	# 就是根据选中的任务,从任务池中删除
	def stop_job(self, request, queryset):
        trigger_name = trigger.get('trigger_name')
        job_id = id.get('id')
        job_name = name.get('job_name')
        JobAction.stop_job(trigger_name + '-' + str(job_id))
        queryset.update(job_state=0)

OK,这里就完成了对页面按钮和定时任务的操作相关功能的开发工作。
写太多了,上一节说这是最后了,食言了,明天再写一节吧!真的最后一节了!
2022-05-02

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值