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

Cached aiohttp.web.Response objects cause requests to hang #3020

Closed
lpedrosa opened this issue May 21, 2018 · 7 comments
Closed

Cached aiohttp.web.Response objects cause requests to hang #3020

lpedrosa opened this issue May 21, 2018 · 7 comments
Labels

Comments

@lpedrosa
Copy link
Contributor

Long story short

If you use a cached aiohttp.web.Response in a middleware function it will cause any subsequent requests to hang.

Expected behaviour

After thinking for a bit, I suggest that we either:

  • Improve documentation, by showing an example of what to do if you wish to cache the response body, or
  • Make the response object re-usable between requests. It can still remain unchangeable after prepare() has been called, preserving its semantics. However, this is probably not feasible with the current architecture.

Actual behaviour

As far as I understand, aiohttp.web.Response is a Finite State Machine. Once a Response
object is dispatched by the server, it must be emptying some internal buffer. This renders it unusable for subsequent dispatches.

The current solution for avoiding this behaviour seems to be having the middleware generate a new Response object, everytime it is called.

Steps to reproduce

Here is a simple application that reproduces the behaviour:

from aiohttp import web


def my_middleware_factory():

    # this could have been passed in as a default arg, or exist as a global
    state = web.Response(status=200, text='this is cached')

    @web.middleware
    async def middleware(request, handler):
        res = await handler(request)
        return state

    return middleware


async def handler(request):
    return web.Response(status=200, text='Hello World!')


def main():
    app = web.Application()
    app.router.add_get('/', handler)
    app.middlewares.append(my_middleware_factory())

    web.run_app(app)


if __name__ == '__main__':
    main()
  • When you hit http://localhost:8080 twice
  • Then the second request should hang your http client

Your environment

Python 3.6
aiohttp=3.2.1
Ubuntu 16.04
'server'

@lpedrosa
Copy link
Contributor Author

I'm glad to help augmenting the current middleware factory usage examples for this. Your framework is really helpful!

I have run into this behaviour while building a generic Exception to Response middleware factory. My current workaround can be found here

The to_response() function generates a new web.Response everytime it is called.

@asvetlov
Copy link
Member

Yes, web response cannot be used multiple times to answer different requests.
You should recreate it every time, the response object cannot be cached.
The rule of thumb: one request -- one response.

If you want to make a documentation pull request -- you are welcome. I doubt if we need to blow up the main docs but FAQ sounds like a good place for such things.

@lpedrosa
Copy link
Contributor Author

The FAQ sounds like a great place to put it. Let me try to figure out how to do it.

The rule of thumb: one request -- one response.

Thanks for clarifying this!

@asvetlov
Copy link
Member

@lpedrosa ping

@lpedrosa
Copy link
Contributor Author

lpedrosa commented Jul 9, 2018

Hi @asvetlov. Sorry about going MIA. I'll create a PR in a couple of minutes, containing the basic draft of the new FAQ entry.

@asvetlov
Copy link
Member

Fixed by #3129

shikhir-arora referenced this issue in gieseladev/discord.py Aug 28, 2018
==================

Features
--------

- Add type hints (`3049 <https://github.com/aio-libs/aiohttp/pull/3049>`_)
- Add ``raise_for_status`` request parameter (`3073 <https://github.com/aio-libs/aiohttp/pull/3073>`_)
- Add type hints to HTTP client (`3092 <https://github.com/aio-libs/aiohttp/pull/3092>`_)
- Minor server optimizations (`3095 <https://github.com/aio-libs/aiohttp/pull/3095>`_)
- Preserve the cause when `HTTPException` is raised from another exception. (`3096 <https://github.com/aio-libs/aiohttp/pull/3096>`_)
- Add `close_boundary` option in `MultipartWriter.write` method. Support streaming (`3104 <https://github.com/aio-libs/aiohttp/pull/3104>`_)
- Added a ``remove_slash`` option to the ``normalize_path_middleware`` factory. (`3173 <https://github.com/aio-libs/aiohttp/pull/3173>`_)
- The class `AbstractRouteDef` is importable from `aiohttp.web`. (`3183 <https://github.com/aio-libs/aiohttp/pull/3183>`_)


Bugfixes
--------

