azure-sdk-for-python icon indicating copy to clipboard operation
azure-sdk-for-python copied to clipboard

Async clients close() does not close TCP connection

Open mikeharder opened this issue 3 years ago • 1 comments

It appears that async clients close() method does not close the underlying TCP connection. While running the app below, when the app is waiting for input the second time, session.closed is True, but the TCP connection is still ESTABLISHED (verified by running netstat -an).

import asyncio
import os

from azure.storage.blob.aio import BlobClient

async def main():
    client = BlobClient.from_connection_string(os.environ['STORAGE_CONNECTION_STRING'], 'container_name', 'blob_name')
    session = None
    async with client:
        stream = await client.download_blob()
        session = client._client._client._pipeline._transport.session
        print(session)
        print('session.closed: ' + str(session.closed))
        input('Press Enter to continue...')
    print('session.closed: ' + str(session.closed))
    input('Press Enter to continue...')

asyncio.run(main())

It also repros with KeyVault SecretClient:

import asyncio
import os

from azure.keyvault.secrets.aio import SecretClient
from azure.identity.aio import DefaultAzureCredential

async def main():
    vault_url = os.environ["VAULT_URL"]
    credential = DefaultAzureCredential(additionally_allowed_tenants=['*'])
    session = None
    async with SecretClient(vault_url=vault_url, credential=credential) as client:
        await client.get_secret("secret_name")
        session = client._client._client._pipeline._transport.session
        print(session)
        print('session.closed: ' + str(session.closed))
        input('Press Enter to continue...')
    print('session.closed: ' + str(session.closed))
    input('Press Enter to continue...')

asyncio.run(main())

However, this does not repro when using aiohttp.ClientSession directly. When this app is waiting for input the second time, session.closed is True, and the TCP connection is in TIME_WAIT (meaning the app has closed the connection).

import aiohttp
import asyncio

async def main():
    session = aiohttp.ClientSession()
    async with session:
        async with session.get('http://example.org') as resp:
            print(resp.status)
        print('session.closed: ' + str(session.closed))
        input('Press Enter to continue...')
    print('session.closed: ' + str(session.closed))
    input('Press Enter to continue...')

asyncio.run(main())

Does not repro when using sync BlobClient:

import os
from azure.storage.blob import BlobClient

client = BlobClient.from_connection_string(os.environ['STORAGE_CONNECTION_STRING'], 'container_name', 'blob_name')
stream = client.download_blob()
input('Press Enter to continue...')
client.close()
input('Press Enter to continue...')

Or when using AsyncPipeline directly:

import asyncio

from azure.core.pipeline.transport import HttpRequest
from azure.core.pipeline import AsyncPipeline
from azure.core.pipeline.transport import AioHttpTransport

async def main():
    request = HttpRequest("GET", 'https://example.org')
    async with AsyncPipeline(AioHttpTransport()) as pipeline:
        response = await pipeline.run(request)
        input('Press Enter to continue...')
    input('Press Enter to continue...')

asyncio.run(main())

mikeharder avatar Nov 10 '22 02:11 mikeharder

Label prediction was below confidence level 0.6 for Model:ServiceLabels: 'Service Bus:0.53615165,Storage:0.27983,Azure.Core:0.03194222'

azure-sdk avatar Nov 10 '22 02:11 azure-sdk

Are there any update or workarounds on this ?

aykborstelmann avatar Oct 04 '23 09:10 aykborstelmann

Not sure but my issue #32458 may be related to this, any solution or work around? it is a pretty bad issue as it doesn't allow to get multiple blobs at once essentially making the whole aio blob storage client useless.

PabloRuizCuevas avatar Oct 12 '23 11:10 PabloRuizCuevas