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

How to force close underlying connection #3433

Closed
postlund opened this issue Dec 6, 2018 · 6 comments
Closed

How to force close underlying connection #3433

postlund opened this issue Dec 6, 2018 · 6 comments

Comments

@postlund
Copy link

postlund commented Dec 6, 2018

Long story short

As part of my Apple TV library (pyatv), I can request the device to play AirPlay streams by sending "some data" (HTTP) to it over TCP port 7000. This part works fine but the problem is that the device keeps showing a white spinner on the screen as long as the TCP connection remains active, even though the video/music stream has ended. So I want to force-close the underlying connection to indicate that the playback is done. Is this possible?

I would prefer not having to create a new ClientSession for each playback session as a) my library is used by other projects in which I have no control of the session b) authentication must be made on on the same connection prior to playback, which makes the design rather awkward to implement.

Expected behaviour

Some method to force close a particular connection.

Actual behaviour

Connection is kept alive for some time (not sure how long or how I could affect it).

Steps to reproduce

This problem is seen in Home Assistant, if for instance Text-To-Speech (TTS), is used from the Apple TV component.

Your environment

Running latest aiohttp from PyPi with Home Assistant on raspbian and Mac OS. Same behavior. Everything is on local network, no proxies or such.

@aio-libs-bot
Copy link

GitMate.io thinks the contributors most likely able to help are @asvetlov, and @fafhrd91.

Possibly related issues are #3363 (How send "WebSocket Connection Close[FIN]"???), #1799 (Unclosed connection), #1814 (Close websocket connection when pong not received), #3052 (SSL with closed connections), and #1768 (websocket connection is closing.).

@webknjaz
Copy link
Member

webknjaz commented Dec 6, 2018

request.transport?

@asvetlov
Copy link
Member

asvetlov commented Dec 6, 2018

It is a client API.
resp.close() forces closing the socket

@postlund
Copy link
Author

postlund commented Dec 9, 2018

I'm not totally sure it does what I need it to. Let me give you an example:

#!/usr/bin/env python3

import asyncio
import aiohttp

async def do_stuff():
    async with aiohttp.ClientSession() as session:
        async with session.get('http://10.0.10.253') as resp:
            text = await resp.text()
            # do something with text
       	    resp.close()  # Strictly not needed because of `with`, right?
        await asyncio.sleep(30)

if __name__ == '__main__':
    loop = asyncio.get_event_loop()
    loop.run_until_complete(do_stuff())

So I do a request, close the response but do not end the session instance by sleeping for 30 seconds. When checking for active connections using lsof in another terminal, I can see:

$ lsof -i -n | grep 10.0.10.253:http
python3.6 40853 postlund    6u  IPv4 0x5c0d9cedcc112963      0t0  TCP 10.0.10.50:52473->10.0.10.253:http (ESTABLISHED)

It dies after some time, maybe 10 seconds or so, but I would expect it to die immediately when doing close. Is there anything I'm missing with this?

@joeyorlando
Copy link

I'm commenting ~2 years later but maybe try:

async with aiohttp.ClientSession(connector=aiohttp.TCPConnector(force_close=True)) as session:
  ...

from aiohttp.BaseConnector:

force_close - Set to True to force close and do reconnect after each request (and between redirects).

@Dreamsorcerer
Copy link
Member

Dreamsorcerer commented Aug 10, 2024

I'm not totally sure it does what I need it to. Let me give you an example:

The problem here is that after reading the request body, the HTTP message is complete and aiohttp releases the connection back to the pool. So, the call to resp.close() does nothing as the connection is already released.

Using a connector with force_close as described above would be the most reliable way to ensure the connection is actually closed upon completion.

@Dreamsorcerer Dreamsorcerer closed this as not planned Won't fix, can't repro, duplicate, stale Aug 10, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

6 participants