2017-05-11 23 views
0

新しいスレッドでフラスコサーバーを開き、実行中のプログラムに関する情報を提供するPythonデバッグライブラリを作成しています。これは、デバッグされているプログラムがWebサーバー自体でない場合にうまく動作します。しかし、デバッグモードで動作している別のフラスコサーバーと同時に実行しようとすると、物事が壊れます。 2番目のサーバーにアクセスしようとすると、2つのサーバー間で結果が交互になります。2つのスレッド/プロセスで2つのフラスコサーバーを1つのPythonプログラムの下で2つのポートで実行するにはどうすればよいですか?

はここでの例です:私は私のブラウザで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) 

さて、その結果は、代わりに一貫し2という1または2いずれであってもよいです。

Threadの代わりにmultiprocessing.Processを使用しても同じ結果が得られます。

これはどうして起こりますか?どのように回避できますか?フラスコ/ワルキューグ/ WSGIでやむを得ないことはありますか?私はシンプルさのためにフラスコが好きで、理想的にはそれを使い続けたいと思っています。それが不可能な場合、同時に実行されている他のWebサーバーに干渉しないように私が使用できる最も単純なライブラリ/フレームワークは何ですか?可能であれば、プロセスの代わりにスレッドを使用したいと思います。

答えて

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

これで、同じソケットを使用していても、2つの異なるアプリが使用できるようになりました。

あなたには、いくつかの出力を追加する場合には、例えば、このより良いを見ることができます:

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

にスタートアップコードを変更した場合正しく動作するはずです.app2のみがリロードされます。ただし、別のスレッドではなく、別のプロセスで実行されます。これは、デバッグモードを使用することによって暗示されます。これを回避する

ハックを使用することです:

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

今リロード機能は、それがすでにサブプロセスで実行していると考えて、新しいものを開始していない、すべてが同じプロセスで実行されます。リロードは機能しませんし、他にどんな副作用があるかもわかりません。

関連する問題