我一直在努力尝试解决这个问题,希望其他人已经遇到了这个问题,并且知道如何解决它:)
我正在尝试构建一个非常简单的Flask端点,该端点只需要调用长时间运行的阻塞php
脚本(请考虑while true {...}
)。我尝试了几种不同的方法来异步启动脚本,但是问题是,即使执行脚本运行后生成响应的代码,我的浏览器也从未真正收到响应。
我尝试同时使用multiprocessing
和threading
,但似乎都无法使用:
# multiprocessing attempt
@app.route('/endpoint')
def endpoint():
def worker():
subprocess.Popen('nohup php script.php &', shell=True, preexec_fn=os.setpgrp)
p = multiprocessing.Process(target=worker)
print '111111'
p.start()
print '222222'
return json.dumps({
'success': True
})
# threading attempt
@app.route('/endpoint')
def endpoint():
def thread_func():
subprocess.Popen('nohup php script.php &', shell=True, preexec_fn=os.setpgrp)
t = threading.Thread(target=thread_func)
print '111111'
t.start()
print '222222'
return json.dumps({
'success': True
})
在两种情况下,我都看到111111
和222222
,但是我的浏览器仍然挂在端点的响应上。我已经尝试过p.daemon = True
和p.terminate()
的过程,但是没有运气。我曾希望在不同的外壳中启动带有nohup的脚本,并且可以使用单独的进程/线程,但是以某种方式会影响Flask或uWSGI。
由于当我直接使用python app.py
启动Flask应用并直接通过My Nginx代理和uWSGI来直接运行Flask应用时,这在我的Mac上确实可以在我的Mac上运行,所以我开始相信它可能不是代码本身那有问题。而且因为我的Nginx只是将请求转发到uWSGI,所以我相信可能是引起该请求的原因。
这是uWSGI网域的ini配置,我在皇帝模式下运行:
[uwsgi]
protocol = uwsgi
max-requests = 5000
chmod-socket = 660
master = True
vacuum = True
enable-threads = True
auto-procname = True
procname-prefix = michael-
chdir = /srv/www/mysite.com
module = app
callable = app
socket = /tmp/mysite.com.sock
答案 0 :(得分:3)
这类内容是Python Celery
(http://www.celeryproject.org/)的实际且可能是主要用例。通常,请勿运行wsgi
进程中受CPU限制的长时间运行的作业。这很棘手,效率低下,最重要的是,它比在芹菜工人中设置 async 任务要复杂得多。如果只想制作原型,可以将代理设置为memory
,而不使用外部服务器,或者在同一台计算机上运行单线程的redis
。
这样,您可以启动任务,调用正在阻塞的task.result()
,但它以 IO绑定方式,或更高的速度阻塞,您可以通过以下方式立即返回检索task_id
并构建第二个端点 /result?task_id=<task_id>
,以检查结果是否可用:
result = AsyncResult(task_id, app=app)
if result.state == "SUCCESS":
return result.get()
else:
return result.state # or do something else depending on the state
通过这种方式,您将拥有一个最适合的无阻塞wsgi
应用程序:短时间的CPU无限制调用最多具有IO调用,且具有OS级调度,然后您可以直接依赖于wsgi
服务器workers|processes|threads
或您需要在任何wsgi服务器(例如uwsgi,gunicorn等)中扩展API来满足99%的工作负荷的芹菜,因为芹菜通过增加工作进程数来水平扩展。 / p>
答案 1 :(得分:0)
这种方法对我有用,它在命令行中调用超时命令(睡眠10秒),并使其在后台工作。它立即返回响应。
@app.route('/endpoint1')
def endpoint1():
subprocess.Popen('timeout 10', shell=True)
return 'success1'
但是,不是在WSGI服务器上进行测试,而是在本地进行测试。