Skip to content

contextvars.Context not activated for connection_made() #305

Description

@versusvoid
  • 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.

Activity

  1. versusvoid commented on Dec 18, 2019

    @versusvoid
    ContributorAuthor

    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

  2. 1st1 commented on Jan 14, 2020

    @1st1
    Member

    Yes, this is a bug.

  3. 1st1 commented on Mar 17, 2020

    @1st1
    Member

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

  4. added a commit that references this issue on May 25, 2020
    75b988f
  5. added a commit that references this issue on Jan 25, 2021
    7975b7b
  6. added 2 commits that reference this issue on Feb 5, 2021
    389776f
    ed6561d
  7. added a commit that references this issue on Mar 12, 2025
    7b202cc
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions