SAP / python-pyodata

Enterprise-ready Python OData client
Apache License 2.0
220 stars 93 forks source link

persist async session #277

Closed developer992 closed 4 months ago

developer992 commented 4 months ago

Hello

I am trying to figure out how to persist a client async session

from the docs:

service_aiohttp = await pyodata.Client.build_async_client(SERVICE_URL, aiohttp.ClientSession())

problem 1: await cannot be used outside async function

ok, solution?

async def build():
    return await pyodata.Client.build_async_client(SERVICE_URL, session)

nope; RuntimeError: Timeout context manager should be used inside a task

so then i used with statement like so:

async def build_aclient(self):
    async with aiohttp.ClientSession() as session:
        session.headers.update({"Authorization": f"Bearer {self.access_token}"})
        yield await pyodata.Client.build_async_client(self.service_url, session)

this could work BUT, you need to loop through clients and there is always only one

async for aclient in build_aclient():
    items = await aclient.entity_sets.resource.get_entities().select('key1,key2').async_execute()

which is not ideal. if return is used instead of yield, the session is terminated as soon as the function exits, per expectations

I don't want to use with aiohttp.ClientSession() as session in every function as I need to implement several services and would like to keep things tidy.

Many thanks for the ideas.

developer992 commented 4 months ago

I found many resources but i can't figure it out:

https://github.com/aio-libs/aiohttp/issues/4932 https://docs.aiohttp.org/en/latest/client_advanced.html#aiohttp-persistent-session

What even is App in this context and why would I cache to some object outside? Doesn't seem very useful..

phanak-sap commented 4 months ago

Hi @developer992,

I am sorry, but this not seems to be a issue actionable by some fix in this library - seems more like generic "howto use specific async python networking library". We intentionally kept the pyodata api as simple as possible, so the details would be related to request, asyncio, httpx and similar libraries. The session management for original, request-like sync api also is dependent on how a programmer is using the Requests(-like) library - session instances are not created inside pyodata, just provided from outside. You need at the moment google/stackoverflow around async sessions with the library you use.

The second parameter aiohttp.ClientSession() in your first example is a builder of new session instance, so it is up to you how to handle/persist a theasync session before calling the pyodata.Client.build_async_client. The client is just "an odata service endpoint", in effect just specific URL and after initialization, with stored odata metadata. HTTP networking is up to the pyodata library user, to manage how he sees fit.

If you later see a problem with current async API, feel free to reopen this issue, ideally with a failing test resp. sample code that is "expected" and not working at the moment. I must say that I am not an expert on python async networking anyway (if you check the PR history, this was a community-driven PR), so cannot provide you with "one best/correct example of usage".