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.

Se cerró la sesión aiohttp sin salir del administrador de contexto.

Tengo una API bastante complicada con parámetros y encabezados personalizados, por lo que creé una clase para envolverla. Aquí tienes un ejemplo ficticio:

import asyncio
import aiohttp

class MyAPI:
    def __init__(self, base_url: str):
        self.base_url = base_url

async def send(self, session, method, url) -> aiohttp.ClientResponse:
    request_method = getattr(session, method.lower())
    full_url = f"{self.base_url}/{url}"

    async with request_method(full_url) as response:
        return response

async def main():
    api = MyAPI("https://httpbin.org")

    async with aiohttp.ClientSession() as session:
        response = await api.send(session, "GET", "/uuid")
        print(response.status)       # 200 OK
        print(await response.text()) # Exception: Connection closed

asyncio.run(main())

¿Por qué se cerró mi sesión? No salí del gestor de contexto de session.

Si ignoro la clase de envoltura, todo funciona como se esperaba:

async def main():
    async with aiohttp.ClientSession() as session:
        async with session.get("https://httpbin.org/uuid") as response:
            print(await response.text())
Tags:  , ,

Answer

  1. Avatar for davy.ai

    La sesión está cerrada porque el método MyAPI.send() no maneja correctamente la respuesta de la solicitud aiohttp. En el ejemplo dado, el método devuelve el objeto de respuesta de la solicitud, pero no consume el cuerpo de la respuesta. Como resultado, la respuesta permanece abierta y la conexión no se libera de vuelta al grupo hasta que se consume el cuerpo de la respuesta.

    Para solucionar esto, puedes modificar el método MyAPI.send() para que consuma el cuerpo de la respuesta antes de devolver el objeto de respuesta. Aquí tienes un ejemplo actualizado:

    class MyAPI:
        def __init__(self, base_url: str):
            self.base_url = base_url
    
        async def send(self, session, method, url) -> aiohttp.ClientResponse:
            request_method = getattr(session, method.lower())
            full_url = f"{self.base_url}/{url}"
    
            async with request_method(full_url) as response:
                # Consumir el cuerpo de la respuesta antes de devolverla
                response_text = await response.text()
                return response
    
    async def main():
        api = MyAPI("https://httpbin.org")
    
        async with aiohttp.ClientSession() as session:
            response = await api.send(session, "GET", "/uuid")
            print(response.status)       # 200 OK
            print(await response.text()) # Cuerpo de la respuesta
    

    En el ejemplo actualizado, se consume el cuerpo de la respuesta con await response.text() antes de devolver el objeto de respuesta. Esto garantiza que la conexión se libere y que la sesión no se cierre prematuramente.

Comments are closed.