Flask dev sunucusunu çalıştırmak neden kendisini iki kez çalıştırıyor?


111

Bir web sitesi geliştirmek için Flask kullanıyorum ve geliştirme sırasında aşağıdaki dosyayı kullanarak flask çalıştırıyorum:

#!/usr/bin/env python
from datetime import datetime
from app import app
import config

if __name__ == '__main__':
    print '################### Restarting @', datetime.utcnow(), '###################'
    app.run(port=4004, debug=config.DEBUG, host='0.0.0.0')

Sunucuyu başlattığımda veya dosyalar güncellendiği için otomatik olarak yeniden başladığında, yazdırma satırını her zaman iki kez gösterir:

################### Restarting @ 2014-08-26 10:51:49.167062 ###################
################### Restarting @ 2014-08-26 10:51:49.607096 ###################

Gerçekten bir sorun olmasa da (gerisi beklendiği gibi çalışıyor), neden böyle davrandığını merak ediyorum. Herhangi bir fikir?

Yanıtlar:


162

Werkzeug yeniden yükleyici, kodunuz her değiştiğinde bu işlemi yeniden başlatabilmesi için bir alt işlem oluşturur. Werkzeug, aradığınızda Flask'a geliştirme sunucusunu sağlayan kütüphanedir app.run().

restart_with_reloader()İşlev koduna bakın ; senin komut çalıştırılır tekrar birlikte subprocess.call().

Eğer ayarlarsanız use_reloaderiçin Falsegörürsünüz davranış go away, ama sonra da yeniden işlevsellik kaybetmek:

app.run(port=4004, debug=config.DEBUG, host='0.0.0.0', use_reloader=False)

flask runKomutu kullanırken de yeniden yükleyiciyi devre dışı bırakabilirsiniz :

FLASK_DEBUG=1 flask run --no-reload

WERKZEUG_RUN_MAINÇocuk işleminin ne zaman yeniden yüklendiğini tespit etmek istiyorsanız , ortam değişkenini arayabilirsiniz :

import os
if os.environ.get('WERKZEUG_RUN_MAIN') == 'true':
    print '################### Restarting @ {} ###################'.format(
        datetime.utcnow())

Bununla birlikte, modül globallerini ayarlamanız gerekiyorsa, bunun yerine @app.before_first_requestdekoratörü bir işlev üzerinde kullanmalı ve bu işlevin bu tür küreselleri ayarlamasını sağlamalısınız . Her yeniden yüklemeden sonra, ilk istek geldiğinde yalnızca bir kez çağrılacaktır:

@app.before_first_request
def before_first_request():
    print '########### Restarted, first request @ {} ############'.format(
        datetime.utcnow())

Bu kullanımlar çatallama veya sap isteklerine yeni subprocesses o tam ölçekli WSGI sunucusunda çalıştırırsanız, o hesaba almak yapmak before_first_requestişleyicileri olabilir her yeni alt işlemi için çağrılabilir.


2
Ah tamam. Açıklama için teşekkürler! Yani normal bir davranış olarak kabul ediliyor mu? En azından
kodumda bir sorun olmaması iyi

1
@ kramer65: tamamen normal ve beklenen bir davranıştır. :-)
Martijn Pieters

1
Yavaş başlatma kodunu yalnızca bir kez çalıştırmanın, wsgi altında çalışırken de çağrılmasını (yani app.run, dan değil ), ancak ilk isteği beklemeden çalıştırmanın pratik bir yolu var mı ? Bu ilk talebin başlatma maliyeti ile yüklenmesini istemiyorum.
Kylotan

1
@Kylotan: çevreyi incelemelisiniz; Yalnızca geliştirme sırasında çalışırken DEBUG ayarlarsanız, WERKZEUG_RUN_MAINortam değişkenini arayabilir ve kodunuzu yalnızca DEBUGyanlış olduğunda veya WERKZEUG_RUN_MAINörneğin ayarlandığında çalıştırabilirsiniz . Biraz sıkıcı oluyor.
Martijn Pieters