- Prevent double closing when client connection is released before the
last ``data_received()`` callback. (`3031 <https://github.com/aio-libs/aiohttp/pull/3031>`_)
- Make redirect with `normalize_path_middleware` work when using url encoded paths. (`3051 <https://github.com/aio-libs/aiohttp/pull/3051>`_)
- Postpone web task creation to connection establishment. (`3052 <https://github.com/aio-libs/aiohttp/pull/3052>`_)
- Fix ``sock_read`` timeout. (`3053 <https://github.com/aio-libs/aiohttp/pull/3053>`_)
- When using a server-request body as the `data=` argument of a client request, iterate over the content with `readany` instead of `readline` to avoid `Line too long` errors. (`3054 <https://github.com/aio-libs/aiohttp/pull/3054>`_)
- fix `UrlDispatcher` has no attribute `add_options`, add `web.options` (`3062 <https://github.com/aio-libs/aiohttp/pull/3062>`_)
- correct filename in content-disposition with multipart body (`3064 <https://github.com/aio-libs/aiohttp/pull/3064>`_)
- Many HTTP proxies has buggy keepalive support.
Let's not reuse connection but close it after processing every response. (`3070 <https://github.com/aio-libs/aiohttp/pull/3070>`_)
- raise 413 "Payload Too Large" rather than raising ValueError in request.post()
Add helpful debug message to 413 responses (`3087 <https://github.com/aio-libs/aiohttp/pull/3087>`_)
- Fix `StreamResponse` equality, now that they are `MutableMapping` objects. (`3100 <https://github.com/aio-libs/aiohttp/pull/3100>`_)
- Fix server request objects comparison (`3116 <https://github.com/aio-libs/aiohttp/pull/3116>`_)
- Do not hang on `206 Partial Content` response with `Content-Encoding: gzip` (`3123 <https://github.com/aio-libs/aiohttp/pull/3123>`_)
- Fix timeout precondition checkers (`3145 <https://github.com/aio-libs/aiohttp/pull/3145>`_)


Improved Documentation
----------------------

- Add a new FAQ entry that clarifies that you should not reuse response
objects in middleware functions. (`3020 <https://github.com/aio-libs/aiohttp/pull/3020>`_)
- Add FAQ section "Why is creating a ClientSession outside of an event loop dangerous?" (`3072 <https://github.com/aio-libs/aiohttp/pull/3072>`_)
- Fix link to Rambler (`3115 <https://github.com/aio-libs/aiohttp/pull/3115>`_)
- Fix TCPSite documentation on the Server Reference page. (`3146 <https://github.com/aio-libs/aiohttp/pull/3146>`_)
- Fix documentation build configuration file for Windows. (`3147 <https://github.com/aio-libs/aiohttp/pull/3147>`_)
- Remove no longer existing lingering_timeout parameter of Application.make_handler from documentation. (`3151 <https://github.com/aio-libs/aiohttp/pull/3151>`_)
- Mention that ``app.make_handler`` is deprecated, recommend to use runners
API instead. (`3157 <https://github.com/aio-libs/aiohttp/pull/3157>`_)


Deprecations and Removals
-------------------------

