Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Problems with flask restful and async #30

Closed
gcarvellas opened this issue Jul 29, 2023 · 4 comments
Closed

Problems with flask restful and async #30

gcarvellas opened this issue Jul 29, 2023 · 4 comments
Assignees
Labels
bug Something isn't working

Comments

@gcarvellas
Copy link
Contributor

Flask Restful is a python module that allows routes to be formatted in a nice OOP model.

The problem with flask restful is that it does not support async. This is very problematic for performance since our DB and route calls will be blocking.

See if it's possible to add async support. If not, drop flask restful and just use regular blueprints.

@gcarvellas gcarvellas added the bug Something isn't working label Jul 29, 2023
@gcarvellas gcarvellas self-assigned this Jul 29, 2023
@gcarvellas
Copy link
Contributor Author

flask-restful/flask-restful#917 it doesn't seem like async support will be added anytime soon, so flask restful will be removed

@gcarvellas
Copy link
Contributor Author

gcarvellas commented Sep 11, 2023

I ran into an issue where async functions with decorators don't work.

Will go back to this issue at a later point

Error message:

$ curl -X GET -H "Authorization: Bearer $token" -H 'Content-Type: application/json' -d '{"vendorType": "artist"}' localhost:3001/health
<!doctype html>
<html lang=en>
  <head>
    <title>TypeError: The view function did not return a valid response. The return type must be a string, dict, list, tuple with headers or status, Response instance, or WSGI callable, but it was a coroutine.
 // Werkzeug Debugger</title>
    <link rel="stylesheet" href="?__debugger__=yes&amp;cmd=resource&amp;f=style.css">
    <link rel="shortcut icon"
        href="?__debugger__=yes&amp;cmd=resource&amp;f=console.png">
    <script src="?__debugger__=yes&amp;cmd=resource&amp;f=debugger.js"></script>
    <script>
      var CONSOLE_MODE = false,
          EVALEX = true,
          EVALEX_TRUSTED = false,
          SECRET = "eZTgSDMs4VKl0zO8Uz2u";
    </script>
  </head>
  <body style="background-color: #fff">
    <div class="debugger">
<h1>TypeError</h1>
<div class="detail">
  <p class="errormsg">TypeError: The view function did not return a valid response. The return type must be a string, dict, list, tuple with headers or status, Response instance, or WSGI callable, but it was a coroutine.
</p>
</div>
<h2 class="traceback">Traceback <em>(most recent call last)</em></h2>
<div class="traceback">
  <h3></h3>
  <ul><li><div class="frame" id="frame-140447334005920">
  <h4>File <cite class="filename">"/usr/local/lib/python3.10/site-packages/flask/app.py"</cite>,
      line <em class="line">2213</em>,
      in <code class="function">__call__</code></h4>
  <div class="source "><pre class="line before"><span class="ws">    </span>def __call__(self, environ: dict, start_response: t.Callable) -&gt; t.Any:</pre>
<pre class="line before"><span class="ws">        </span>&#34;&#34;&#34;The WSGI server calls the Flask application object as the</pre>
<pre class="line before"><span class="ws">        </span>WSGI application. This calls :meth:`wsgi_app`, which can be</pre>
<pre class="line before"><span class="ws">        </span>wrapped to apply middleware.</pre>
<pre class="line before"><span class="ws">        </span>&#34;&#34;&#34;</pre>
<pre class="line current"><span class="ws">        </span>return self.wsgi_app(environ, start_response)</pre></div>
</div>

<li><div class="frame" id="frame-140447334005696">
  <h4>File <cite class="filename">"/usr/local/lib/python3.10/site-packages/flask/app.py"</cite>,
      line <em class="line">2193</em>,
      in <code class="function">wsgi_app</code></h4>
  <div class="source "><pre class="line before"><span class="ws">            </span>try:</pre>
<pre class="line before"><span class="ws">                </span>ctx.push()</pre>
<pre class="line before"><span class="ws">                </span>response = self.full_dispatch_request()</pre>
<pre class="line before"><span class="ws">            </span>except Exception as e:</pre>
<pre class="line before"><span class="ws">                </span>error = e</pre>
<pre class="line current"><span class="ws">                </span>response = self.handle_exception(e)</pre>
<pre class="line after"><span class="ws">            </span>except:  # noqa: B001</pre>
<pre class="line after"><span class="ws">                </span>error = sys.exc_info()[1]</pre>
<pre class="line after"><span class="ws">                </span>raise</pre>
<pre class="line after"><span class="ws">            </span>return response(environ, start_response)</pre>
<pre class="line after"><span class="ws">        </span>finally:</pre></div>
</div>

<li><div class="frame" id="frame-140447334004912">
  <h4>File <cite class="filename">"/usr/local/lib/python3.10/site-packages/flask_cors/extension.py"</cite>,
      line <em class="line">176</em>,
      in <code class="function">wrapped_function</code></h4>
  <div class="source "><pre class="line before"><span class="ws">        </span># Wrap exception handlers with cross_origin</pre>
