Apscheduler多次执行工作

时间:2016-08-31 15:25:53

标签: django uwsgi apscheduler

我有一个运行uwsgi(有10个工人)+ ngnix的django应用程序。我正在使用apscheduler进行调度。每当我安排一份工作时,它都会被执行多次。从这些答案ans1ans2我知道这是因为调度程序是在每个uwsgi工作者中启动的。我按照answer中的建议将调度程序绑定到套接字,并通过在db中保持状态来完成调度程序的条件初始化,这样只会启动一个调度程序实例,但仍存在相同的问题,有时候,在创建作业时,发现调度程序没有运行,并且作业保持挂起而不执行。

我正在使用以下代码在django应用程序的URL中初始化apscheduler。这将在应用程序启动时启动调度程序。

def job_listener(ev):
    print('event',ev)


job_defaults = {
    'coalesce': True,  
    'max_instances': 1
}

scheduler = BackgroundScheduler(job_defaults=job_defaults, timezone=TIME_ZONE, daemon=False)
scheduler.add_jobstore(MongoDBJobStore(client=client), 'default')
scheduler.add_executor(ThreadPoolExecutor(), 'default')
scheduler.add_executor(ProcessPoolExecutor(),'processpool')
scheduler.add_listener(job_listener)


def initialize_scheduler():
    try:
        if scheduler_db_conn.find_one():
            print('scheduler already running')
            return True
        scheduler.start()
        scheduler_db_conn.save({'status': True})
        print('---------------scheduler started --------------->')
        return True
    except:
        return False

我使用以下代码创建作业。

from scheduler_conf import scheduler
def create_job(arg_list):
    try:
        print('scheduler status-->',scheduler.running)
        job = scheduler.add_job(**arg_list)
        return True
    except:
        print('error in creating Job')
        return False

我无法正确配置和运行调度程序。我已经提到了apschedule中的所有主题,但仍然没有得到解决方案。

  • 如果我不限制在每个工作人员中运行多个调度程序,则会多次执行该作业。
  • 但是如果我只限制在一个worker内运行的一个调度程序,那么一些作业会保持挂起而不会执行。

这是解决方案吗?

2 个答案:

答案 0 :(得分:3)

让我们考虑以下事实:

(1)默认情况下,UWSGI将您的Django App预先加载到UWSGI主进程中。记忆之前分叉其工人。

(2)UWSGI" forks"来自主人的工人,意味着他们基本上被复制到每个工人的记忆中。由于fork()的实现方式,Child进程(即worker)不会继承Parent的线程。

(3)当你调用BackgroundScheduler.start()时,会创建一个线程,负责在任何w​​orker / master调用此函数时执行作业。

在创建任何工作人员之前,您必须在主要流程上致电BackgroundScheduler.start()。通过这样做,当创建工作程序时,它们不会继承BackgroundScheduler线程(上面的#2),因此不会执行任何作业(但它们仍然可以通过与jobstore通信来安排/修改/删除作业!)。 / p>

要做到这一点,只需确保在实例化应用程序的任何函数/模块中调用BackgroundScheduler.start()。例如,在以下Django项目结构中,我们(可能)希望在wsgi.py中执行此代码,这是UWSGI服务器的入口点。:

mysite/
manage.py
mysite/
    __init__.py
    settings.py
    urls.py
    wsgi.py

<强>缺陷:

在django应用程序的网址中不要&#34; initializ [e] apscheduler ....这将在应用程序启动时启动调度程序。&#34; 这些可能是由每个工作人员加载,因此start()被执行多次。

不要在"lazy-app&#34;中启动UWSGI服务器。模式,这将在每个工人创建后加载应用程序。

不要使用默认(内存)jobstore运行BackgroundScheduler。这将在所有工人之间产生裂脑综合症。对于在作业上执行的所有CRUD操作,您希望像MongoDB一样强制执行单点事实。

This post可能只会在Gunicorn(WSGI服务器)环境中为您提供更多详细信息。

答案 1 :(得分:0)

假设您想在应用程序中使用默认作业存储和默认执行程序运行 BackgroundScheduler:

from apscheduler.schedulers.background import BackgroundScheduler


scheduler = BackgroundScheduler()

这将为您提供一个 BackgroundScheduler,其 MemoryJobStore 名为“default”,ThreadPoolExecutor 名为“default”,默认最大线程数为 10。

现在,假设您想减少线程数,并且还想调整新作业的默认值并设置不同的时区。以下示例将为您提供:

from pytz import utc
from apscheduler.schedulers.background import BackgroundScheduler

job_defaults = {
    'coalesce': False,
    'max_instances': 3
}
scheduler = BackgroundScheduler(job_defaults=job_defaults, timezone=utc)