- Drop ``loop.current_task()`` from ``helpers.current_task()`` (`2826 <https://github.com/aio-libs/aiohttp/pull/2826>`_)
- Drop ``reader`` parameter from ``request.multipart()``. (`3090 <https://github.com/aio-libs/aiohttp/pull/3090>`_)
kornicameister referenced this issue in kornicameister/korni-stats-collector Sep 17, 2018
This PR updates [aiohttp](https://pypi.org/project/aiohttp) from **3.3.2** to **3.4.4**.



<details>
  <summary>Changelog</summary>
  
  
   ### 3.4.4
   ```
   ==================

- Fix installation from sources when compiling toolkit is not available (`3241 &lt;https://github.com/aio-libs/aiohttp/pull/3241&gt;`_)
   ```
   
  
  
   ### 3.4.3
   ```
   ==================

- Add ``app.pre_frozen`` state to properly handle startup signals in sub-applications. (`3237 &lt;https://github.com/aio-libs/aiohttp/pull/3237&gt;`_)
   ```
   
  
  
   ### 3.4.2
   ```
   ==================

- Fix ``iter_chunks`` type annotation (`3230 &lt;https://github.com/aio-libs/aiohttp/pull/3230&gt;`_)
   ```
   
  
  
   ### 3.4.1
   ```
   ==================

- Fix empty header parsing regression. (`3218 &lt;https://github.com/aio-libs/aiohttp/pull/3218&gt;`_)
- Fix BaseRequest.raw_headers doc. (`3215 &lt;https://github.com/aio-libs/aiohttp/pull/3215&gt;`_)
- Fix documentation building on ReadTheDocs (`3221 &lt;https://github.com/aio-libs/aiohttp/pull/3221&gt;`_)
   ```
   
  
  
   ### 3.4.0
   ```
   ==================

Features
--------

- Add type hints (`3049 &lt;https://github.com/aio-libs/aiohttp/pull/3049&gt;`_)
- Add ``raise_for_status`` request parameter (`3073 &lt;https://github.com/aio-libs/aiohttp/pull/3073&gt;`_)
- Add type hints to HTTP client (`3092 &lt;https://github.com/aio-libs/aiohttp/pull/3092&gt;`_)
- Minor server optimizations (`3095 &lt;https://github.com/aio-libs/aiohttp/pull/3095&gt;`_)
- Preserve the cause when `HTTPException` is raised from another exception. (`3096 &lt;https://github.com/aio-libs/aiohttp/pull/3096&gt;`_)
- Add `close_boundary` option in `MultipartWriter.write` method. Support streaming (`3104 &lt;https://github.com/aio-libs/aiohttp/pull/3104&gt;`_)
- Added a ``remove_slash`` option to the ``normalize_path_middleware`` factory. (`3173 &lt;https://github.com/aio-libs/aiohttp/pull/3173&gt;`_)
- The class `AbstractRouteDef` is importable from `aiohttp.web`. (`3183 &lt;https://github.com/aio-libs/aiohttp/pull/3183&gt;`_)


Bugfixes
--------

- Prevent double closing when client connection is released before the
  last ``data_received()`` callback. (`3031 &lt;https://github.com/aio-libs/aiohttp/pull/3031&gt;`_)
- Make redirect with `normalize_path_middleware` work when using url encoded paths. (`3051 &lt;https://github.com/aio-libs/aiohttp/pull/3051&gt;`_)
- Postpone web task creation to connection establishment. (`3052 &lt;https://github.com/aio-libs/aiohttp/pull/3052&gt;`_)
- Fix ``sock_read`` timeout. (`3053 &lt;https://github.com/aio-libs/aiohttp/pull/3053&gt;`_)
- When using a server-request body as the `data=` argument of a client request, iterate over the content with `readany` instead of `readline` to avoid `Line too long` errors. (`3054 &lt;https://github.com/aio-libs/aiohttp/pull/3054&gt;`_)
- fix `UrlDispatcher` has no attribute `add_options`, add `web.options` (`3062 &lt;https://github.com/aio-libs/aiohttp/pull/3062&gt;`_)
- correct filename in content-disposition with multipart body (`3064 &lt;https://github.com/aio-libs/aiohttp/pull/3064&gt;`_)
- Many HTTP proxies has buggy keepalive support.
  Let&#39;s not reuse connection but close it after processing every response. (`3070 &lt;https://github.com/aio-libs/aiohttp/pull/3070&gt;`_)
- raise 413 &quot;Payload Too Large&quot; rather than raising ValueError in request.post()
  Add helpful debug message to 413 responses (`3087 &lt;https://github.com/aio-libs/aiohttp/pull/3087&gt;`_)
- Fix `StreamResponse` equality, now that they are `MutableMapping` objects. (`3100 &lt;https://github.com/aio-libs/aiohttp/pull/3100&gt;`_)
- Fix server request objects comparison (`3116 &lt;https://github.com/aio-libs/aiohttp/pull/3116&gt;`_)
- Do not hang on `206 Partial Content` response with `Content-Encoding: gzip` (`3123 &lt;https://github.com/aio-libs/aiohttp/pull/3123&gt;`_)
- Fix timeout precondition checkers (`3145 &lt;https://github.com/aio-libs/aiohttp/pull/3145&gt;`_)


Improved Documentation
----------------------

- Add a new FAQ entry that clarifies that you should not reuse response
  objects in middleware functions. (`3020 &lt;https://github.com/aio-libs/aiohttp/pull/3020&gt;`_)
- Add FAQ section &quot;Why is creating a ClientSession outside of an event loop dangerous?&quot; (`3072 &lt;https://github.com/aio-libs/aiohttp/pull/3072&gt;`_)
- Fix link to Rambler (`3115 &lt;https://github.com/aio-libs/aiohttp/pull/3115&gt;`_)
- Fix TCPSite documentation on the Server Reference page. (`3146 &lt;https://github.com/aio-libs/aiohttp/pull/3146&gt;`_)
- Fix documentation build configuration file for Windows. (`3147 &lt;https://github.com/aio-libs/aiohttp/pull/3147&gt;`_)
- Remove no longer existing lingering_timeout parameter of Application.make_handler from documentation. (`3151 &lt;https://github.com/aio-libs/aiohttp/pull/3151&gt;`_)
- Mention that ``app.make_handler`` is deprecated, recommend to use runners
  API instead. (`3157 &lt;https://github.com/aio-libs/aiohttp/pull/3157&gt;`_)


Deprecations and Removals
-------------------------

- Drop ``loop.current_task()`` from ``helpers.current_task()`` (`2826 &lt;https://github.com/aio-libs/aiohttp/pull/2826&gt;`_)
- Drop ``reader`` parameter from ``request.multipart()``. (`3090 &lt;https://github.com/aio-libs/aiohttp/pull/3090&gt;`_)
   ```
   
  
</details>


 

<details>
  <summary>Links</summary>
  
  - PyPI: https://pypi.org/project/aiohttp
  - Changelog: https://pyup.io/changelogs/aiohttp/
  - Repo: https://github.com/aio-libs/aiohttp
</details>
@lock
Copy link

lock bot commented Oct 28, 2019

This thread has been automatically locked since there has not been any recent activity after it was closed. Please open a [new issue] for related bugs.
If you feel like there's important points made in this discussion, please include those exceprts into that [new issue].
[new issue]: https://github.com/aio-libs/aiohttp/issues/new

@lock lock bot added the outdated label Oct 28, 2019
@lock lock bot locked as resolved and limited conversation to collaborators Oct 28, 2019
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Projects
None yet
Development

No branches or pull requests

2 participants