Flask 개발 서버를 실행하면 자체적으로 두 번 실행되는 이유는 무엇입니까?


107

웹 사이트 개발을 위해 Flask 를 사용 하고 있으며 개발 중에 다음 파일을 사용하여 flask를 실행합니다.

#!/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')

서버를 시작하거나 파일이 업데이트되어 자동으로 다시 시작될 때 항상 인쇄 줄이 두 번 표시됩니다.

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

실제로 문제가되지는 않지만 (나머지는 예상대로 작동 함) 왜 이렇게 작동하는지 궁금합니다. 어떤 아이디어?

답변:


154

Werkzeug 리 로더는 코드가 변경 될 때마다 해당 프로세스를 다시 시작할 수 있도록 자식 프로세스를 생성합니다. Werkzeug는 app.run().

restart_with_reloader()기능 코드를 참조하십시오 . 스크립트가 실행됩니다 다시subprocess.call().

사용자가 설정 한 경우 use_reloaderFalse볼 수 있습니다 당신 동작은 사라,하지만 당신은 또한 다시로드 기능을 잃게 :

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

flask run명령을 사용할 때도 리 로더를 비활성화 할 수 있습니다 .

FLASK_DEBUG=1 flask run --no-reload

WERKZEUG_RUN_MAIN다시로드하는 하위 프로세스에있을 때 감지하려는 경우 환경 변수를 찾을 수 있습니다 .

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

그러나 모듈 전역을 설정해야하는 경우 대신 함수에 @app.before_first_request데코레이터 를 사용하고 해당 함수가 이러한 전역을 설정하도록해야합니다. 첫 번째 요청이 들어올 때마다 새로 고침 할 때마다 한 번만 호출됩니다.

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

요청을 처리하기 위해 분기 또는 새 하위 프로세스를 사용하는 본격적인 WSGI 서버에서이를 실행하는 경우 해당 before_first_request처리기 각각의 새 하위 프로세스에 대해 호출 수 있다는 점을 고려하십시오 .


2
그래. 설명 해주셔서 감사합니다! 그래서 정상적인 행동으로 간주됩니까? 내 코드와 아무것도의 잘못이 적어도 좋은에서 ... :)
kramer65

1
@ kramer65 : 완전히 정상적이고 예상되는 동작입니다. :-)
Martijn Pieters

1
느린 초기화 코드를 한 번만 실행하는 실용적인 방법이 app.run있습니까? 첫 번째 요청이 초기화 비용으로 부담되는 것을 원하지 않습니다.
Kylotan 2015 년

1
@Kylotan : 환경을 조사해야합니다. 개발 중일 때만 DEBUG를 설정 한 경우 WERKZEUG_RUN_MAIN환경 변수를 찾아서 예를 들어 DEBUGfalse이거나 WERKZEUG_RUN_MAIN설정된 경우에만 코드를 실행할 수 있습니다 . 조금 지루해집니다.
Martijn Pieters

명확히하기 위해 "기능을 다시로드하는 것"은 반응성을 의미한다고 생각 dash했습니다 (나를 위해 사용하는 모든 목적을 무너 뜨릴 것입니다 ). noobs저와 같은 다른 사람에게 이것은 파일 편집 / 저장이 라이브 업데이트를 트리거하는 기능만을 의미합니다.
Hendy

12

최신 flask run명령을 사용하는 경우 app.run사용할 옵션이 없습니다. 리 로더를 완전히 비활성화하려면 --no-reload다음을 전달하십시오 .

FLASK_DEBUG=1 flask run --no-reload

또한 __name__ == '__main__'앱이 직접 실행되지 않기 때문에 절대 사실이 아닙니다. 블록이 없는 경우를 제외하고 Martijn의 답변 에서 동일한 아이디어를 사용하십시오 __main__.

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

저도 같은 문제가 있었는데, 내가 설정하여 그것을 해결 app.debugFalse. 그것을 설정하면 True__name__ == "__main__"전화가 두 번 호출되었습니다.


__main__여전히 두 번 app.debug = Falseapp.run_server(debug=False). 그것이 당신을 위해 그렇게했다고 확신합니까, 아니면 몇 가지 재현 가능한 코드를 게시하여 시도해 볼 수 있습니까?
Hendy

app.debug를 변경하는 것이 나를 위해 해결 한 전부였습니다. 플라스크 서버가 시작될 때 main이 두 번만 실행되는지 확인할 수 있습니까? 최소한의 작업 예제를 실행하고 문제가 발생하는지 확인하십시오. 또한 여러 Python 버전에서 실패하는 최소한의 예제를 실행 해보십시오. 문제가 될 수 있습니다. 그 이후로 내 프로젝트를 python과 flask 대신 Java와 SparkJava로 마이그레이션했기 때문에 정확히 무엇이 문제를 해결했는지 기억이 나지 않습니다.
Carvell Wakeman

flaskvia를 사용 plotly dash하고 있으며 최근에 전달 된 기본 debug 인수를 flask. 나는 내가 위에서 착각했고 아마도 app.debug=False( 아마도 기본 args에 의해 재정의 될 수 있음 run_server) 또는 전달하지 않고 시도 만 시도 True했으며 위에 표시된대로 명시 적으로 설정 하지 않았다고 추측 할 것입니다 . 이것은 지금 나를 위해 올바르게 작동하고 있습니다 (확인 debug=False). 감사!
Hendy

2

플라스크 0.11에서이를 사용하여 응용 프로그램을 실행하는 것이 좋습니다 flask run보다는 python application.py. 후자를 사용하면 코드가 두 번 실행될 수 있습니다.

여기에 언급 된대로 :

... Flask 0.11부터 플라스크 방법을 권장합니다. 그 이유는 다시로드 메커니즘이 작동하는 방식으로 인해 특정 코드를 두 번 실행하는 것과 같은 기괴한 부작용이 있기 때문입니다.


0

Flask 앱이 자체적으로 두 번 실행되는 가능한 이유 중 하나는 WEB_CONCURRENCYHeroku 의 설정 구성 때문입니다 . 하나로 설정하려면 콘솔에서 쓸 수 있습니다. heroku config:set WEB_CONCURRENCY=1


-1

나는 같은 문제가 있었다. 내 메인을 수정하고 use_reloader = False를 삽입하여 해결했습니다. 여기에서이 문제에 대한 해결 방법을 찾고있는 경우 아래 코드에서 시작할 수 있지만 자동으로 감지되는 코드의 변경 기능이 작동하지 않으며 응용 프로그램을 다시 시작해도 작동하지 않습니다. 코드를 편집 할 때마다 애플리케이션을 수동으로 중지하고 다시 시작해야합니다.

if __name__ == '__main__':
    app.run(debug=True, use_reloader=False)
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.