django-rest-framework icon indicating copy to clipboard operation
django-rest-framework copied to clipboard

Async Support

Open robd003 opened this issue 2 years ago • 36 comments

Django 4.1 alpha1 was just released and now supports async ClassBasedViews

Could we get DRF APIViews to support async since it's already available in the master branch of Django?

robd003 avatar May 22 '22 18:05 robd003

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

stale[bot] avatar Jul 31 '22 07:07 stale[bot]

This is much needed.

sun337 avatar Aug 05 '22 07:08 sun337

Are there any plans to implement this?

TheWeirdDev avatar Aug 05 '22 09:08 TheWeirdDev

well, honestly I cannot imagine has the whole DRF can be future-proof without adding a fully fledged async support.

PaoloC68 avatar Aug 05 '22 14:08 PaoloC68

@tomchristie any chance this could get put on the roadmap?

robd003 avatar Aug 05 '22 15:08 robd003

Up

firminoneto11 avatar Aug 08 '22 13:08 firminoneto11

DRF async support would much appreciated!

hguitar avatar Aug 10 '22 01:08 hguitar

I have an API that depends on a third party https call and this will really make my life better, when can this be out?

helenap avatar Aug 16 '22 01:08 helenap

@tomchristie I would like to work on this!

em1208 avatar Aug 18 '22 09:08 em1208

Noted. I expect that a third-party package implementing an AsyncAPIView would be a good start here.

Has anyone attempted an implementation of an equivalent to the existing APIView? What blockers are there to being able to implement one? What particular support is needed from the maintenance team here?

tomchristie avatar Aug 18 '22 12:08 tomchristie

I haven't tried before but I would like to start with a test implementation. I will report any blockers. When would you like to review a PR for DRF?

em1208 avatar Aug 19 '22 00:08 em1208

I opened this PR https://github.com/encode/django-rest-framework/pull/8617 with a tentative implementation of the async support.

em1208 avatar Aug 19 '22 09:08 em1208

You rock @em1208

robd003 avatar Aug 20 '22 00:08 robd003

Okay, so @em1208 has a neatly done pull request which adds async view support.

My concerns around this are to do with introducing false expectations to our users. I'd rather explore that through conversation instead of dictating, so here goes...

Could somebody start by giving an example of what you want this support for and why?

tomchristie avatar Aug 22 '22 11:08 tomchristie

As an extension of my PR, I think it would be good to have separate async mixins using the new async API of the queryset and it should be enough for most users.

em1208 avatar Aug 22 '22 12:08 em1208

With async support from DRF users would be able to fully go async for their apis, allowing them to use awsome tools such as httpx, async db drivers in the future and also use the new queryset api that Django's team is working on, without much effort, by just creating a regular async DRF view.

I also think that going full async with new DRF's views could improve even more concurrency on apis, because we would be able to write non blocking code, which is amazing!

firminoneto11 avatar Aug 22 '22 12:08 firminoneto11

Okay, so I'll address a couple of concerns based on those comments...

With async support from DRF users would be able to fully go async for their apis

Okay. Though the pull request as it stands adds "async within a thread" support, rather than "async all-the-way-through support".

I think the dispatch method would need to return an optionally-awaitable instance in order to properly support a fully async calling stack, rather than using sync_to_async.

(At least, that's what I understood based on a look at the dispatch view of Django's View class. Anyone?)

I think it would be good to have seperate async mixins [...]

Agreed. If async support is being added, it'd make sense for it to extend into the mixins. But... I'm not keen on REST framework taking on new functionality.

Anyways, my preference at the moment is the same as with almost every other REST framework proposal. Which is: A third party package would probably be a perfectly okay place for this functionality to be supported in.

tomchristie avatar Aug 22 '22 15:08 tomchristie

I can update the PR to make it ""async all-the-way" if it would make it acceptable, I tried to minimise the impact on the existing codebase. I understand the preference is for a third party package but I still think the new async functionality of Django could be nicely supported by DRF together with the existing functionality.

em1208 avatar Aug 23 '22 13:08 em1208

I can update the PR to make it ""async all-the-way" if it would make it acceptable

It'd certainly be interesting to know what that'd look like. (It's still very likely I'd prefer to see work there in a third party package, but.)

