Apscheduler 多次执行作业

dae*_*n24 5 django uwsgi apscheduler

我有一个使用 uwsgi(有 10 个工人)+ ngnix 运行的 django 应用程序。我正在使用 apscheduler 进行调度。每当我安排一项工作时,它都会被多次执行。从这些答案ans1ans2我了解到这是因为调度程序是在uwsgi 的每个工作人员中启动的。我通过按照本答案中的建议将调度程序绑定到套接字并在数据库中保持状态来对调度程序进行有条件的初始化,以便仅启动一个调度程序实例,但仍然存在相同的问题,有时在创建时也存在发现调度程序未运行的作业并且该作业保持挂起且未执行。

我正在使用以下代码在 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
Run Code Online (Sandbox Code Playgroud)

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

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
Run Code Online (Sandbox Code Playgroud)

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

  • 如果我不限制在每个工人中运行多个调度程序,则该作业将执行多次。
  • 但是,如果我限制在一个 worker 中只运行一个调度程序,则某些作业会一直挂起而不执行。

有什么办法解决这个问题?

The*_*inn 5

让我们考虑以下事实:

(1) 默认情况下,UWSGI分叉其工作线程之前将您的 Django 应用程序预加载到 UWSGI 主进程的内存中。

(2) UWSGI从master“分叉”worker,这意味着它们本质上被复制到每个worker的内存中。由于如何fork()实现,子进程(即工作线程)不会继承父进程的线程。

(3) 当您调用 时BackgroundScheduler.start(),会创建一个线程,该线程负责在调用此函数的任何工作人员/主设备上执行作业。

您必须做的就是在创建任何工人之前调用BackgroundScheduler.start()Master 进程。通过这样做,当工作人员被创建时,他们将不会继承 BackgroundScheduler 线程(上面的#2),因此不会执行任何作业(但他们仍然可以通过与作业存储通信来安排/修改/删除作业!)。

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

mysite/
manage.py
mysite/
    __init__.py
    settings.py
    urls.py
    wsgi.py
Run Code Online (Sandbox Code Playgroud)

陷阱:

不要“在 django 应用程序的 urls 中初始化 [e] apscheduler ......这将在应用程序启动时启动调度程序。” 这些可能由每个工作人员加载,因此start()被执行多次。

不要在“lazy-app ”模式下启动 UWSGI 服务器,这将在每个工作人员创建后加载应用程序。

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

这篇文章可能会为您提供更多详细信息,仅适用于 Gunicorn(WSGI 服务器)环境。