您好, 欢迎来到 !    登录 | 注册 | | 设为首页 | 收藏本站

确保只有一个工作进程在运行多个工作进程的金字塔web应用程序中启动apscheduler事件

确保只有一个工作进程在运行多个工作进程的金字塔web应用程序中启动apscheduler事件

由于Gunicorn开始用8名工人(在你的例子),这fork了该程序8次进8点的过程。这8个流程是从Master流程派生的,Master流程监视每个流程的状态并具有添加/删除工作人员的能力。

每个进程都会获取你的APScheduler对象的副本,该对象最初是你主流程的APScheduler的精确副本。这导致每个“第n个”工作人员(进程)总共执行“ n”次作业。

解决此问题的方法是使用以下选项来运行gunicorn:

env/bin/gunicorn module_containing_app:app -b 0.0.0.0:8080 --workers 3 --preload

该–preload标志告诉Gunicorn“ 在派生工作进程之前加载应用程序 ”。这样,每个工作人员都“获得了已由Master实例化的应用程序副本,而不是实例化了应用程序本身”。这意味着以下代码在主进程中仅执行一次:

rerun_monitor = Scheduler()
rerun_monitor.start()
rerun_monitor.add_interval_job(job_to_be_run,\
            seconds=JOB_INTERVAL)

此外,我们需要将Jobstore设置为:memory:以外的其他值。这样,尽管每个工作程序都是自己的独立进程,无法与其他7个进程进行通信,但通过使用本地数据库(而不是内存),我们可以保证一个作业库上的CRUD操作的“真点”。

from apscheduler.schedulers.background import BackgroundScheduler
from apscheduler.jobstores.sqlalchemy import sqlAlchemyJobStore

rerun_monitor = Scheduler(
    jobstores={'default': sqlAlchemyJobStore(url='sqlite:///jobs.sqlite')})
rerun_monitor.start()
rerun_monitor.add_interval_job(job_to_be_run,\
            seconds=JOB_INTERVAL)

最后,由于要执行BackgroundScheduler,我们要使用它start()。当我们调用start()BackgroundScheduler时,将在后台启动一个新线程,该线程负责调度/执行作业。这很重要,因为请记住在步骤(1)中,由于我们的–preload标志,我们start()在Master Gunicorn过程中仅执行一次该功能。根据定义,分叉的进程不会继承其父级的线程,因此每个工作进程都不会运行BackgroundScheduler线程。

from apscheduler.jobstores.sqlalchemy import sqlAlchemyJobStore

rerun_monitor = BackgroundScheduler(
    jobstores={'default': sqlAlchemyJobStore(url='sqlite:///jobs.sqlite')})
rerun_monitor.start()
rerun_monitor.add_interval_job(job_to_be_run,\
            seconds=JOB_INTERVAL)

所有这些的结果是,每个Gunicorn工人都有一个APScheduler,该APScheduler被欺骗为“ STARTED”状态,但实际上并没有运行,因为它会丢弃其父线程!每个实例还能够更新作业存储数据库,只是不执行任何作业!

其他 2022/1/1 18:22:09 有514人围观

撰写回答


你尚未登录,登录后可以

和开发者交流问题的细节

关注并接收问题和回答的更新提醒

参与内容的编辑和改进,让解决方法与时俱进

请先登录

推荐问题


联系我
置顶