msgraph-sdk-python icon indicating copy to clipboard operation
msgraph-sdk-python copied to clipboard

AttributeError: 'NoneType' object has no attribute '__aenter__' when using asyncio.gather

Open MoBoo opened this issue 2 years ago • 12 comments

Hello,

i am using the OnBehalfOf-Flow to fetch informations about applications from graphapi. When using asyncio.gather to "parallelize" multiple requests (e.g. to fetch application infos and application owners) i get this error AttributeError: 'NoneType' object has no attribute '__aenter__.

This is a minimal example the reproduce the error:

async def main():
  scopes = ["https://graph.microsoft.com/Application.ReadWrite.All"]
  credentials = OnBehalfOfCredential(
              tenant_id=<redacted>,
              client_id=<redacted>,
              client_secret=<redacted>,
              user_assertion=<redacted>,
          )
  client = GraphServiceClient(credentials=credentials, scopes=scopes)
  
  app, app_owners = await asyncio.gather(*[
        client.applications.by_application_id<redacted>).get(),
        client.applications.by_application_id(<redacted>).owners.get()
    ])

asyncio.run(main())

When running those two requests sequentially they work without any problems. So i think there is some sort of race condition going on?

For a large amount of requests, this can have quite a performance impact, because it limits the benefits of actually it runnung concurrently.

Maybe there is an easy fix for it, that i might have overlooked. (E.g. manually trigger token exchange before the asyncio.gather call)

MoBoo avatar Dec 07 '23 09:12 MoBoo

The issue might be related to this other discussion: https://github.com/Azure/azure-sdk-for-python/issues/32309. We get the same error but we're not using asyncio.gather.

frejonb avatar Dec 19 '23 15:12 frejonb

I have the same problem, but with ClientSecretCredential

zus666 avatar Jan 15 '24 09:01 zus666

Same here with ClientSecretCredential using it in an AsyncAPIView with django rest framework.

ntsphwoelfel avatar Feb 13 '24 18:02 ntsphwoelfel

Same Issue here

Christiaan-Mathu avatar Feb 27 '24 09:02 Christiaan-Mathu

Same Issue here

[2024-03-15T13:02:17.411Z] ClientSecretCredential.get_token failed: 'NoneType' object has no attribute '__aenter__'

pumon avatar Mar 15 '24 13:03 pumon

This does not only happen when asyncio.gather is used. I make my msgraph api requests by using aiohttp's background tasks, but this also happens. I found a workaround: use sync version instead async version. For example, using from azure.identity import ClientSecretCredential instead from azure.identity.aio import ClientSecretCredential

arenekosreal avatar Mar 27 '24 08:03 arenekosreal

I got the same error in an async with asyncio.TaskGroup() as tg: block. I solved this error by defining GraphServiceClient in the function that I give to tg.create_task().

tasks = []
async with asyncio.TaskGroup() as tg:
  for data in temp:
      task = tg.create_task(foo(data))
      tasks.append(task)
return [task.result() for task in tasks]
async def foo(data):
  credentials = ClientSecretCredential(
        tenant_id=... ,
        client_id=... ,
        client_secret=... 
    )
    scopes = ['https://graph.microsoft.com/.default']
    graph_client = GraphServiceClient(credentials, scopes)

   return await <GRAPH API ENDPOINT>

mattia-danese avatar Apr 06 '24 12:04 mattia-danese

This solved for me:

changed this from azure.identity.aio import ClientSecretCredential to from azure.identity import ClientSecretCredential

The synchronous version of ClientSecretCredential is not being a problem.

ArunJRK avatar Apr 29 '24 07:04 ArunJRK

I'm using this SDK in Azure Durable Functions. I also get this error and it seems more likely to see it the more requests are being made in a certain time period.

danielniccoli avatar May 06 '24 08:05 danielniccoli

I confirm I have the same issue in Azure (Durable) Functions. I'm using ClientSecretCredential from azure.identity.aio. It always happens after an inactivity period.

alessnet avatar May 08 '24 07:05 alessnet

I have the same issue even in local from azure.identity import ClientSecretCredential worked for me. What are the consequences of using the synchronous version of ClientSecretCredential?

joan1294 avatar Jun 25 '24 07:06 joan1294

What are the consequences of using the synchronous version of ClientSecretCredential?

It may block some parts of the execution. But in my experience with asyncio, multiprocessing, and threading, the GIL doesn't make sure the aio improvement doesn't trickle down into faster execution. So it might not be an issue for you here.

ArunJRK avatar Jun 27 '24 06:06 ArunJRK

Hello @danielniccoli thanks for using the SDK and for raising.

On investigating this, it looks to be an issue with Azure_identity's management of sync and async requests rather that on the Graph SDK.

Closing this and moving the workarounds to discussion forums to help anyone who experiences this in the future.

shemogumbe avatar Oct 29 '24 09:10 shemogumbe