来自烧瓶端点的长期运行脚本

时间:2018-09-19 03:26:53

标签: python python-2.7 flask uwsgi

我一直在努力尝试解决这个问题,希望其他人已经遇到了这个问题,并且知道如何解决它:)

我正在尝试构建一个非常简单的Flask端点,该端点只需要调用长时间运行的阻塞php脚本(请考虑while true {...})。我尝试了几种不同的方法来异步启动脚本,但是问题是,即使执行脚本运行后生成响应的代码,我的浏览器也从未真正收到响应。

我尝试同时使用multiprocessingthreading,但似乎都无法使用:

# 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
  })

在两种情况下,我都看到111111222222,但是我的浏览器仍然挂在端点的响应上。我已经尝试过p.daemon = Truep.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

2 个答案:

答案 0 :(得分:3)

这类内容是Python Celeryhttp://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服务器上进行测试,而是在本地进行测试。