基于某些原因可能在开发的时候通过django的manage.py运行定时任务没有任何的问题,但是一旦到了线上环境通过nginx+uwsgi来运行就会发现定时任务不断的重复执行,并且基本都执行失败了。发生这个问题的原因在于uwsgi启动了多个进程来提供服务,于是每次启动的时候定时任务都会跟着再启动一次,于是有4个进程的话,对应的服务就会启动4次,除了第一次可能执行成功后面的基本都会挂掉。
要解决这个问题其实也不难,只要保证在第一次启动的时候添加定时任务并且执行,以后启动的进程不再处理定时任务即可。但是在这种条件下通过python的进程互斥其实貌似并不是非常好使,具体可以看这个:
uWSGI employs some tricks which disable the Global Interpreter Lock and with it, the use of threads which are vital to the operation of APScheduler. To fix this, you need to re-enable the GIL using the
--enable-threads
switch. See the uWSGI documentation for more details.Also, assuming that you will run more than one worker process (as you typically would in production), you should also read the next section.
https://apscheduler.readthedocs.io/en/latest/faq.html#how-can-i-use-apscheduler-with-uwsgi
基于这个原因其实可以自己来创建相关的互斥,保证只有一个运行即可,解决方法1:
import sys, socket
try:
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.bind(("127.0.0.1", 47200))
except socket.error:
print "!!!scheduler already started, DO NOTHING"
else:
from apscheduler.schedulers.background import BackgroundScheduler
scheduler = BackgroundScheduler()
scheduler.start()
print "scheduler started"
解决方法2:
import atexit
import fcntl
from flask_apscheduler import APScheduler
def init(app):
f = open("scheduler.lock", "wb")
try:
fcntl.flock(f, fcntl.LOCK_EX | fcntl.LOCK_NB)
scheduler = APScheduler()
scheduler.init_app(app)
scheduler.start()
except:
pass
def unlock():
fcntl.flock(f, fcntl.LOCK_UN)
f.close()
atexit.register(unlock)
https://www.cnblogs.com/shenckicc/p/7019639.html?utm_source=itdadao&utm_medium=referral
解决问题的思想都是一致的,我用的是第一种方法。
2 comments
只保证一个apscheduler运行的话,那为什么不单独跑一个uwsgi进程呢?这种方法简单高效
单独跑一个那是不是整个服务器上就只有一个uwsgi进程提供服务了?如果不是,要是在启动另外的进程那么还是会重复启动。