当我启用 uwsgi 线程支持并启动调度程序时,api 停止工作
When I enable uwsgi thread support and start the scheduler the api stops working
我是 python、flask、nginx 和所有这些东西的新手。
我有一个 flask 应用程序作为前端的 API。此外,当 flask 应用程序启动时,我想使用 APScheduler 启动计划任务。
问题是,当我启用 uwsgi 线程支持并启动调度程序时,api 停止工作(504 网关超时)。但调度程序的工作方式与日志文件中所示相同。当我删除调度程序/线程支持时,api 可以工作,但我显然不再有调度程序了。
我怀疑调度程序以某种方式阻止了烧瓶应用程序 运行 正确?
由于我对这些技术不熟悉,因此我将 post 下面的设置。如果您需要更多文件信息,请告诉我。(整个过程是 raspberry pi 上的 运行,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
WARNING:apscheduler.scheduler:已跳过作业"startHandlerJob (trigger: cron[minute=''], next run at: 2019-12-18 19:01:00 CET)" 的执行:已达到 运行ning 实例的最大数量 (1)
DEBUG:apscheduler.scheduler:下次唤醒时间为 2019-12-18 19:02:00+01:00(59.980780 秒后)
DEBUG:apscheduler.scheduler:正在寻找 运行 的工作
WARNING:apscheduler.scheduler:已跳过作业 "startHandlerJob (trigger: cron[minute=''], next run at: 2019-12-18 19:02:00 CET)" 的执行:已达到 运行ning 实例的最大数量 (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 网关超时响应。当我删除调度程序并禁用线程支持时,此调用将按预期工作。
感谢任何帮助。可能我遗漏了一些明显的东西,因为我对所有这些东西都是陌生的。
谢谢!
我有点犹豫要不要把这个作为答案,但这里是...
在uwsgi app.ini设置进程后(你的情况是5,我用4)我也设置了
threads = 2
。我不知道这是否与 --enable-threads
选项有任何直接关系,因为这似乎是为了让您的应用程序启动它自己的线程,但它可能有助于 uwsgi 在每个进程中拥有自己的线程。 UWSGI 文档还指出(某处)进程越多不一定越好。
此外,您的日志文件显示来自调度程序的警告,表明已达到 运行ning 实例的最大数量。我认为这意味着您给调度程序的工作没有在下一个预定 运行(1 分钟后)之前完成?如果是这样,它是否卡在某个地方,阻止了其他一切?
最后,如果一切都失败了,文档中的其他内容 (UWSGI Security and availability)
A common problem with webapp deployment is “stuck requests”. All of your threads/workers are stuck (blocked on request) and your app cannot accept more requests. To avoid that problem you can set a harakiri timer.It is a monitor (managed by the master process) that will destroy processes stuck for more than the specified number of seconds (choose harakiri value carefully).
最后,最后 :) 有一个类似 top 的 uwsgi 监控工具,可以方便地查看发生了什么,只是
pip install uwsgitop
uwsgitop 127.0.0.1:9191
加上 telnet 到 adress:port 显然可以向您显示更多信息(我自己还没有尝试过)。
好的,谢谢你的回答。我没有让它与您建议的解决方案一起使用。因此,我简单地决定 运行 调度程序作为单独的 systemd 服务。这样调度就不会阻止烧瓶 api 工作。
我遇到了完全相同的问题。我的解决方法是使用 ProcessPoolExecutor
而不是 ThreadPoolExecutor
.
由于某些未知原因(至少我不知道),当 ThreadPoolExecutor
中有多个线程时,该死的问题就出现了。
在我将大多数 cpu-bound 线程更改为进程后(即对这些作业使用 ProcessPoolExecutor
),该死的问题消失了...
我是 python、flask、nginx 和所有这些东西的新手。
我有一个 flask 应用程序作为前端的 API。此外,当 flask 应用程序启动时,我想使用 APScheduler 启动计划任务。
问题是,当我启用 uwsgi 线程支持并启动调度程序时,api 停止工作(504 网关超时)。但调度程序的工作方式与日志文件中所示相同。当我删除调度程序/线程支持时,api 可以工作,但我显然不再有调度程序了。 我怀疑调度程序以某种方式阻止了烧瓶应用程序 运行 正确?
由于我对这些技术不熟悉,因此我将 post 下面的设置。如果您需要更多文件信息,请告诉我。(整个过程是 raspberry pi 上的 运行,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
WARNING:apscheduler.scheduler:已跳过作业"startHandlerJob (trigger: cron[minute=''], next run at: 2019-12-18 19:01:00 CET)" 的执行:已达到 运行ning 实例的最大数量 (1) DEBUG:apscheduler.scheduler:下次唤醒时间为 2019-12-18 19:02:00+01:00(59.980780 秒后) DEBUG:apscheduler.scheduler:正在寻找 运行 的工作 WARNING:apscheduler.scheduler:已跳过作业 "startHandlerJob (trigger: cron[minute=''], next run at: 2019-12-18 19:02:00 CET)" 的执行:已达到 运行ning 实例的最大数量 (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 网关超时响应。当我删除调度程序并禁用线程支持时,此调用将按预期工作。
感谢任何帮助。可能我遗漏了一些明显的东西,因为我对所有这些东西都是陌生的。 谢谢!
我有点犹豫要不要把这个作为答案,但这里是...
在uwsgi app.ini设置进程后(你的情况是5,我用4)我也设置了
threads = 2
。我不知道这是否与 --enable-threads
选项有任何直接关系,因为这似乎是为了让您的应用程序启动它自己的线程,但它可能有助于 uwsgi 在每个进程中拥有自己的线程。 UWSGI 文档还指出(某处)进程越多不一定越好。
此外,您的日志文件显示来自调度程序的警告,表明已达到 运行ning 实例的最大数量。我认为这意味着您给调度程序的工作没有在下一个预定 运行(1 分钟后)之前完成?如果是这样,它是否卡在某个地方,阻止了其他一切?
最后,如果一切都失败了,文档中的其他内容 (UWSGI Security and availability)
A common problem with webapp deployment is “stuck requests”. All of your threads/workers are stuck (blocked on request) and your app cannot accept more requests. To avoid that problem you can set a harakiri timer.It is a monitor (managed by the master process) that will destroy processes stuck for more than the specified number of seconds (choose harakiri value carefully).
最后,最后 :) 有一个类似 top 的 uwsgi 监控工具,可以方便地查看发生了什么,只是
pip install uwsgitop
uwsgitop 127.0.0.1:9191
加上 telnet 到 adress:port 显然可以向您显示更多信息(我自己还没有尝试过)。
好的,谢谢你的回答。我没有让它与您建议的解决方案一起使用。因此,我简单地决定 运行 调度程序作为单独的 systemd 服务。这样调度就不会阻止烧瓶 api 工作。
我遇到了完全相同的问题。我的解决方法是使用 ProcessPoolExecutor
而不是 ThreadPoolExecutor
.
由于某些未知原因(至少我不知道),当 ThreadPoolExecutor
中有多个线程时,该死的问题就出现了。
在我将大多数 cpu-bound 线程更改为进程后(即对这些作业使用 ProcessPoolExecutor
),该死的问题消失了...