django-apscheduler用法详解

django-apscheduler用法详解

1.安裝

pip install django-apscheduler

2.settings.py

INSTALLED_APPS = [
	...
    'django_apscheduler',	# 导入django_apscheduler
	'my_scheduler',		# 新建app,用来启动apscheduler
    ...
]

执行python manage.py migrate django_apscheduler,生成对应的表django_apscheduler_djangojob、django_apscheduler_djangojobexecution。

3.my_scheduler/views.py

from apscheduler.schedulers.background import BackgroundScheduler
from django_apscheduler.jobstores import DjangoJobStore, register_events, register_job
from django.conf import settings
import logging
import os


# 日志配置
logging.basicConfig(level=logging.INFO,
                    format='%(asctime)s %(filename)s[line:%(lineno)d] %(levelname)s %(message)s',
                    datefmt='%Y-%m-%d %H:%M:%S',
                    filename=os.path.join(settings.MEDIA_ROOT, 'log', 'scheduler.log'),
                    filemode='a')

# 实例化调度器
sched = BackgroundScheduler()
# 调度器使用默认的DjangoJobStore()
sched.add_jobstore(DjangoJobStore(), 'default')
sched._logger = logging
# 注册事件。启用时会报外键引用错误,原因待查。。。
# register_events(sched)
sched.start()

4.其它app使用调度器

from my_scheduler.views import sched
from datetime import datetime


def send_mail(value):
	print('{} {} send mail'.format(datetime.now(), value))


# date定時任務(执行一次)
sched.add_job(send_mail, 'date', run_date=datetime.strptime('2020-04-10 14:30', '%Y-%m-%d %H:%M'),
              args=['date_job'], id='job_id', misfire_grace_time=60, coalesce=True)
# 间隔任务
sched.add_job(send_mail, 'interval', seconds=60, args=['interval_job'])
# cron定时调度(循环执行)
sched.add_job(send_mail, 'cron', month='1-12', day='3rd fri', hour='0-3', minute=30, end_date='2014-05-30', args=['cron_job'])

add_job特殊参数介绍:

  • coalesce:当由于某种原因导致某个job积攒了好几次没有实际运行(比如说系统挂了5分钟后恢复,有一个任务是每分钟跑一次的,按道理说这5分钟内本来是“计划”运行5次的,但实际没有执行),如果coalesce为True,下次这个job被submit给executor时,只会执行1次,也就是最后这次,如果为False,那么会执行5次(不一定,因为还有其他条件,看后面misfire_grace_time的解释)

  • max_instance: 就是说同一个job同一时间最多有几个实例再跑,比如一个耗时10分钟的job,被指定每分钟运行1次,如果我们max_instance值为5,那么在第6~10分钟上,新的运行实例不会被执行,因为已经有5个实例在跑了

  • misfire_grace_time:设想和上述coalesce类似的场景,如果一个job本来14:00有一次执行,但是由于某种原因没有被调度上,现在14:01了,这个14:00的运行实例被提交时,会检查它预订运行的时间和当下时间的差值(这里是1分钟),大于我们设置的30秒限制,那么这个运行实例不会被执行

问题:uwsgi启动项目,apscheduler重复执行解决方法

此问题是uwsgi启动时开启多个进程造成的,修改uwsgi进程个数为1,workers=1,问题得以解决。
在网上查询到有人通过锁的方式避免apscheduler重复执行(我没有成功…),如下:

# 方式一:利用端口不能复用的方式
import sys, socket


try:
    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    sock.bind(("127.0.0.1", 8888))
except socket.error:
    print("!!!scheduler already started, DO NOTHING")
else:
    sched = BackgroundScheduler()
    sched.add_jobstore(DjangoJobStore(), 'default')
    sched._logger = logging
    sched.start()
    print("scheduler started")




# 方式二:文件锁的方式, windows平台python无fcntl
import atexit
import fcntl


def init(app):
    f = open("scheduler.lock", "wb")
    try:
        fcntl.flock(f, fcntl.LOCK_EX | fcntl.LOCK_NB)
        sched = BackgroundScheduler()
        sched.init_app(app)
        sched.add_jobstore(DjangoJobStore(), 'default')
        sched._logger = logging
        sched.start()
    except:
        pass

    def unlock():
        fcntl.flock(f, fcntl.LOCK_UN)
        f.close()

    atexit.register(unlock)		# 程序退出时回调函数unlock()

引用资料

https://blog.csdn.net/weixin_38168918/article/details/101286885

https://www.jianshu.com/p/9d6b277c4a7d

https://zhuanlan.zhihu.com/p/46948464

你可能感兴趣的:(django)