烧瓶,断言错误

时间:2016-11-23 14:48:37

标签: python flask

我想在浏览器中输入www.xxx.xx / stopwork时终止z进程。

我试过了:

@app.route('/dowork',methods=['POST'])

def dowork():
...............
      def workit():
        ...................

       z = Process(target=workit)


       z.start()

       @app.route('/stopwork', methods=['POST'])

       def stopwork():

       z.terminate()

       return redirect('/') 

return redirect('/')

它应该工作 - 进程停止。当我想从浏览器再次调用/ dowork时。 dowork()再次启动,但我在浏览器中出错:

内部服务器错误

服务器遇到内部错误,无法完成您的请求。服务器过载或应用程序出错。

来自应用程序的错误:

现有的端点功能:%s' %端点) AssertionError:视图函数映射正在覆盖现有的端点函数:stopwork

有没有办法在执行z.terminate后将端点设置为空白?所以以后没有覆盖?

1 个答案:

答案 0 :(得分:0)

它不能正常工作。从来没有。它似乎可行,但Web应用程序不保证是单线程的,甚至不是单个进程。因此,停止请求可以由与处理启动请求不同的线程甚至进程处理。

您不能指望请求中的任何值可以在另一个请求中访问,除非您以某种方式明确地保留它。在cookie或数据库中。 Process实例不能以这种方式持久化,因为它的一部分值是外部操作系统级进程。您可以保存其进程ID以及其父进程ID,以确保在发出停止请求时识别该对。这是一个如何使用会话cookie的示例:

from multiprocessing import Process
from time import sleep

import psutil
from flask import Flask, redirect, session, url_for


app = Flask(__name__)
app.secret_key = 'f\xa9\x85\xf0\xe9\x982\xc4\xf8\xa0k\x91\xa7\xef\x12y'


@app.route('/')
def index():
    return (
        '<form action="/work/start" method="POST">'
            '<input type="submit" value="Start">'
        '</form>'
        '<form action="/work/stop" method="POST">'
            '<input type="submit" value="Stop">'
        '</form>'
    )


def work_it():
    while True:
        print('working...')
        sleep(1)


@app.route('/work/start', methods=['POST'])
def start_work():
    if 'work_process' not in session:
        process = Process(target=work_it)
        process.start()
        pid = process.pid
        parent_pid = psutil.Process(process.pid).parent().pid
        session['work_process'] = (parent_pid, pid)
    return redirect(url_for('index'))


@app.route('/work/stop', methods=['POST'])
def stop_work():
    if 'work_process' in session:
        parent_pid, pid = session['work_process']
        try:
            process = psutil.Process(pid)
            if process.parent().pid == parent_pid:
                process.terminate()
        except psutil.NoSuchProcess:
            pass
        session.pop('work_process')
    return redirect(url_for('index'))

它使用psutil来获取父进程的PID并终止进程。

这种“解决方案”有一些缺点。如果浏览器允许从不同的选项卡/窗口中分离cookie,则可以按浏览器启动进程,甚至可以从同一浏览器启动进程。 Firefox正在使用私有窗口功能执行此操作。要停止进程,需要cookie。因此,如果您阻止或删除cookie,则无法使用“停止”按钮停止该过程。再次以Firefox为例:关闭私人窗口时,其cookie已消失。

因此,对于更好或甚至是真正的解决方案,您需要存储数据以在某些数据库中识别服务器上的已启动进程。由于Flask与数据库无关,因此我没有提供一个示例,因为您可能在Web应用程序中使用了与我为示例选择的完全不同的数据库方法。