The reason this works with FLASK_DEBUG=0 but not FLASK_DEBUG=1 is because the app runs in the main thread while not in debug mode, but doesn't run in the main thread while in debug mode.
The relevant code is in asyncio.events.BaseDefaultEventLoopPolicy.get_event_loop:
def get_event_loop():
if (self._local._loop is None and
not self._local._set_called and
isinstance(threading.current_thread(), threading._MainThread)):
self.set_event_loop(self.new_event_loop())
if self._local._loop is None:
raise RuntimeError('There is no current event loop in thread %r.'
% threading.current_thread().name)
return self._local._loop
An event loop may be created only in the main thread with the current event loop policy: _UnixDefaultEventLoopPolicy in my case. Note that _UnixDefaultEventLoopPolicy subclasses BaseDefaultEventLoopPolicy but does not override BaseDefaultEventLoopPolicy.
Possible solutions:
- Create a new event loop in the current thread
loop = asyncio.new_event_loop()
- Create a custom event loop policy that allows
asyncio.get_event_loop() to create a new event loop in a thread other than the main thread by overriding the events.AbstractEventLoopPolicy.get_event_loop method. The safest way to do this is probably to subclass whichever event loop policy your environment is using and override its get_event_loop method, removing the main thread check. This way you retain all other policy behaviors, though the change may break some of these behaviors.
Either way, you're creating an event loop for the thread. My standard inclination is to go for simplicity, so #1.
So why doesn't the app run in the main thread while in debug mode? First, there are two processes while running in debug mode: the Flask server and the debugger, flask run and python pydevd.py, respectively. The main thread of each process has an event loop that facilitates communication between the app server and the debugger - among other things, and spawns another thread in which the app actually runs. You'll also see this behavior without debug mode enabled if the application is being served by a multi-threaded app server, e.g. gunicorn or uwsgi.
Flask doesn't really support asyncio. Sure one can use it with Flask, but no guarantees are made about their compatibility. See this issue, and more specifically: the issue referenced in its comments