es.davy.ai

Preguntas y respuestas de programación confiables

¿Tienes una pregunta?

Si tienes alguna pregunta, puedes hacerla a continuación o ingresar lo que estás buscando.

Cerrar automáticamente una sesión aiohttp al salir de Python.

Quiero poder cerrar automáticamente una sesión aiohttp utilizando atexit, pero tengo problemas para averiguar por qué esto no funciona.

Tenía un código que funcionaba anteriormente, pero una vez que definí el bucle de eventos fuera del módulo y dentro del archivo en el que se utilizaba el módulo, se rompe.

Versión simplificada del código:

Funciona como se pretende, pero las funciones públicas no son asíncronas

import module

client = module.Client()
client.foo()
import asyncio
import atexit
import aiohttp

class Client:
    def __init__(self, loop=None):
        self.loop = asyncio.get_event_loop() if loop is None else loop
        atexit.register(self.close)
        self._session = aiohttp.ClientSession(loop=self.loop)

    def _run(self, future):
        return self.loop.run_until_complete(future)

    def close(self):
        self._run(self._session.close())

    def foo(self):
        ...
        self._run(...)
        ...

No funciona como se pretendía, las funciones públicas son asíncronas y el bucle se define en main.py

import module
import asyncio

async def main():
    client = module.Client()
    await client.foo()

asyncio.run(main())
import asyncio
import atexit
import aiohttp

class Client:
    def __init__(self, loop=None):
        self.loop = asyncio.get_event_loop() if loop is None else loop
        atexit.register(self.close)
        self._session = aiohttp.ClientSession(loop=self.loop)

    def _run(self, future):
        return self.loop.run_until_complete(future)

    def close(self):
        self._run(self._session.close())

    async def foo(self):
        ...
        await ...
        ...

El segundo segmento de código genera el error “Event loop is closed”.

Las soluciones que he probado basadas en preguntas similares en StackOverflow dan los errores “el bucle de eventos ya se está ejecutando” o “no hay un bucle de eventos actual en el hilo”.

¿Hay una solución para poder cerrar automáticamente la sesión del cliente cuando el bucle de eventos se crea en otro lugar? ¿Importa si las funciones públicas son asíncronas si no todo dentro de ellas está esperando?

Cualquier ayuda sería apreciada, ¡gracias!

Tags:  , ,

Answer

  1. Avatar for davy.ai

    Para cerrar automáticamente una sesión aiohttp usando atexit cuando el bucle de eventos se crea en otro lugar, puede pasar el bucle al constructor de ClientSession en lugar de usar el bucle predeterminado. De esta manera, la sesión usará el mismo bucle que el utilizado por las funciones públicas. Además, no importa si las funciones públicas son asincrónicas si no se espera todo dentro de ellas.

    Aquí hay una versión actualizada del código de muestra que debería funcionar:

    # main.py
    import module
    import asyncio
    
    async def main():
        loop = asyncio.get_event_loop()
        client = module.Client(loop=loop)
        await client.foo()
    
    asyncio.run(main())
    
    # module/client.py
    import asyncio
    import atexit
    import aiohttp
    
    class Client:
        def __init__(self, loop=None):
            self.loop = loop or asyncio.get_event_loop()
            atexit.register(self.close)
            self._session = aiohttp.ClientSession(loop=self.loop)
    
        async def close(self):
            await self._session.close()
    
        async def foo(self):
            ...
            await ...
            ...
    

    En esta versión actualizada, pasamos el bucle al constructor de Client, que establece el atributo de bucle y lo pasa al constructor de ClientSession. También hacemos que la función close sea asíncrona utilizando await para cerrar la sesión.

    ¡Esperamos que esto resuelva su problema!

Comments are closed.