Notion Blog
知行合一1 分钟阅读

uwsgi 多个进程定时任务执行多次

我的定时任务用的是django_apscheduler,启动是用的uwsgi的processes=2

定时任务执行了两次

要解决这个问题,可以从以下几个方面进行:

在django_apscheduler的配置中,在django的配置文件中添加"DJANGO_APPSCHEDULER_SINGLETON = True",这样会强制只使用一个调度实例,避免每个进程都触发调度。

在uWSGI中设置"single-interpreter = true",这个设置会确保两个进程共用同一个Python解释器实例,也能避免重复调度。
在任务函数中添加锁保证同时只有一个进程在执行,例如:
pythonCopy codeimport locking
lock = locking.get_lock("my_lock")
with lock:
# 执行任务函数
如果使用数据库去记录任务执行结果,注意保证事务的完整性,避免重复插入记录。
根据业务需求,可以只在一个指定进程中运行定时任务,另一个进程专注处理请求。在uWSGI中可以通过进程编号指定。
检查定时任务的触发设置,确保只被添加了一次,不会存在重复的调度。

综合使用以上几点,可以有效避免和解决django_apscheduler在多进程uWSGI下定时任务被重复执行的问题。

不一定需要每一种方法都去操作,可以根据实际情况选择采取一种或几种方法来解决定时任务在多进程环境下重复执行的问题:

如果使用的是django_apscheduler,设置"DJANGO_APPSCHEDULER_SINGLETON = True"就可以避免重复调度,这是最简单的解决方案。
如果不想代码侵入,可以直接在uWSGI中通过"single-interpreter = true"来解决,让多个进程共享一个解释器实例。
如果任务可以确保幂等性,也可以仅仅添加任务函数锁,但需要考虑锁的性能影响。
可以结合业务需要,在一个进程中运行任务,另一个处理请求来隔离。
检查定时任务的配置和触发器是否重复是必要的。
其他像数据库锁、事务等可以根据需要决定是否采取。

所以不一定非要全部采取,建议从简单可行的做起,比如单例模式或者uWSGI interpreter配置。也可以结合业务需求,在一个进程中运行任务,逐步排查优化。根据实际效果来决定是否需要更多手段结合使用。

目的是用最简单高效的方式解决进程重复执行的问题,不要过度设计,采取与业务匹配的解决方案。

方法2

uwsgi的lazy-apps参数可以让uwsgi在fork工作进程之后再加载Django应用,这样每个工作进程都会有自己的Django实例和apscheduler线程。这样可以避免多个工作进程共享同一个apscheduler线程导致的任务重复执行。

要使用lazy-apps参数,您可以在uwsgi的配置文件中添加以下内容:

[uwsgi]lazy-apps = true

方法3

原理占用一个端口,如果占用就不在启动,确定是浪费一个端口

import socket

scheduler = BackgroundScheduler()
# 添加一个数据库任务存储
scheduler.add_jobstore(DjangoJobStore(), 'default')
try:
    soc = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    soc.bind(('127.0.0.1', 45672))
except Exception as e:
    logger.warning(f'定时任务已启动{e}')
else:
    scheduler.start()
有关使用上的问题,欢迎您在底部评论区留言,一起交流~

读者评论

评论会同步写入该文在 Notion 中的页面底部(与正文同页,便于管理)。

0/1500

暂无评论,欢迎抢沙发。