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

asyncio support #3103

Closed
graingert opened this issue Mar 6, 2017 · 36 comments
Closed

asyncio support #3103

graingert opened this issue Mar 6, 2017 · 36 comments
Assignees
Labels
type: feature request ‘Nice-to-have’ improvement, new feature or different behavior or design.

Comments

@graingert
Copy link

graingert commented Mar 6, 2017

I want to use google-cloud-python in a Sanic web service, however I'm having to use run_in_executor() to use this library without stalling the eventloop.

This is much less efficient than an Asyncio native client.

@graingert
Copy link
Author

graingert commented Mar 6, 2017

@jonparrott it would be possible to support python 2.x and python 3.x with various event loops from the same source by using a custom deferred, future or IOAction implementation.

@theacodes
Copy link
Contributor

This might be possible once we exorcise httplib2 from this project. @lukesneeringer

@lukesneeringer
Copy link
Contributor

That sounds right to me (and that has moved up in priority slightly).

Tagging #1998 for reference.

@lukesneeringer lukesneeringer added priority: p2 Moderately-important priority. Fix may not be included in next release. Status: Acknowledged status: blocked Resolving the issue is dependent on other work. labels Mar 6, 2017
@graingert
Copy link
Author

graingert commented Mar 6, 2017

the core code would use Action composition:

return get_url(xys).map(process_request).flat_map(make_another_request)

Then there could be various, pluggable http transport implementations, that would take an Action instance and return a Future from various event systems (asyncio, twisted), or even use blocking IO.

@graingert
Copy link
Author

graingert commented Mar 8, 2017

import asyncio
import functools


class AsyncIOAction(object):
    def __init__(self, fn):
        this.exec = fn

    def map(self, fn):
        @functools.wraps(fn)
        async def exec():
            value = await self.exec()
            return fn(value)

        return AsyncIOAction(exec)

    def flat_map(self, fn):
        @functools.wraps(fn)
        async def exec():
            value = await self.exec()
            return await fn(value).exec()

        return AsyncIOAction(exec)

    @classmethod
    def all(items):
        async def exec():
            return await asyncio.wait([x.exec() for x in items])

        return AsyncIOAction(exec)

def aiohttp_action(request):
    async def exec():
        return await aiohttp.request(**request)

    return AsyncIOAction(exec)
        
# blocking.py
import functools

class BlockingIOAction(object):
    def __init__(self, fn):
        this.exec = fn

    def map(self, fn):
        @functools.wraps(self, fn)
        def exec():
            value = self.exec()
            return fn(value)
        return BlockingIOAction(exec)

    def flat_map(self, fn):
        @functools.wraps(fn)
        def exec():
            value = self.exec()
            return fn(value).exec()
        
        return BlockingIOAction(exec)

    @classmethod
    def all(items):
        def exec():
            return [x.exec() for x in items]

        return BlockingIOAction(exec)

def requests_action(request): # or httplib2 etc.
    def exec():
        requests.request(**request)

    return BlockingIOAction(exec)

# twisted.py

class TwistedIOAction(object):
    ...

Should be pretty easy with twisted deferred too. Idea being, calling code would choose an IO type, configure the google cloud platform library appropriately, call a method on some API endpoint and then be able to call .exec() on the returned action. The calling code would then be able to receive the value, await and receive the value, or yield it in twisted inline callbacks.

@graingert
Copy link
Author

@graingert
Copy link
Author

graingert commented Mar 8, 2017

inside google code platform:

def some_api_method(IOAction, ham, spam):
    @IOAction.inline_callbacks
    def _some_api_method():
        v = yield some_other_method(IOAction, ham)
        v2 = yield another_method(IOAction, spam, v)
        Return(v + v2)
        
return _some_api_method()

In some calling code:

async def async_caller():
    await some_api_method(AsyncIOAction, ham="ham", spam="spam").exec()

def blocking_caller():
    some_api_method(BlockingIOAction, ham="ham", spam="spam").exec()

@graingert
Copy link
Author

of course https://pypi.python.org/pypi/txaio might be a better way of implementing it.

@theacodes
Copy link
Contributor

@graingert oh that's super interesting. However, this seems to re-enforce the fact that we can't really support this without breaking our public interface and without seriously re-thinking all of our internals. We'd have to start from scratch with this in mind. :/

@graingert
Copy link
Author

graingert commented Jul 24, 2017

@jonparrott with crossbario/txaio#113 and crossbario/txaio#110

you probably won't have to change that much.

And you'd be able to keep the same public api for people using requests.

@theacodes
Copy link
Contributor

inlinecallbacks would help, but this is an enormous undertaking and a lot of our code that deals with IO is non-trivial (resumable-media).

I'm open to doing this, but from my perspective it seems like the tooling isn't quite ready and it would take an enormous amount of engineering effort to get all of our plumbing ready- plus, we have a consider how gRPC plays into all this.

@dhermes
Copy link
Contributor

dhermes commented Jul 24, 2017

FWIW, resumable-media would be the easiest thing of all to add support for because the actual I/O is "isolated" (I took the sans-I/O approach when writing it)

