Django使用django-apscheduler的问题

由于业务需要,后台要有一个定时任务的功能,起初考虑单独出来使用Linux系统的corn来实现。但是考虑到这样会很不方便。于是便寻找定时任务的模块,就找到了APScheduler,考虑到要在Django中使用,后来就采用了django-apscheduler来作为定时任务的模块,但是这个模块本身有bug。当你使用uwsgi部署并开启多进程的时候,该模块的内置使用get方法来获取任务列表,然后就会报错。因为同一时间有了多个任务,get方法获取到多个任务的时候就会抛出异常。
Django定时任务不要使用django-apscheduler模块,直接使用APScheduler模块即可。

使用APScheduler

现在,我们避免了django-apscheduler模块抛出异常问题,但是我们还有一个问题等待解决,那就是uWsgi使用多进程模式启动Django项目,因此我们会有多个进程去执行这个定时任务,导致定时任务被重复执行。解决这个问题的方法,我们直接就会想到采用加锁的方式。第一个拿到锁的进程,执行定时任务,其余的进程由于拿不到锁,因此也就不会执行定时任务。下面给出两种加锁方案,分别适用于不同的场合。

Redis分布式锁

redis中放置锁,是可以解决分布式下的问题。当然,如果你没有使用分布式,也是可以使用redis锁的。

def testaps():
    cache=get_redis_connection("default")
    key = f"APS_Lock"
    lock = cache.set(key, value=1, nx=True, ex=180)
    if lock:
        scheduler = BackgroundScheduler()
        def my_job():
            print (time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(time.time())))
        scheduler.add_job(my_job, 'interval', seconds=10)
        scheduler.start()
    else:
        ...

testaps()

当多个进程都执行testaps方法的时候,只有第一个拿到redis锁(这是个原子操作)的进程才能开启定时任务,其他的进程都无法开启定时任务,这样就可以保证定时任务只被执行一次。

文件锁

在不是分布式的场景下(或者没有redis这种工具的场景下),使用文件锁也能达到相同的效果。

import atexit
import fcntl

def init():
    f = open("scheduler.lock", "wb")
    try:
        fcntl.flock(f, fcntl.LOCK_EX | fcntl.LOCK_NB)
        scheduler = BackgroundScheduler()
        def my_job():
            print (time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(time.time())))
        scheduler.add_job(my_job, 'interval', seconds=10)
        scheduler.start()
    except:
        pass
    def unlock():
        fcntl.flock(f, fcntl.LOCK_UN)
        f.close()
    atexit.register(unlock)

init()

socket锁

参考资料

Original: https://blog.csdn.net/zy010101/article/details/120860642
Author: zy010101
Title: Django使用django-apscheduler的问题

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/736185/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球