2017-09-28 20 views
0

Kubernetesで実行しているとき、特にgraceful shutdownのときに正しく動作するFlaskアプリを書き込もうとしています。Flaskでバックグラウンドタイマーを実行するには

そのように、私は、コードを持っている必要があります:

  • は、シャットダウン信号
  • を受け取る時間が 「UP」になるまで、「シャットダウンタイマー」
  • を開始
  • ノーマルとしての要求を続けます
  • その後

を自分自身をシャットダウンこれまでのところ、私が持っていることはこれです:

from flask import Flask, abort 
import signal 
import time 
app = Flask(__name__) 
shuttingDown = False 

def exit_gracefully(self, signum): 
    app.logger.error('Received shutdown signal. Exiting gracefully') 
    global shuttingDown 
    shuttingDown = True 
    # TODO: wait for some time here to ensure we are not receiving any more 
    # traffic 
    time.sleep(20) 
    exit(0) 

signal.signal(signal.SIGTERM, exit_gracefully) 

@app.route("/") 
def hello(): 
     return "Hello World!" 

@app.route("/_status/liveness") 
def liveness(): 
     return "I am alive" 

@app.route("/_status/readiness") 
def readiness(): 
     if not shuttingDown: 
      return "I am ready" 
     else: 
      abort(500, 'not ready anymore') 

"シャットダウン"信号を送信した後を除いて上記の "動作"は、シャットダウン時の "猶予期間"内にあっても "/"への通常のリクエストは応答されません)。

"time.sleep()"の呼び出しは同期しているようです。

これを「非同期」にする方法を知っている人はいますか?時間が "アップ"になるまでアプリがリクエストを処理し続けるようにするには?

+1

ウェブサーバーとしては何を使用しますか?私はKubernetesに慣れていないので、これは愚かな疑問かもしれません。あなたのHTTPサーバーを提供しているのですか、またはFlaskの内部サーバー、WSGIなどを使用していますか? – Hannu

+0

上記の組み込みFlask開発サーバーを使用しています。 – srkiNZ84

+0

下記の私の修正された回答を参照してください。それはそれを行うべきであり、代替手段も提供する。 – Hannu

答えて

1

あなたはFlask開発サーバーを内蔵していると思います。このようなFlaskとDjangoの組み込み開発サーバー、または標準ライブラリのWebサーバーまたはWSGIサーバーに基づくものは、運用システム向けではなく、通常はシグナルのシャットダウンを適切に処理しません。

このように、Apache/mod_wsgi(mod_wsgi-express)、gunicorn、またはuWSGIなどの適切なプロダクショングレードのWSGIサーバーを実際に使用する必要があります。これらはすべて適切にシグナルを処理し、コンテナのシャットダウンを遅らせる原因となるシグナルを無視する開発サーバーでは問題が発生しません。シャットダウンタイムアウトが発生したときに最終的にKubernetesによって殺されます。

+0

確かに、Flaskサーバーをビルドしてこの動作をローカルでテストしようとしていました。上記の使用に関して、WSGIサーバーが信号を受信して​​からシャットダウンを開始するまでの間に「待機時間」を構成する方法はありますか? – srkiNZ84

+0

あなたのリクエストはどのくらいですか? Apache/mod_wsgiは通常、プロセスが強制的にシャットダウンされる前に現在のリクエストを完了できるようにするために、通常は数秒です。リクエストの特定のインスタンスを排除する制御を強化する必要がある場合は、シグナルの使用とは別に管理する必要があります。アプリケーションにリクエストを送信する必要があります。これにより、応答レスポンスを準備プローブに送信して、Kubernetesがサービスのアクティブなエンドポイントからそれを削除し、新しいトラフィックを受信しないようにします。 –

+0

アクティブなリクエストのタイムアウトまたはモニタリングにより、サーバが終了したり強制終了してインスタンスが置き換えられたりする可能性があります。すべてそれは本当にあなたがしようとしていることに依存します。別々のインスタンスを起動し、どこでリクエストがルート/イングレスに移動するかを制御し、新しいトラフィックが新しいインスタンスに切り替えられるように、緑色/青色の配置を使用するほうがよいでしょう。しばらくすると、古いインスタンスがシャットダウンされます。必要なインスタンスの数が重複しているので、明らかにそれ以上のリソースが必要です。 –

0

これは内部サーバーで動作します。警告には、サーバーをシャットダウンする/ _shutdown URLがあり、これは悪意のあるシャットダウンに開放されています。これが欲しいものでない場合は、requests.post()を削除し、os._exit()のコメントを外してください。もちろん、@app.route("/_shutdown")とその機能も削除してください。

from flask import Flask, abort, request 
import signal 
import threading 
import time 
import os 
import requests 
app = Flask(__name__) 
shuttingDown = False 


def exit_call(): 
    time.sleep(20) 
    requests.post("http://localhost:5420/_shutdown") 
    # os._exit(0) 


def exit_gracefully(self, signum): 
    app.logger.error('Received shutdown signal. Exiting gracefully') 
    global shuttingDown 
    shuttingDown = True 
    # TODO: wait for some time here to ensure we are not receiving any more 
    # traffic 
    _et = threading.Thread(target=exit_call) 
    _et.daemon = True 
    _et.start() 


signal.signal(signal.SIGTERM, exit_gracefully) 


@app.route("/") 
def hello(): 
     return "Hello World!" 


@app.route("/_status/liveness") 
def liveness(): 
     return "I am alive" 


@app.route("/_shutdown", methods=["POST"]) 
def shutdown(): 
    func = request.environ.get('werkzeug.server.shutdown') 
    if func is None: 
     return "Not a werkzeug server" 
    func() 
    return "shutdown" 


@app.route("/_status/readiness") 
def readiness(): 
     if not shuttingDown: 
      return "I am ready" 
     else: 
      abort(500, 'not ready anymore') 


app.run(port=5420) 
関連する問題