Sadece açıklığa kavuşturmak için, "işlevselliği yeniden yüklemenin" tepkisellik anlamına geldiğini düşündüm (bu dashbenim için kullanmanın tüm amacını ortadan kaldırır ). Benim noobsgibi diğerleri için bu, yalnızca dosyayı düzenleme / kaydetmenin canlı bir güncellemeyi tetiklediği işlevsellik anlamına gelir.
Hendy

13

Modern flask runkomutu kullanıyorsanız , seçeneklerden hiçbiri app.runkullanılmaz. Yeniden yükleyiciyi tamamen devre dışı bırakmak için şunu iletin --no-reload:

FLASK_DEBUG=1 flask run --no-reload

Ayrıca, __name__ == '__main__'uygulama doğrudan çalıştırılmadığı için asla doğru olmayacaktır. Martijn'in cevabındaki aynı fikirleri , __main__blok olmadan kullanın .

if os.environ.get('WERKZEUG_RUN_MAIN') != 'true':
    # do something only once, before the reloader

if os.environ.get('WERKZEUG_RUN_MAIN') == 'true':
    # do something each reload

8

Ben aynı sorunu vardı ve ben ayarlayarak onu çözdüm app.debugiçin False. Bunu olarak ayarlamak True, benim __name__ == "__main__"iki kez aranmasına neden oluyordu .


Benim __main__hala ikisi ile iki kez çalışır app.debug = Falseve app.run_server(debug=False). Bunun sizin için yaptığından emin misiniz, yoksa denemek için yeniden üretilebilir bir kod gönderebilir misiniz?
Hendy

Bunu benim için çözmek için yaptığım tek şey app.debug'ı değiştirmek oldu. Ana birimin, cep şişesi sunucusu başlatıldığında yalnızca iki kez çalıştığını doğrulayabilir misiniz? Çalışmakta olan minimum bir çalışma örneği almayı deneyin ve sorunun olup olmadığına bakın. Ayrıca, bir sorun olabilecek birden fazla python sürümünde başarısız olan minimal bir örnek çalıştırmayı deneyin. O zamandan beri projemi python ve flask yerine Java ve SparkJava'ya taşıdım, bu yüzden sorunu neyin düzelttiğini tam olarak hatırlamıyorum.
Carvell Wakeman

flaskÜzerinden kullanıyorum plotly dashve yakın zamanda aktarılan varsayılan debug bağımsız değişkeni değiştirdiklerini öğrendim flask. Yukarıda yanıldığımı ve belki de yaptığımı app.debug=False(varsayılan argümanlar tarafından geçersiz kılındığımı run_server) ya da sadece geçmeden denediğimi True, yukarıda gösterildiği gibi açıkça ayarlamadığımı tahmin edeceğim . Bu benim için artık doğru çalışıyor (bundan emin olmak debug=False). Teşekkürler!
Hendy

2

Flask 0.11'den, uygulamanızı flask runyerine ile çalıştırmanız önerilir python application.py. İkincisini kullanmak, kodunuzun iki kez çalıştırılmasına neden olabilir.

Burada belirtildiği gibi :

... Flask 0.11'den itibaren balon yöntemi tavsiye edilir. Bunun nedeni, yeniden yükleme mekanizmasının nasıl çalıştığına bağlı olarak bazı tuhaf yan etkilerin olmasıdır (belirli bir kodu iki kez çalıştırmak gibi ...)


0

Flask uygulamasının kendisini iki kez çalıştırmasının olası nedenlerinden biri WEB_CONCURRENCY, Heroku'daki ayar yapılandırmasıdır . Birini ayarlamak için konsolda yazabilirsiniz heroku config:set WEB_CONCURRENCY=1


-1

Ben de aynı sorunu yaşadım. Main'i değiştirerek ve use_reloader = False'ı içine ekleyerek çözdüm. Bu sorun için bir çözüm arayan herhangi bir kuruluş varsa, aşağıdaki kod sizi başlatacaktır, ancak koddaki değişikliklerin işlevselliği otomatik olarak algılanıp uygulamayı yeniden başlatarak çalışmayacaktır. Koddaki her düzenlemeden sonra uygulamayı manuel olarak durdurmanız ve yeniden başlatmanız gerekecektir.

if __name__ == '__main__':
    app.run(debug=True, use_reloader=False)
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.