2017-05-11 14 views
0

새로운 스레드에서 플라스크 서버를 열고 파이썬이 실행중인 프로그램에 대한 정보를 제공하는 파이썬 디버깅 라이브러리를 작성하고 있습니다. 디버깅중인 프로그램이 웹 서버 자체가 아니라면 제대로 작동합니다. 그러나 디버그 모드에서 실행중인 다른 플라스크 서버와 동시에 실행하려고하면 문제가 발생합니다. 두 번째 서버에 액세스하려고하면 결과가 두 서버간에 번갈아 나타납니다. 내 브라우저에서 http://localhost:5002/를 방문 할 때 하나의 파이썬 프로그램 아래 두 개의 포트에있는 두개의 쓰레드/프로세스에서 두 개의 플라스크 서버를 실행할 수 있습니까?

from flask.app import Flask 
from threading import Thread 

# app1 represents my debugging library 

app1 = Flask('app1') 

@app1.route('/') 
def foo(): 
    return '1' 

Thread(target=lambda: app1.run(port=5001)).start() 

# Cannot change code after here as I'm not the one writing it 

app2 = Flask('app2') 

@app2.route('/') 
def bar(): 
    return '2' 

app2.run(debug=True, port=5002) 

지금, 결과는 1 또는 2 대신 지속적으로 2되는 수 있습니다 중 하나

다음은 예입니다.

Thread 대신 multiprocessing.Process을 사용하면 같은 결과가 나타납니다.

어떻게 이런 일이 발생하며 어떻게 피할 수 있습니까? flask/werkzeug/WSGI를 피할 수 없는가? 나는 단순함으로 플라스크를 좋아하고 이상적으로는 그것을 계속 사용하고 싶습니다. 그렇게 할 수 없다면 동시에 사용할 수있는 다른 웹 서버를 방해하지 않을 수있는 가장 간단한 라이브러리/프레임 워크는 무엇입니까? 가능한 경우 프로세스 대신 스레드를 사용하고 싶습니다.

답변

0

(기본적으로 디버그 모드에서 사용) werkzeug의 장전 creates a new process 사용 subprocess.call, 단순화 된 것이 같은 것을 수행합니다

new_environ = os.environ.copy() 
new_environ['WERKZEUG_RUN_MAIN'] = 'true' 
subprocess.call([sys.executable] + sys.argv, env=new_environ, close_fds=False) 

이 스크립트는 경우 일반적으로 미세 인 재실행되는 것을 의미 여기에 포함 된 모든 내용은 app.run()이지만, 경우에 따라 app1과 app2가 모두 다시 시작되지만 둘 다 동일한 포트를 사용합니다. OS가 지원하는 경우 수신 대기 포트가 상위 프로세스에서 열리고 하위 프로세스가 직접 상속하여 직접 사용하므로 environment variable WERKZEUG_SERVER_FD is set 인 경우

이제 동일한 소켓을 사용하는 두 개의 다른 앱이 생겼습니다. 예를 들어

from flask.app import Flask 
from threading import Thread 
import os 

app1 = Flask('app1') 

@app1.route('/') 
def foo(): 
    return '1' 

def start_app1(): 
    print("starting app1") 
    app1.run(port=5001) 

app2 = Flask('app2') 

@app2.route('/') 
def bar(): 
    return '2' 

def start_app2(): 
    print("starting app2") 
    app2.run(port=5002, debug=True) 

if __name__ == '__main__': 
    print("PID:", os.getpid()) 
    print("Werkzeug subprocess:", os.environ.get("WERKZEUG_RUN_MAIN")) 
    print("Inherited FD:", os.environ.get("WERKZEUG_SERVER_FD")) 
    Thread(target=start_app1).start() 
    start_app2() 

이 인쇄 :

 
PID: 18860 
Werkzeug subprocess: None 
Inherited FD: None 
starting app1 
starting app2 
* Running on http://127.0.0.1:5001/ (Press CTRL+C to quit) 
* Running on http://127.0.0.1:5002/ (Press CTRL+C to quit) 
* Restarting with inotify reloader 
PID: 18864 
Werkzeug subprocess: true 
Inherited FD: 4 
starting app1 
starting app2 
* Debugger is active! 

당신이

if __name__ == '__main__': 
    if os.environ.get("WERKZEUG_RUN_MAIN")) != 'true': 
     Thread(target=start_app1).start() 
    start_app2() 

에 시작 코드를 변경하는 경우 일부 출력, 예를 추가하는 경우

당신이 더 잘 볼 수 있습니다 올바르게 작동해야하며 reloader에 의해 app2 만 다시로드됩니다. 그러나 디버그 모드를 사용하여 암시 된 다른 스레드가 아닌 별도의 프로세스에서 실행됩니다. 이를 방지하기 위해

해킹을 사용하는 것입니다 :

if __name__ == '__main__': 
    os.environ["WERKZEUG_RUN_MAIN"] = 'true' 
    Thread(target=start_app1).start() 
    start_app2() 

는 이제 장전이 이미 서브 프로세스에서 실행중인 생각하고 새로운 시작되지 않는, 모든 것이 동일한 프로세스에서 실행됩니다. 다시로드하면 작동하지 않으며 어떤 부작용이 있는지 알 수 없습니다.