The sync-to-async wrapper makes it really nice and easy, but we're also essentially indulging in false advertising. Async in that case isn't going to improve overall request/response concurrency at all, and really only potentially helps in exceedingly narrow use-cases such as "we need a view that makes two outgoing HTTP requests in parallel".

tomchristie avatar Aug 24 '22 14:08 tomchristie

Thanks @tomchristie for taking this into consideration. I updated the PR https://github.com/encode/django-rest-framework/pull/8617 to have an async dispatch method.

em1208 avatar Aug 24 '22 23:08 em1208

I would disagree with an AsyncAPIView class. The best approach probably involves mimicking what Django Core is doing.

That is, dynamically deciding whether to dispatch as async or sync based on whether all HTTP method functions are async.

For backwards compatibility purposes, we could add an additional check that tosses an exception if trying to use async on django<4.1

Archmonger avatar Aug 25 '22 07:08 Archmonger

@Archmonger thanks for your comment. I removed the AsyncAPIView and done all the changes under APIView .

em1208 avatar Aug 25 '22 08:08 em1208

Could somebody start by giving an example of what you want this support for and why?

So that it doesn't get lost, there is a lot of historical use cases people have provided over at:

  • #7774

johnthagen avatar Oct 13 '22 16:10 johnthagen

So https://github.com/em1208/adrf is looking great. I'm wondering where the best place to link to this from the docs would be? Perhaps an "Async Views" section in https://www.django-rest-framework.org/api-guide/views/ noting that support for those is provided by this third party package?

tomchristie avatar Nov 30 '22 14:11 tomchristie

What is the status of this?

smittysmee avatar Feb 20 '23 18:02 smittysmee

I'd still agree with my comment above... I'd suggest that someone opens a pull request adding adrf to the documentation, as this will help improve its visibility.

tomchristie avatar Feb 21 '23 11:02 tomchristie

I'm curious the reason not to pull adrf fully into DRF if it is the solution?

johnthagen avatar Feb 21 '23 12:02 johnthagen

I'm curious the reason not to pull adrf fully into DRF if it is the solution?

If we're going to add complexity to a codebase, then we need to be confident that it's worth the trade-off. Dealing with that as a third party package is a more flexible way to explore the design space, without committing ourselves to it.

tomchristie avatar Feb 21 '23 13:02 tomchristie

I can update the PR to make it ""async all-the-way" if it would make it acceptable

It'd certainly be interesting to know what that'd look like. (It's still very likely I'd prefer to see work there in a third party package, but.)

The sync-to-async wrapper makes it really nice and easy, but we're also essentially indulging in false advertising. Async in that case isn't going to improve overall request/response concurrency at all, and really only potentially helps in exceedingly narrow use-cases such as "we need a view that makes two outgoing HTTP requests in parallel".

@tomchristie Could you please elaborate on why it would only potentially improve concurrency when running multiple outgoing long-running HTTP requests? I've seen you really try to underline that you do not want to offer any false expectations and false marketing here in this thread (which makes sense!), but in this particular scenario I am curious if you could explain more? This is purely the only reason I want to add async behaviour to some(!) of our views

errrken avatar Feb 26 '23 09:02 errrken

I can update the PR to make it ""async all-the-way" if it would make it acceptable

It'd certainly be interesting to know what that'd look like. (It's still very likely I'd prefer to see work there in a third party package, but.) The sync-to-async wrapper makes it really nice and easy, but we're also essentially indulging in false advertising. Async in that case isn't going to improve overall request/response concurrency at all, and really only potentially helps in exceedingly narrow use-cases such as "we need a view that makes two outgoing HTTP requests in parallel".

@tomchristie Could you please elaborate on why it would only potentially improve concurrency when running multiple outgoing long-running HTTP requests? I've seen you really try to underline that you do not want to offer any false expectations and false marketing here in this thread (which makes sense!), but in this particular scenario I am curious if you could explain more? This is purely the only reason I want to add async behaviour to some(!) of our views

Async IO doesn't necessarily speeds up your code, it just reduces the server resources usage for concurrent tasks by leveraging concurrent network IO in a single-threaded application.

HMaker avatar Apr 07 '23 16:04 HMaker