Dmitri Kalbfleysh
Dmitri Kalbfleysh

Reputation: 73

Errno None Can not write request body for <my_url> with a large number of requests

The tracker often receives an error that I have not been able to fix and reproduce for a long time.

This is what my client looks like

class Client:
    _auth = (API_USER, API_PASSWORD)

    def __init__(self):
        self.auth = aiohttp.BasicAuth(self._auth[0], self._auth[1])

    async def send(self, url, json, debug=True,):
        try:
            async with aiohttp.ClientSession(
                    connector=aiohttp.TCPConnector(verify_ssl=False),
                    raise_for_status=True,
            ) as session:
                async with session.post(
                        url=url,
                        json=json,
                        auth=self.auth,
                ) as response:
                    if debug:
                        print(f"{url} response.status", response.status, json)
                    if response.status not in [200, 201]:
                        error = False
                        result = None
                        return error, result

                    error = False
                    result = await response.json(content_type=None)

                    if 'error' in result:
                        if debug:
                            print(f'{url} error', result, json)
                        error = True
                        result = None

                    return error, result
        except (
                aiohttp.client_exceptions.ClientResponseError,
                aiohttp.client_exceptions.ClientConnectorError,
                JSONDecodeError,
                TimeoutError,
        ) as e:
            error = True
            result = None
            return error, result


Client.send(
    url="my_url",
    json=my_json
)

Please tell me what the problem is

To Reproduce: Do not know how

Expected behavior: Send request normally

Logs/tracebacks:

ConnectionResetError: Cannot write to closing transport
  ...
  File "aiohttp/http_writer.py", line 67, in _write
    raise ConnectionResetError('Cannot write to closing transport')


ClientOSError: [Errno None] Can not write request body for <my_url>
  ...
  File "aiohttp/streams.py", line 588, in read
    await self._waiter

Upvotes: 4

Views: 1562

Answers (1)

莫昌钦
莫昌钦

Reputation: 124

I have solved my problem by creating A new Session. Before, I initialize a Session in the class, and then use it to make plenty of POST requests, I can find this "[Errno None] Can not write request body xxx" occasionally in log file. Thus, I think we should create a new Session on each request, and close it after getting the response.

# before
class TestClient():
    def __init__(self):

        self.a_url = 'http://127.0.0.1:22091/test1'
        self.b_url = 'http://127.0.0.1:22092/test2'
        self.c_url = 'http://127.0.0.1:22093/test3'

        new_loop = asyncio.new_event_loop()
        asyncio.set_event_loop(new_loop)
        self.loop = asyncio.get_event_loop()
        self.session = self.loop.run_until_complete(self.get_session())

    async def get_session(self):
        return aiohttp.ClientSession(read_timeout=2)

    def __del__(self):
        self.loop.close()

    async def async_single_call(self):
        async_time_out = 10
        try:
            task_list = [ 
            asyncio.ensure_future(async_down(self.session, self.a_url, {'msg': "hello"*100000}, async_time_out)),
            asyncio.ensure_future(async_down(self.session, self.b_url, {'msg': "hello"*100000}, async_time_out)),
            asyncio.ensure_future(async_down(self.session, self.c_url, {'msg': "hello"*100000}, async_time_out))]
        except Exception as e:
            print(e)
        finally:
            pass


# after
class TestClient():
    def __init__(self):

        self.a_url = 'http://127.0.0.1:22091/test1'
        self.b_url = 'http://127.0.0.1:22092/test2'
        self.c_url = 'http://127.0.0.1:22093/test3'

        new_loop = asyncio.new_event_loop()
        asyncio.set_event_loop(new_loop)
        self.loop = asyncio.get_event_loop()
     

    def get_session(self):
        return aiohttp.ClientSession(read_timeout=2)

    def __del__(self):
        self.loop.close()

    async def async_single_call(self):
        async_time_out = 10
        the_new_session = self.get_session()
        try:
            task_list = [ 
            asyncio.ensure_future(async_down(the_new_session, self.a_url, {'msg': "hello"*100000}, async_time_out)),
            asyncio.ensure_future(async_down(the_new_session, self.b_url, {'msg': "hello"*100000}, async_time_out)),
            asyncio.ensure_future(async_down(the_new_session, self.c_url, {'msg': "hello"*100000}, async_time_out))]
        except Exception as e:
            print(e)
        finally:
            await the_new_session.close()

I hope it can bring you some inspiration :-)

Upvotes: 1

Related Questions