forked from orbit-oss/flask
Added support for background loading of the application to speed up initial requests in dev mode.
This commit is contained in:
parent
670d2a4d50
commit
9eb59b0bef
1 changed files with 25 additions and 4 deletions
29
flask/cli.py
29
flask/cli.py
|
|
@ -11,7 +11,7 @@
|
||||||
|
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
from threading import Lock
|
from threading import Lock, Thread
|
||||||
from functools import update_wrapper
|
from functools import update_wrapper
|
||||||
|
|
||||||
import click
|
import click
|
||||||
|
|
@ -99,25 +99,46 @@ def locate_app(app_id):
|
||||||
|
|
||||||
class DispatchingApp(object):
|
class DispatchingApp(object):
|
||||||
"""Special application that dispatches to a flask application which
|
"""Special application that dispatches to a flask application which
|
||||||
is imported by name on first request. This is safer than importing
|
is imported by name in a background thread. If an error happens
|
||||||
the application upfront because it means that we can forward all
|
it is is recorded and shows as part of the WSGI handling which in case
|
||||||
errors for import problems into the browser as error.
|
of the Werkzeug debugger means that it shows up in the browser.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, loader, use_eager_loading=False):
|
def __init__(self, loader, use_eager_loading=False):
|
||||||
self.loader = loader
|
self.loader = loader
|
||||||
self._app = None
|
self._app = None
|
||||||
self._lock = Lock()
|
self._lock = Lock()
|
||||||
|
self._bg_loading_exc_info = None
|
||||||
if use_eager_loading:
|
if use_eager_loading:
|
||||||
self._load_unlocked()
|
self._load_unlocked()
|
||||||
|
else:
|
||||||
|
self._load_in_background()
|
||||||
|
|
||||||
|
def _load_in_background(self):
|
||||||
|
def _load_app():
|
||||||
|
with self._lock:
|
||||||
|
try:
|
||||||
|
self._load_unlocked()
|
||||||
|
except Exception:
|
||||||
|
self._bg_loading_exc_info = sys.exc_info()
|
||||||
|
t = Thread(target=_load_app, args=())
|
||||||
|
t.start()
|
||||||
|
|
||||||
|
def _flush_bg_loading_exception(self):
|
||||||
|
exc_info = self._bg_loading_exc_info
|
||||||
|
if exc_info is not None:
|
||||||
|
self._bg_loading_exc_info = None
|
||||||
|
raise exc_info[0], exc_info[1], exc_info[2]
|
||||||
|
|
||||||
def _load_unlocked(self):
|
def _load_unlocked(self):
|
||||||
self._app = rv = self.loader()
|
self._app = rv = self.loader()
|
||||||
|
self._bg_loading_exc_info = None
|
||||||
return rv
|
return rv
|
||||||
|
|
||||||
def __call__(self, environ, start_response):
|
def __call__(self, environ, start_response):
|
||||||
if self._app is not None:
|
if self._app is not None:
|
||||||
return self._app(environ, start_response)
|
return self._app(environ, start_response)
|
||||||
|
self._flush_bg_loading_exception()
|
||||||
with self._lock:
|
with self._lock:
|
||||||
if self._app is not None:
|
if self._app is not None:
|
||||||
rv = self._app
|
rv = self._app
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue