Skip to content

AsyncToSync error with Flask Async, Gunicorn and Gevent #5256

@SamStephens

Description

@SamStephens

When using the Async options for Flask, running an application with an asynchronous teardown_request function, using Gunicorn with Gevent as the WSGI server, there is a race condition where a lot of simultaneous requests results in the error "You cannot use AsyncToSync in the same thread as an async event loop - just await the async function directly.".

I've attached a reproduction. To reproduce the bug:

  • Unzip the zip to a directory.
  • Install the requirements using pip install -r requirements.txt.
  • Run the application using gunicorn -b 0.0.0.0:8080 app:app --worker-class=gevent -w 2 --threads 2.
  • In another shell, run ./lots-of-curls.sh.

The stack trace I see is

Traceback (most recent call last):
  File "/home/sam/.pyenv/versions/3.9.7/envs/flask-test-3.9.7/lib/python3.9/site-packages/gunicorn/workers/base_async.py", line 55, in handle
    self.handle_request(listener_name, req, client, addr)
  File "/home/sam/.pyenv/versions/3.9.7/envs/flask-test-3.9.7/lib/python3.9/site-packages/gunicorn/workers/ggevent.py", line 128, in handle_request
    super().handle_request(listener_name, req, sock, addr)
  File "/home/sam/.pyenv/versions/3.9.7/envs/flask-test-3.9.7/lib/python3.9/site-packages/gunicorn/workers/base_async.py", line 108, in handle_request
    respiter = self.wsgi(environ, resp.start_response)
  File "/home/sam/.pyenv/versions/3.9.7/envs/flask-test-3.9.7/lib/python3.9/site-packages/flask/app.py", line 2213, in __call__
    return self.wsgi_app(environ, start_response)
  File "/home/sam/.pyenv/versions/3.9.7/envs/flask-test-3.9.7/lib/python3.9/site-packages/flask/app.py", line 2206, in wsgi_app
    ctx.pop(error)
  File "/home/sam/.pyenv/versions/3.9.7/envs/flask-test-3.9.7/lib/python3.9/site-packages/flask/ctx.py", line 401, in pop
    self.app.do_teardown_request(exc)
  File "/home/sam/.pyenv/versions/3.9.7/envs/flask-test-3.9.7/lib/python3.9/site-packages/flask/app.py", line 2038, in do_teardown_request
    self.ensure_sync(func)(exc)
  File "/home/sam/.pyenv/versions/3.9.7/envs/flask-test-3.9.7/lib/python3.9/site-packages/asgiref/sync.py", line 209, in __call__
    raise RuntimeError(
RuntimeError: You cannot use AsyncToSync in the same thread as an async event loop - just await the async function directly.

If you run without gevent, using the command line gunicorn -b 0.0.0.0:8080 app:app -w 2 --threads 2 the issue does not manifest.

If you remove all the & characters from the end of the lines in lots-of-curls.sh, so the curl statements run serially rather than in parallel, no issue shows up so this appears to definitely be a race condition of some sort.

It is possible this is a bug in another component in the stack, but I just don't have clear enough knowledge of how the responsibilities are assigned to know which component is at fault, apologies if the bug is not in Flask itself.

Environment:

  • Python version: 3.9.7
  • Flask version: 2.3.3

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions