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

Pyramid 2.0 asyncio support #3391

Closed
4 tasks
ergo opened this issue Oct 16, 2018 · 6 comments
Closed
4 tasks

Pyramid 2.0 asyncio support #3391

ergo opened this issue Oct 16, 2018 · 6 comments

Comments

@ergo
Copy link
Member

ergo commented Oct 16, 2018

It would be great to implement easy asyncio support for pyramid 2.0.
This issue should serve as a plan to implement that.
I would suggest we use python 3.6/3.7 as a base requirement for the module.
By default pyramid should work in a standard "sync" mode same as django or flask and provide decorators/factories for optional asynchronous views and machinery.

  • Support async context factories
  • Support async auth policies
  • Support async views
  • Support async tweens

Pyramid would "reserve" a single thread for asyncio execution and all async parts of application code would be marked accordingly by async/await or decorator.

Links for inspiration:

https://github.com/housleyjk/aiopyramid/tree/master/aiopyramid
https://github.com/mardiros/pyramid_asyncio
https://aiohttp-wsgi.readthedocs.io/en/stable/installation.html

@mmerickel
Copy link
Member

mmerickel commented Oct 16, 2018

This issue is a duplicate of #2603 and I don't want to have two issues on async support open right now. I'm going to close at least one of them.

I don't think pyramid 2.0 is relevant here until someone demonstrates a working reference implementation / pull request and we can see what backward incompatible changes would be made to pyramid to support any asyncio features.

I strongly disagree with the idea that pyramid would work in some sort of "dual" mode and care at all about any thread pools, etc. This stuff is entirely up to the runtime itself that is invoking pyramid's router and the question is how much of pyramid's pipeline needs to be tweaked to support an async call stack. WSGI itself does not support async code, and that is the only entry point into pyramid's router right now. This will need to change.

There are basically two options:

  1. invoke a pyramid router synchronously and then allow some code to do something asynchronously (async-in-sync)

  2. invoke a pyramid router asynchronously and then allow some code to do something synchronously (sync-in-async)

The first option (async-in-sync) is doable right now because you can just start an event loop in your view and add async work to it. Alternatively you can define a shared event loop running in another thread. No one is really interested in these options.

The second option is that pyramid adopts an ASGI protocol (see the Application class at https://asgi.readthedocs.io/en/latest/introduction.html#how-does-asgi-work). The runtime then provides a standard way within pyramid to dispatch some work onto a threadpool which executes synchronously, while the view code waits on a future until that work is done, yielding control back to the event loop to handle other requests. This is the only really interesting option, and is also how I have seen other potential integrations do things. See, for example, asgiref.sync.sync_to_async which is a decorator that turns synchronous code into work on a threadpool, returning an awaitable future.

The question is basically, how do we go about modifying pyramid internals to handle an ASGI call stack all the way down to a view callable. This basically means that pyramid needs to expect a lot of hooks to return futures and it needs to be able to deal with them.

@mmerickel
Copy link
Member

I should also point out that pyramid has no chance of modifying its router to support an ASGI call stack until webob itself supports async IO. This means that anywhere that webob touches IO (primarily the wsgi.inputsocket) needs to be thought about carefully unless you want users to have to do await request.POST and await request.params everywhere.

@ergo
Copy link
Member Author

ergo commented Oct 17, 2018

I think I used some confusing terminology here, ASGI like approach is what I meant when I mentioned separate parts of application:

there’s a defined way of translating between the two, allowing WSGI applications to be run inside ASGI servers through a translation wrapper (provided in the asgiref library). A threadpool can be used to run the synchronous WSGI applications away from the async event loop.

I'm not sure why the async-in-sync option you mentioned earlier is not interesting? Because of one-directionality of WSGI protocol?

Also as for webob support, await would be required only in the async part of the application, right?

@mmerickel
Copy link
Member

I'm not sure why the async-in-sync option you mentioned earlier is not interesting?

It's not interesting because it can already be done, easily, with no changes to Pyramid, right now using a wsgi container in any asyncio http server and using async_to_sync decorators on any async code called from within Pyramid. It's also not interesting because there is just very few reasons to want to do this and the reasons you would want to are fairly clear. If you need it, you can just do it, right now, without talking to us about it.

Also as for webob support, await would be required only in the async part of the application, right?

await would almost certainly be required on any apis that trigger IO and require a slightly different request object with a slightly different api. Note also that zope.interface's registry would also need to grow some async support. Basically any libraries we use that call back into our code or user code would need to support an async call stack. This is why asyncio is such a massive and infectious beast that changes the entire call stack.

@ergo
Copy link
Member Author

ergo commented Oct 17, 2018

After discussion on IRC and some clarifications seems that example here https://docs.pylonsproject.org/projects/pyramid-cookbook/en/latest/deployment/asgi.html seems to be the best route to go.

@ergo ergo closed this as completed Oct 17, 2018
@mmerickel
Copy link
Member

Thanks @ergo! This discussion helped me think a bit further about what Pyramid would need to do in order to support a fully async call stack and it seems pretty daunting, requiring at least changes to webob and the z.i component registry (for async events) before we can think about changing Pyramid itself.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants