2016-11-23 5 views
0

브라우저에 www.xxx.xx/stopwork를 입력하면 z 프로세스를 종료하고 싶습니다. 내가 시도Flask, 어설 션 오류

는 : - 프로세스가 중지됩니다 예상대로

@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는()를 다시 시작,하지만 난 브라우저에 오류가 있습니다

내부 서버 오류 서버에 내부 오류가 발생하여 요청을 완료 할 수 없습니다

합니다. 서버가 과부하되었거나 응용 프로그램에 오류가 있습니다.

그리고 응용 프로그램에서 오류 : % 엔드 포인트) AssertionError를 :보기 기능 매핑 기존 엔드 포인트 기능을 덮어 쓰기한다 : '%의 기존 엔드 포인트 기능'

stopwork

설정하는 방법이 있나요 z.terminate가 실행 된 후 끝 점이 공백으로 표시됩니까? 따라서 나중에 덮어 쓰기가 발생하지 않습니다.

+0

무엇이'def (workit)'입니까? 'def dowork()'안에 있습니까? – ettanany

+0

나는 편집했다. 이제는 더 분명해질 것입니다. 예, dowork() 안에 있습니다. 보시다시피 workit()은 프로세스가됩니다. – Lucas

+0

들여 쓰기가 잘못 되었기 때문에 코드를 따라하기가 어렵지만 어딘가에 함수 호출 안에서'@ app.route ('/ stopwork', methods = [ 'POST'])'가 있습니다. 라인을 처음 실행하면 엔드 포인트가 등록됩니다. 두 번 실행하면 엔드 포인트를 다시 등록하려고 시도하고 실패합니다. dowork와 동일한 레벨에서'stopwork'을 정의해야합니다. 그러면 단 한 번만 끝점을 등록하십시오. – dirn

답변

0

정상적으로 작동하지 않습니다. 심지어 한 번. 작동하는 것처럼 보일 수도 있지만 웹 응용 프로그램은 단일 프로세스가 아닌 단일 스레드로 보장되지 않습니다. 따라서 중지 요청은 시작 요청이 처리 된 것보다 다른 스레드 또는 프로세스에 의해 처리 될 수 있습니다.

요청에 대한 어떤 값도 명시 적으로 유지하지 않는 한 다른 요청에서 액세스 할 수 있다고 기대할 수 없습니다. 쿠키 또는 데이터베이스에서. A 부분 값이 외부 운영 체제 레벨 프로세스이기 때문에 Process 인스턴스를 그런 식으로 유지할 수 없습니다. 중지 요청이있을 때 프로세스 ID와 상위 프로세스 ID를 저장하여이 쌍을 인식 할 수 있습니다. 이것에 대한 세션 쿠키를 사용하는 방법 다음 예제 :

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')) 

그것은 부모 프로세스 'PID를 얻을 수 psutil를 사용하고 프로세스를 종료 할 수 있습니다.

"해결책"에는 몇 가지 단점이 있습니다. 브라우저가 다른 탭/창에서 쿠키를 분리 할 수 ​​있도록 허용하는 경우 브라우저 당 프로세스를 시작하거나 동일한 브라우저에서 여러 프로세스를 시작할 수 있습니다. Firefox는 개인 창 기능으로이를 수행합니다. 그리고 프로세스를 중지하려면 쿠키가 필요합니다. 따라서 쿠키를 차단하거나 지우면 중지 버튼을 사용하여 더 이상 프로세스를 중지 할 수 없습니다. 다시 Firefox 예제 : 개인 창을 닫으면 쿠키가 사라집니다.

더 나은 해결책이라 할지라도 데이터베이스에있는 서버의 시작된 프로세스를 식별하기 위해 데이터를 저장해야합니다. Flask는 데이터베이스에 의존하지 않기 때문에 예를 선택했을 때보 다 웹 애플리케이션에서 전혀 다른 데이터베이스 접근 방식을 사용할 수 있으므로 예제가 없습니다.

+0

우수 작품 BlackJack,이 문제에 대해 내 눈을 열었습니다. MySQL 데이터베이스를 사용하여 솔루션을 적용하는 방법을 알아 보는 것이 매우 교육적입니다. – Lucas