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

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

contextvars.Context not activated for connection_made() #305

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

Comments

@versusvoid
Copy link

@versusvoid 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
Author

@versusvoid versusvoid commented Dec 18, 2019

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

versusvoid added a commit to versusvoid/uvloop that referenced this issue Dec 18, 2019
@1st1
Copy link
Member

@1st1 1st1 commented Jan 14, 2020

Yes, this is a bug.

@1st1 1st1 added the bug label Jan 14, 2020
@1st1 1st1 added this to To do in v0.15 Mar 17, 2020
@1st1
Copy link
Member

@1st1 1st1 commented Mar 17, 2020

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

@fantix fantix moved this from To do to In progress in v0.15 Mar 21, 2020
versusvoid added a commit to versusvoid/uvloop that referenced this issue Mar 30, 2020
versusvoid added a commit to versusvoid/uvloop that referenced this issue Mar 31, 2020
fantix added a commit to fantix/uvloop that referenced this issue May 25, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
v0.15
  
In progress
Linked pull requests

Successfully merging a pull request may close this issue.

None yet
2 participants
You can’t perform that action at this time.