【问题标题】:When I enable uwsgi thread support and start the scheduler the api stops working当我启用 uwsgi 线程支持并启动调度程序时,api 停止工作
【发布时间】:2020-04-11 10:42:36
【问题描述】:

我是 python、flask、nginx 和所有这些东西的新手。

我有一个用作前端 API 的烧瓶应用程序。此外,当启动烧瓶应用程序时,我想使用 APScheduler 启动计划任务。

问题是,当我启用 uwsgi 线程支持并启动调度程序时,api 停止工作(504 网关超时)。但是调度程序的工作方式与日志文件中的一样。当我删除调度程序/线程支持时,api 工作,但我显然没有调度程序了。 不知何故,我怀疑调度程序会阻止烧瓶应用程序正常运行?

由于我是这些技术的新手,我将在下面发布我的设置。如果您需要更多文件信息,请告诉我。(整个过程在树莓派上运行,并且通过局域网从我的电脑访问 api)

app.service

[Unit]
Description=uWSGI instance to serve app
After=network.target

[Service]
User=pi
Group=www-data
WorkingDirectory=/home/pi/flask
Environment="PATH=/home/pi/flask/appenv/bin"
ExecStart=/home/pi/flask/appenv/bin/uwsgi --ini app.ini --enable-threads

[Install]
WantedBy=multi-user.target

app.ini

[uwsgi]
module = wsgi:app

master = true
processes = 5

socket = /home/pi/flask/app.sock
chmod-socket = 660
vacuum = true

die-on-term = true

app.py

#!/usr/bin/env python3

from flask import Flask, request
from apscheduler.schedulers.background import BackgroundScheduler

import logging
logging.basicConfig(filename='logfile.log',level=logging.DEBUG)

from api.Controller import Controller
from Handler.Handler import Handler
from apscheduler.executors.pool import ThreadPoolExecutor, ProcessPoolExecutor

api_controller = Controller()
handler = Handler()

def startHandlerJob():
    handler.ExecuteAllSensors()

app = Flask( __name__ )


@app.route('/app')
def apiDefinition():
    return 'API Definition: GetHumidityValues, TODO'

@app.route( "/app/GetHumidityValues", methods=["GET"] )
def GetHumidityValues():
    logging.info("app.py: API-call GetHumidityValues")
    return api_controller.GetHumidityValues()


if (__name__ == "__main__"):
    app.run(host='0.0.0.0')

executors = {
    'default': ThreadPoolExecutor(20),
    'processpool': ProcessPoolExecutor(5)
}
job_defaults = {
    'coalesce': False,
    'max_instances': 1
}

scheduler = BackgroundScheduler(daemon=True, executors=executors, job_defaults=job_defaults)
scheduler.start()
scheduler.add_job(startHandlerJob,'cron', minute='*')

logfile.log

警告:apscheduler.scheduler:执行作业“startHandlerJob(触发器:cron[minute=''],下次运行时间:2019-12-18 19:01:00 CET)”已跳过:最大数量已达到运行实例 (1) DEBUG:apscheduler.scheduler:下次唤醒时间为 2019-12-18 19:02:00+01:00(在 59.980780 秒内) DEBUG:apscheduler.scheduler:寻找要运行的作业 警告:apscheduler.scheduler:执行作业“startHandlerJob(触发器:cron [minute=''],下次运行时间:2019-12-18 19:02:00 CET)”跳过:运行实例的最大数量达到 (1) DEBUG:apscheduler.scheduler:下次唤醒时间为 2019-12-18 19:03:00+01:00(59.979407 秒)

systemctl 状态应用

* app.service - uWSGI instance to serve app
   Loaded: loaded (/etc/systemd/system/app.service; enabled; vendor preset: enabled)
   Active: active (running) since Wed 2019-12-18 18:40:57 CET; 23min ago
 Main PID: 21129 (uwsgi)
    Tasks: 8 (limit: 2200)
   Memory: 22.9M
   CGroup: /system.slice/app.service
           |-21129 /home/pi/flask/appenv/bin/uwsgi --ini app.ini --enable-threads
           |-21148 /home/pi/flask/appenv/bin/uwsgi --ini app.ini --enable-threads
           |-21149 /home/pi/flask/appenv/bin/uwsgi --ini app.ini --enable-threads
           |-21150 /home/pi/flask/appenv/bin/uwsgi --ini app.ini --enable-threads
           |-21151 /home/pi/flask/appenv/bin/uwsgi --ini app.ini --enable-threads
           `-21152 /home/pi/flask/appenv/bin/uwsgi --ini app.ini --enable-threads

Dec 18 18:40:57 raspberrypi uwsgi[21129]: mapped 386400 bytes (377 KB) for 5 cores
Dec 18 18:40:57 raspberrypi uwsgi[21129]: *** Operational MODE: preforking ***
Dec 18 18:40:59 raspberrypi uwsgi[21129]: WSGI app 0 (mountpoint='') ready in 2 seconds on interpreter 0xa6f900 pid: 21129 (default app)
Dec 18 18:40:59 raspberrypi uwsgi[21129]: *** uWSGI is running in multiple interpreter mode ***
Dec 18 18:40:59 raspberrypi uwsgi[21129]: spawned uWSGI master process (pid: 21129)
Dec 18 18:40:59 raspberrypi uwsgi[21129]: spawned uWSGI worker 1 (pid: 21148, cores: 1)
Dec 18 18:40:59 raspberrypi uwsgi[21129]: spawned uWSGI worker 2 (pid: 21149, cores: 1)
Dec 18 18:40:59 raspberrypi uwsgi[21129]: spawned uWSGI worker 3 (pid: 21150, cores: 1)
Dec 18 18:40:59 raspberrypi uwsgi[21129]: spawned uWSGI worker 4 (pid: 21151, cores: 1)
Dec 18 18:40:59 raspberrypi uwsgi[21129]: spawned uWSGI worker 5 (pid: 21152, cores: 1)

日志文件显示调度程序处于活动状态。但是当我尝试使用 http:/raspberryipaddress/app 时,答案是 504 Gateway Time-out 响应。当我删除调度程序并禁用线程支持时,此调用按预期工作。

感谢任何帮助。可能我遗漏了一些明显的东西,因为我对所有这些东西都不熟悉。 谢谢!

【问题讨论】:

  • 你之前发过这个,我没机会说;您是坚持使用uWSGI 还是可以将 gunicorn 与 nginx 一起使用?
  • 我遇到了非常相似的问题,但您可以将--preload 传递给gunicorn 以阻止子线程/进程尝试执行这些工作。对于uWSGI 我不知道。您可能不应该仅仅在此基础上进行切换,但也许这会给您一个起点来检查问题并找到合适的解决方案
  • 我可以随意使用我想要的任何东西。我还没有听说过gunicorn。它是否让我想要完成的任务更容易?
  • 我一直使用gunicorn,但--preload 是对我的APScheduler 问题的(看似)永久修复。无论如何,以这种方式启动并测试它是一项 5 分钟的工作,我不确定 uWSGI 可能做的其他事情,而 gunicorn 做/不做

标签: python nginx flask systemd apscheduler


【解决方案1】:

我有点犹豫是否要将此作为答案,但这里是......

在设置进程后的 uwsgi app.ini 中(在你的情况下为 5,我使用 4)我还设置了 threads = 2。我不知道这是否与 --enable-threads 选项有任何直接关系,因为这似乎是让您的应用程序启动它自己的线程,但它可能有助于 uwsgi 每个进程拥有自己的线程。 UWSGI 文档还指出(某处)更多的进程不一定更好。

此外,您的日志文件会显示来自调度程序的警告,表明已达到最大运行实例数。我认为这意味着您给调度程序的工作在下一次计划运行(1 分钟后)之前没有完成?如果是这种情况,它会卡在某个地方,阻塞其他所有东西吗?

最后,如果一切都失败了,文档中的其他内容 (UWSGI Security and availability)

webapp 部署的一个常见问题是“卡住的请求”。您的所有线程/工作人员都被卡住(根据请求被阻止)并且您的应用程序无法接受更多请求。为了避免这个问题,你可以设置一个 harakiri 计时器。它是一个监视器(由主进程管理),它将摧毁停滞超过指定秒数的进程(仔细选择 harakiri 值)。

最后,终于 :) 有一个顶级的 uwsgi 监控工具,可以方便地查看发生了什么,只是

pip install uwsgitop
uwsgitop 127.0.0.1:9191

加上远程登录到该地址:端口显然会显示更多信息(我自己还没有尝试过)。

【讨论】:

    【解决方案2】:

    好的,感谢您的回答。我没有让它与您建议的解决方案一起使用。因此,我只是决定将调度程序作为单独的 systemd 服务运行。这样调度不会停止烧瓶 api 的工作。

    【讨论】:

    • 那么您是否正在运行将python进程分开一个用于调度程序另一个用于烧瓶应用程序,它们如何通信
    猜你喜欢
    • 2021-01-14
    • 1970-01-01
    • 1970-01-01
    • 2014-05-09
    • 2017-03-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-10-30
    相关资源
    最近更新 更多