<pre class="line before"><span class="ws">        </span># These error handlers will still respect the behavior of the route</pre>
<pre class="line before"><span class="ws">        </span>if options.get(&#39;intercept_exceptions&#39;, True):</pre>
<pre class="line before"><span class="ws">            </span>def _after_request_decorator(f):</pre>
<pre class="line before"><span class="ws">                </span>def wrapped_function(*args, **kwargs):</pre>
<pre class="line current"><span class="ws">                    </span>return cors_after_request(app.make_response(f(*args, **kwargs)))</pre>
<pre class="line after"><span class="ws">                </span>return wrapped_function</pre>
<pre class="line after"><span class="ws"></span> </pre>
<pre class="line after"><span class="ws">            </span>if hasattr(app, &#39;handle_exception&#39;):</pre>
<pre class="line after"><span class="ws">                </span>app.handle_exception = _after_request_decorator(</pre>
<pre class="line after"><span class="ws">                    </span>app.handle_exception)</pre></div>
</div>

<li><div class="frame" id="frame-140447334004800">
  <h4>File <cite class="filename">"/usr/local/lib/python3.10/site-packages/flask/app.py"</cite>,
      line <em class="line">2190</em>,
      in <code class="function">wsgi_app</code></h4>
  <div class="source "><pre class="line before"><span class="ws">        </span>ctx = self.request_context(environ)</pre>
<pre class="line before"><span class="ws">        </span>error: BaseException | None = None</pre>
<pre class="line before"><span class="ws">        </span>try:</pre>
<pre class="line before"><span class="ws">            </span>try:</pre>
<pre class="line before"><span class="ws">                </span>ctx.push()</pre>
<pre class="line current"><span class="ws">                </span>response = self.full_dispatch_request()</pre>
<pre class="line after"><span class="ws">            </span>except Exception as e:</pre>
<pre class="line after"><span class="ws">                </span>error = e</pre>
<pre class="line after"><span class="ws">                </span>response = self.handle_exception(e)</pre>
<pre class="line after"><span class="ws">            </span>except:  # noqa: B001</pre>
<pre class="line after"><span class="ws">                </span>error = sys.exc_info()[1]</pre></div>
</div>

<li><div class="frame" id="frame-140447334005024">
  <h4>File <cite class="filename">"/usr/local/lib/python3.10/site-packages/flask/app.py"</cite>,
      line <em class="line">1487</em>,
      in <code class="function">full_dispatch_request</code></h4>
  <div class="source "><pre class="line before"><span class="ws">            </span>rv = self.preprocess_request()</pre>
<pre class="line before"><span class="ws">            </span>if rv is None:</pre>
<pre class="line before"><span class="ws">                </span>rv = self.dispatch_request()</pre>
<pre class="line before"><span class="ws">        </span>except Exception as e:</pre>
<pre class="line before"><span class="ws">            </span>rv = self.handle_user_exception(e)</pre>
<pre class="line current"><span class="ws">        </span>return self.finalize_request(rv)</pre>
<pre class="line after"><span class="ws"></span> </pre>
<pre class="line after"><span class="ws">    </span>def finalize_request(</pre>
<pre class="line after"><span class="ws">        </span>self,</pre>
<pre class="line after"><span class="ws">        </span>rv: ft.ResponseReturnValue | HTTPException,</pre>
<pre class="line after"><span class="ws">        </span>from_error_handler: bool = False,</pre></div>
</div>

<li><div class="frame" id="frame-140447334004464">
  <h4>File <cite class="filename">"/usr/local/lib/python3.10/site-packages/flask/app.py"</cite>,
      line <em class="line">1506</em>,
      in <code class="function">finalize_request</code></h4>
  <div class="source "><pre class="line before"><span class="ws">        </span>with the `from_error_handler` flag.  If enabled, failures in</pre>
<pre class="line before"><span class="ws">        </span>response processing will be logged and otherwise ignored.</pre>
<pre class="line before"><span class="ws"></span> </pre>
<pre class="line before"><span class="ws">        </span>:internal:</pre>
<pre class="line before"><span class="ws">        </span>&#34;&#34;&#34;</pre>
<pre class="line current"><span class="ws">        </span>response = self.make_response(rv)</pre>
<pre class="line after"><span class="ws">        </span>try:</pre>
<pre class="line after"><span class="ws">            </span>response = self.process_response(response)</pre>
<pre class="line after"><span class="ws">            </span>request_finished.send(</pre>
<pre class="line after"><span class="ws">                </span>self, _async_wrapper=self.ensure_sync, response=response</pre>
<pre class="line after"><span class="ws">            </span>)</pre></div>
</div>

<li><div class="frame" id="frame-140447334004576">
  <h4>File <cite class="filename">"/usr/local/lib/python3.10/site-packages/flask/app.py"</cite>,
      line <em class="line">1837</em>,
      in <code class="function">make_response</code></h4>
  <div class="source "><pre class="line before"><span class="ws">                        </span>&#34; dict, list, tuple with headers or status,&#34;</pre>
<pre class="line before"><span class="ws">                        </span>&#34; Response instance, or WSGI callable, but it&#34;</pre>
<pre class="line before"><span class="ws">                        </span>f&#34; was a {type(rv).__name__}.&#34;</pre>
<pre class="line before"><span class="ws">                    </span>).with_traceback(sys.exc_info()[2]) from None</pre>
<pre class="line before"><span class="ws">            </span>else:</pre>
<pre class="line current"><span class="ws">                </span>raise TypeError(</pre>
<pre class="line after"><span class="ws">                    </span>&#34;The view function did not return a valid&#34;</pre>
<pre class="line after"><span class="ws">                    </span>&#34; response. The return type must be a string,&#34;</pre>
<pre class="line after"><span class="ws">                    </span>&#34; dict, list, tuple with headers or status,&#34;</pre>
<pre class="line after"><span class="ws">                    </span>&#34; Response instance, or WSGI callable, but it was a&#34;</pre>
<pre class="line after"><span class="ws">                    </span>f&#34; {type(rv).__name__}.&#34;</pre></div>
</div>
</ul>
  <blockquote>TypeError: The view function did not return a valid response. The return type must be a string, dict, list, tuple with headers or status, Response instance, or WSGI callable, but it was a coroutine.
</blockquote>
</div>

<div class="plain">
    <p>
      This is the Copy/Paste friendly version of the traceback.
    </p>
    <textarea cols="50" rows="10" name="code" readonly>Traceback (most recent call last):
  File &#34;/usr/local/lib/python3.10/site-packages/flask/app.py&#34;, line 2213, in __call__
    return self.wsgi_app(environ, start_response)
  File &#34;/usr/local/lib/python3.10/site-packages/flask/app.py&#34;, line 2193, in wsgi_app
    response = self.handle_exception(e)
  File &#34;/usr/local/lib/python3.10/site-packages/flask_cors/extension.py&#34;, line 176, in wrapped_function
    return cors_after_request(app.make_response(f(*args, **kwargs)))
  File &#34;/usr/local/lib/python3.10/site-packages/flask/app.py&#34;, line 2190, in wsgi_app
    response = self.full_dispatch_request()
  File &#34;/usr/local/lib/python3.10/site-packages/flask/app.py&#34;, line 1487, in full_dispatch_request
    return self.finalize_request(rv)
  File &#34;/usr/local/lib/python3.10/site-packages/flask/app.py&#34;, line 1506, in finalize_request
    response = self.make_response(rv)
  File &#34;/usr/local/lib/python3.10/site-packages/flask/app.py&#34;, line 1837, in make_response
    raise TypeError(
TypeError: The view function did not return a valid response. The return type must be a string, dict, list, tuple with headers or status, Response instance, or WSGI callable, but it was a coroutine.
</textarea>
</div>
<div class="explanation">
  The debugger caught an exception in your WSGI application.  You can now
  look at the traceback which led to the error.  <span class="nojavascript">
  If you enable JavaScript you can also use additional features such as code
  execution (if the evalex feature is enabled), automatic pasting of the
  exceptions and much more.</span>
</div>
      <div class="footer">
        Brought to you by <strong class="arthur">DON'T PANIC</strong>, your
        friendly Werkzeug powered traceback interpreter.
      </div>
    </div>

    <div class="pin-prompt">
      <div class="inner">
        <h3>Console Locked</h3>
        <p>
          The console is locked and needs to be unlocked by entering the PIN.
          You can find the PIN printed out on the standard output of your
          shell that runs the server.
        <form>
          <p>PIN:
            <input type=text name=pin size=14>
            <input type=submit name=btn value="Confirm Pin">
        </form>
      </div>
    </div>
  </body>
</html>

<!--

Traceback (most recent call last):
  File "/usr/local/lib/python3.10/site-packages/flask/app.py", line 2213, in __call__
    return self.wsgi_app(environ, start_response)
  File "/usr/local/lib/python3.10/site-packages/flask/app.py", line 2193, in wsgi_app
    response = self.handle_exception(e)
  File "/usr/local/lib/python3.10/site-packages/flask_cors/extension.py", line 176, in wrapped_function
    return cors_after_request(app.make_response(f(*args, **kwargs)))
  File "/usr/local/lib/python3.10/site-packages/flask/app.py", line 2190, in wsgi_app
    response = self.full_dispatch_request()
  File "/usr/local/lib/python3.10/site-packages/flask/app.py", line 1487, in full_dispatch_request
    return self.finalize_request(rv)
  File "/usr/local/lib/python3.10/site-packages/flask/app.py", line 1506, in finalize_request
    response = self.make_response(rv)
  File "/usr/local/lib/python3.10/site-packages/flask/app.py", line 1837, in make_response
    raise TypeError(
TypeError: The view function did not return a valid response. The return type must be a string, dict, list, tuple with headers or status, Response instance, or WSGI callable, but it was a coroutine.


-->

@gcarvellas
Copy link
Contributor Author

I tried using flask method views to allow us to use async with our OOP controller model. However, according to this page https://flask.palletsprojects.com/en/2.3.x/async-await/ , flask method views don't support async. Thus, the only way for us to have async is to not have our controllers wrapped in classes and use blueprints.

@gcarvellas
Copy link
Contributor Author

moved to #40

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

When branches are created from issues, their pull requests are automatically linked.

1 participant