2012-09-25 52 views
40

瓶破裂的管道,我想燒瓶中的應用程序發送一個本地REST請求,就像這樣:與請求

from flask import Flask, url_for, request 
import requests 

app = Flask(__name__) 

@app.route("/<name>/hi", methods=["POST"]) 
def hi_person(name): 
    form = {"name": name} 
    return requests.post(url_for("hi", _external=True), data=form) 

@app.route("/hi", methods=["POST"]) 
def hi(): 
    return 'Hi, %s!' % request.form["name"] 

發送curl -X POST http://localhost:5000/john/hi導致整個燒瓶應用程序凍結。當我發送一個殺手信號時,我得到一個破損的管道錯誤。有沒有辦法防止燒瓶在這裏凍結?

回答

89

在一個能夠處理併發請求的正確的WSGI服務器(可能是gunicornuWSGI)下運行你的燒瓶應用程序,它會工作。在開發,能夠在瓶提供的服務器線程:

app.run(threaded=True) 

但要注意,不建議在生產中使用的瓶服務器。

會發生什麼事是,使用你是一個請求您的水壺的應用程序,但由於它仍忙於處理第一個,也不會以第二次請求,直到它與第一個請求響應完成請求。

順便提一下,在Python 3下,socketserver實現處理斷開連接更優雅,並繼續服務而不是崩潰。

+0

+1,絕對))><(( –

+2

我運行螺紋WSGI應用程序,但我得到斷裂的管道反正: app.run(調試=真,螺紋=真,主機='0.0。 0.0',port = 8080) – loretoparisi

+1

@loretoparisi:沒有無法診斷的細節。用你的'app.run()'行運行代碼並調整'curl'命令可以正常工作。也許你應該發佈一個新的 –

16

這裏有幾件事情,我會嘗試一次性解決它們。

首先,您可能正在使用玩具開發服務器。這臺服務器有很多限制,主要是這些限制之一是它一次只能處理一個請求。當您在第一次請求期間創建第二個請求時,您正在鎖定您的應用程序:requests.post()函數正在等待Flask響應,但Flask本身正在等待post()返回!解決此特定問題的方法是在多線程或多進程環境中運行WSGI應用程序。我更喜歡http://twistedmatrix.com/trac/wiki/TwistedWeb,但還有其他幾個選項。

那就這樣...這是一個反模式。您幾乎肯定不想調用HTTP請求的所有開銷,只是爲了在兩個視圖之間共享某些功能。正確的做法是重構一個獨立的函數來完成共享工作。我無法真正重構你的特定例子,因爲你擁有的很簡單,甚至不值得兩個觀點。你想要製造什麼?

編輯:評論詢問玩具stdlib服務器中的多線程模式是否足以防止發生死鎖。我會說「也許」。是的,如果沒有任何依賴性使兩個線程都不能繼續進行,並且兩個線程都有足夠的進度來完成他們的網絡任務,那麼請求將會正確完成。但是,確定兩個線程是否會相互死鎖是不可判定的(證明省略爲鈍),我不肯定地說stdlib服務器可以做到這一點。

+0

+1在請求處理程序中提出請求在大多數情況下是不好的,對自己發出http請求... ick –

+0

我遇到了問題,因爲我合併了兩個Web服務這是以前作爲獨立流程運行的唯一交互這兩種Web服務之間的關係就是POST。我使用藍圖和繁榮將它們結合到了同一個過程中,它凍結了。所以,更多的重構是爲了。 – jfocht

+0

@Corbin那麼threaded = True選項與TwistedWeb不足以滿足多處理和每個請求的多線程執行? – loretoparisi

3

導致崩潰的錯誤是fixed in Version 0.12,2016年12月21日發佈。是的!這是許多人一直在等待的重要解決方案。

從燒瓶中的changelog:

  • 將其還原爲行爲改變是做而不是返回內部服務器錯誤(pull請求#2006)開發服務器崩潰。
+0

是的!謝謝你的提示。升級到燒瓶0.12修復了這個問題。現在只需記錄這些錯誤而不會導致我的服務器崩潰。 –