@graingert
Copy link
Author

@jonparrott @dhermes yeah a sans-io approach for this whole library would be the best option!

@theacodes
Copy link
Contributor

then it might be a good place to proof-of-concept this?

@dhermes
Copy link
Contributor

dhermes commented Jul 24, 2017

@jonparrott I'm happy to review PRs but I don't have cycles.

As an example, take a look at the very small amount of code in ResumableUpload.transmit_next_chunk:

        method, url, payload, headers = self._prepare_request()
        result = _helpers.http_request(
            transport, method, url, data=payload, headers=headers,
            retry_strategy=self._retry_strategy)
        self._process_response(result, len(payload))
        return result

Every public method is split into "prepare" and "process" stages in the same way.

@lukesneeringer lukesneeringer added type: feature request ‘Nice-to-have’ improvement, new feature or different behavior or design. and removed status: blocked Resolving the issue is dependent on other work. priority: p2 Moderately-important priority. Fix may not be included in next release. labels Aug 8, 2017
@lukesneeringer
Copy link
Contributor

I am going to move this to resumable-media.

@lukesneeringer
Copy link
Contributor

This issue was moved to googleapis/google-resumable-media-python#28

@ncouture
Copy link

ncouture commented May 15, 2018

#4513 (Firebase/Firestore listen/watch/server-sent events) brought me here as it seems like a good candidate for using asyncio;

@lukesneeringer should there be medium or long-term plans for using asyncio in google-cloud-python?

@theacodes
Copy link
Contributor

There really isn't a feasible way for us to support asyncio until we can drop Python 2 support.

@graingert
Copy link
Author

graingert commented May 15, 2018 via email

@theacodes
Copy link
Contributor

Supporting twisted is essentially removing our entire underlying transport and replacing it, not to mention replacing all of the layers above that with async layers. That doesn't even get into grpc. It's just not feasible while we still have to support Python 2.

I would love to be pushing the edge of the boundaries here, but it's really not commercially viable for us to drop Python 2, re-architect our GA libraries, or force our users to use a large dependency like Twisted (we already have enough on our hands with grpc).

@systocrat
Copy link

systocrat commented Jul 23, 2018

How feasible would it be for a third party to implement functionality of certain services with asyncio or Twisted on their own? Is the documentation there for it?

@vladyslav2
Copy link

@theacodes Thea, why don't you want to create a new repo with support asyncio and without python2?

In that case, your clients will be able to choose which way they are want to move.
And by the way - some of us too commercial clients and already been using asyncio for a few years!
I'm sad to see google does not have any plans to support it

@theacodes
Copy link
Contributor

theacodes commented Jul 31, 2018 via email

@vladyslav2
Copy link

@theacodes why do you believe supporting python 3 will be so significant big task?
Are you willing to accept help from a community? I just check iot-core (stuff that i'm interested) and most of calls based on the paho.mqtt.python library which does support asyncio.
So, i'm expecting I can port google-cloud-python/iot in few days since you have tests coverage

@theacodes
Copy link
Contributor

theacodes commented Jul 31, 2018 via email

@alexpirine
Copy link

Please drop support for 2.7 now and add asyncio support :)
Blocking networking calls is such a slow, has-been thing…

@rubik
Copy link

rubik commented Aug 7, 2019

What is the status of this issue? Will it be fixed in the near future?

@tseaver
Copy link
Contributor

tseaver commented Aug 7, 2019

@rubik Dropping 2.7 support is scheduled for Q1 2020. Adding asyncio support will be a major effort, but the relative priority for it isn't set, AFAIK.

@kamyar
Copy link

kamyar commented Jun 3, 2020

Is there any development on this front?
Also can you please reopen this issue as it is mentioned as a blocker for firebase/firebase-admin-python#104 ?
We have been using firestore and lack of async is a very big downside of firestore.
If async supported is not planned for google services, It would be nice if we know beforehand so we can plan our migration to services that support it. Lack of this feature is causing us both money and product quality tbh.

@software-dov
Copy link
Contributor

API core is adding asyncio support right now (see here for details), but it's tough to say how long before client libraries providing asynchronous interfaces will be available.

@ghost
Copy link

ghost commented Feb 2, 2021

So whats going on with this? Did it make happen after half a year or not?

@ntoshev
Copy link

ntoshev commented Mar 17, 2021

This is sorely needed, @lukesneeringer. An update will be greatly appreciated.

I'm trying to work it around using https://github.com/talkiq/gcloud-aio

@NoamNol
Copy link

NoamNol commented Aug 8, 2021

What do you think about Aiogoogle?

@adriangb
Copy link

adriangb commented Apr 17, 2022

FWIW one workaround I've been using is generating presigned URLs for myself and then using them with httpx. But that compounds with other issues, namely #922. Python 2 has been EOL for 2 years now.

@zagfai
Copy link

zagfai commented Jun 9, 2022

We make our lib which support asyncio for spanner open source: https://pypi.org/project/aspanner/

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
type: feature request ‘Nice-to-have’ improvement, new feature or different behavior or design.
Projects
None yet
Development

No branches or pull requests

17 participants