2015-02-24 143 views
3

我已經使用Flask框架實現了簡單的API,現在我正試圖將它部署到gunicorn服務器。使用Flask和gunicorn加載服務器的全局數據

我的服務器腳本如下所示:

app = Flask(__name__) 

class Server(object): 
    def __init__(self, data): 
     self.data = data 

@app.route("/api_method", methods=['GET', 'POST']) 
def api_method(): 
    return server.data 

if __name__ == '__main__': 
    with smart_open(sys.argv[1]) as f: 
     server = Server(f.read()) 
    app.run() 

當我運行這個從控制檯的「瓶的應用程序」比一切都很好,但是當我嘗試下gunicorn運行這個話,根本看不到服務器。我只能通過移動服務器創建來修復它,但我必須對路徑進行硬編碼。

有沒有什麼辦法如何在啓動gunicorn服務器時加載類似我的Server類的東西,然後在API方法中讀取它?

回答

3

這裏是我的建議如何做到這一點。

1.如果需要通過這種方式實例化,我不會依賴全局變量server。由於它是在創建應用程序後實例化的,所以最好將它明確地傳遞給應用程序。這樣,您就可以從其他模塊(blueprintspluggable views等),例如訪問它,您可以用瓶的配置機制:

app.config['server'] = Server(f.read()) 

#...then in your view functions... 

return app.config['server'].data 

或者通過燒瓶的globals objectg

@app.before_request 
def add_server_to_globals(): 
    with open(sys.argv[1]) as f: 
     g.server = Server(f.read()) 

#...then in your view functions... 
return g.server.data 

或者通過繼承Flask並將它傳入初始化器。現在

2.您使用gunicorn,你可以不依賴於if __name__ == '__main__'塊,當你運行該文件,而不是在它的進口,這是唯一的執行。 Gunicorn通過導入應用程序對象(參見how APP_MODULE is explained in the docs)並將其交給gunicorn的WSGI服務器工作,因此用於實例化Server的代碼將不會運行。

獨角獸的另一個新要求是你不能依靠sys.argv,因爲這將是gunicorn的sys.argv,這與當前直接運行文件時傳遞的任何參數不同。

要替換if __name__ == '__main__'塊,您可以像上面那樣使用before_request在應用程序處理其第一個請求之前運行一些代碼。我建議使用環境變量或config file將您的參數傳遞給Server類。例如:

@app.before_request 
def add_server_to_globals(): 
    with open(os.environ['SERVER_FILE']) as f: 
     g.server = Server(f.read()) 

然後運行與環境變量設置你的應用程序:

$ SERVER_FILE=blah.txt gunicorn app:app 
[2015-02-24 10:10:20 -0800] [3217] [INFO] Starting gunicorn 19.2.1 
... 

您還可以看看在燒瓶中的文檔中描述的"application factory"模式更換if __name__ == '__main__'塊。但在這種情況下,這並不是必須的。如果您想僅對Server對象進行實例化(出於性能方面的原因),則應用程序工廠的用途將是。

Here's some fully working code based on your example

Here's another example using an application factory

+0

其實全局對象g的版本只對一個請求有效。我意識到,然後加載的對象消失,這不是我真正想要的。所以app.config ['server'] = ...是正確的解決方案。 – ziky90 2015-02-25 08:45:56

+0

啊,沒錯。對於那個很抱歉。我誤解了'before_first_request'和'before_request'。我使用正確的信息更新了我的文章,並添加了關於如何在應用程序工廠中使用before_request的示例。 – 2015-02-25 17:58:32

+0

謝謝,在我的情況下,文件可以很安靜,可以在S3上遠程執行(我之所以使用'smart_open'庫而不是標準'open')。因此,在每個請求之前仍然加載文件是安靜的問題,但'app.config ['server'] = Server(f.read())'適合我。 – ziky90 2015-02-25 22:26:01

1

簡單:)

with smart_open(sys.argv[2]) as f: 
    server = Server(f.read()) 
if __name__ == '__main__': 
    app.run() 

邏輯已經在他的回答給您由史蒂芬Kryskalla。

但要確保你保持app.run()if __name__=="__main__"因爲你不希望這樣的gunicorn進口服務器

編輯時運行的更多信息: 必須有實際sys.argv中[2]相反,因爲在sys.argv [1]是服務器應用程序的路徑。

+1

我其實已經試過這個,你基本上是對的,但有一個特點。 它實際上更改爲sys.argv [2],因爲運行服務器的第二個參數是服務器腳本的路徑。 因此,如果我想要在本地Flask服務器和gunicorn服務器上運行相同的代碼,可能會出現問題。 – ziky90 2015-02-24 20:54:02

+0

是的,你是對的。我只是試圖傳達簡單的修復,而不重新檢查應該使用的命令。 :) – itzMEonTV 2015-02-25 05:40:27

相關問題