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

contextvars.Context not activated for connection_made() #305

Closed
versusvoid opened this issue Dec 13, 2019 · 3 comments
Closed

contextvars.Context not activated for connection_made() #305

versusvoid opened this issue Dec 13, 2019 · 3 comments
Labels

Comments

@versusvoid
Copy link
Contributor

versusvoid commented Dec 13, 2019

  • uvloop version: 0.14.0, reproducible on master (35f8250)
  • Python version: 3.8
  • Platform: Linux
  • Can you reproduce the bug with PYTHONASYNCIODEBUG in env?: Yes
  • Does uvloop behave differently from vanilla asyncio? How?: Yes:
import asyncio
import contextvars

import aiohttp
import aiohttp.web
import uvloop


var = contextvars.ContextVar('uvloop is awesome', default=None)


async def handle(request):
    assert var.get() is not None
    return aiohttp.web.Response(text='OK!')


async def client():
    await asyncio.sleep(1)

    async with aiohttp.ClientSession() as session:
        async with session.get('http://localhost:12345/') as response:
            text = await response.text()
            assert text == 'OK!'


async def setup(app):
    var.set('It truly is!')


async def create_app():
    app = aiohttp.web.Application()
    app.on_startup.append(setup)
    app.add_routes([aiohttp.web.get('/', handle)])

    asyncio.create_task(client())

    return app

if __name__ == '__main__':
    asyncio.set_event_loop_policy(uvloop.EventLoopPolicy())
    aiohttp.web.run_app(create_app(), port=12345)

Code works as expected on asyncio loop (var has value in handler) but fails with uvloop. I tracked difference up to connection_made():

  File "uvloop/cbhandles.pyx", line 73, in uvloop.loop.Handle._run
  File "uvloop/handles/tcp.pyx", line 153, in uvloop.loop.TCPTransport._call_connection_made
  File "uvloop/handles/basetransport.pyx", line 134, in uvloop.loop.UVBaseTransport._call_connection_made
  File "uvloop/handles/basetransport.pyx", line 131, in uvloop.loop.UVBaseTransport._call_connection_made
  File "aiohttp/web_protocol.py", line 223, in connection_made

There is similar difference in UVStreamHandler._on_listen:

protocol = self.protocol_factory()

protocol_handler() is being called without context activation, while with asyncio it receives context. I'm not sure if this can be the root cause.

@versusvoid
Copy link
Contributor Author

Context not being restored for protocol_factory call is what causing problems. python's asyncio copies current context (by creating callback handle) when creating listen() handler:

https://github.com/python/cpython/blob/fa919fdf2583bdfead1df00e842f24f30b2a34bf/Lib/asyncio/selector_events.py#L252

uvloop simply calls UVStreamHandler._on_listen from libuv

@1st1
Copy link
Member

1st1 commented Jan 14, 2020

Yes, this is a bug.

@1st1 1st1 added the bug label Jan 14, 2020
@1st1
Copy link
Member

1st1 commented Mar 17, 2020

This PR needs to be considered as part of this issue, basically #306

fantix added a commit to fantix/uvloop that referenced this issue May 25, 2020
fantix pushed a commit to fantix/uvloop that referenced this issue Jan 25, 2021
fantix pushed a commit to fantix/uvloop that referenced this issue Feb 5, 2021
fantix pushed a commit to fantix/uvloop that referenced this issue Feb 5, 2021
@fantix fantix closed this as completed in 7b202cc Feb 5, 2021
This was referenced Feb 10, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants