0

I am making a discord bot with python. When a user types a command, this bot brings data from url and shows it. I use aiohttp for asynchronous http request, but documentation of discord.py says,

Since it is better to not create a session for every request, you should store it in a variable and then call session.close on it when it needs to be disposed.

So i changed all my codes from

async with aiohttp.ClientSession() as session:
    async with session.get('url') as response:
        # something to do

into

# Global variable
session = aiohttp.ClientSession()

async with session.get('url') as response:
    # something to do

All http requests use globally defined session. But when i run this code and stop by keyboard interrupt(Ctrl + C), this warning messages are appeared.

Unclosed client session
client_session: <aiohttp.client.ClientSession object at 0x0000015A45ADBDD8>
Unclosed connector
connections: ['[(<aiohttp.client_proto.ResponseHandler object at 0x0000015A464925E8>, 415130.265)]']
connector: <aiohttp.connector.TCPConnector object at 0x0000015A454B3320>

How can i close ClientSession when program stops by keyboard interrupt?

What I tried:

I tried following but nothing worked well.

  1. Making a class and close in its __del__. __del__ was not called when keyboard interrupt.
class Session:
    def __init__(self):
        self._session = aiohttp.ClientSession()

    def __del__(self):
        self._session.close()
  1. Infinite loop in main, and catch KeyboardInterrupt. Program is blocked with bot.run() so cannot reach to code.
from discord.ext import commands

if __name__ == "__main__":
    bot = commands.Bot()
    bot.run(token) # blocked
    try:
        while(True):
            sleep(1)
    except KeyboardInterrupt:
        session.close()
  1. Close session when bot is disconnected. on_disconnect had been not called when keyboard interrupt.
@bot.event
async def on_disconnect():
    await session.close()
  • edit: I missed await before session.close(), but this was just my mistake when I wrote this question. All I tried also didn't work well as i expected when i wrote correctly with await.
Ellisein
  • 878
  • 6
  • 17

2 Answers2

1

You must await the closing of a ClientSession object:

await session.close()

Notice coroutine in the docs here. Your attempt #3 is probably best suited for this problem, as it is naturally an async function.

felipe
  • 7,324
  • 2
  • 28
  • 37
  • I missed it when i write this question.. thanks but when i wrote code correctly with `await session.close()`, all i tried didn't work. – Ellisein Jul 24 '19 at 06:27
  • According to their docs [here](https://github.com/Rapptz/discord.py/blob/45375364b7a2225fe9be091f421fbd04e4af9e2e/docs/api.rst), the `on_disconnect()` mentions the following: `Called when the client has disconnected from Discord. This could happen either through the internet being disconnected, explicit calls to logout, or Discord terminating the connection one way or the other.` Perhaps the method is not getting called to begin with (nothing a simple `print` won't show). Try using the magic method `__exit___` instead of `__del__` on your first example. – felipe Jul 24 '19 at 06:57
  • Keep in mind you can't call a `coroutine` within a non-async method with simply the `await`, as your first example suggests. – felipe Jul 24 '19 at 06:59
1

I tried the following code and it seems to work well.

import asyncio
import aiohttp

class Session:
    def __init__(self):
        self._session = aiohttp.ClientSession()

    def __del__(self):
        loop = asyncio.get_event_loop()
        loop.run_until_complete(self.close()

    async def close(self):
        await self._session.close()

session = Session()
Ellisein
  • 878
  • 6
  • 17