RobertCraigie / prisma-client-py

Prisma Client Python is an auto-generated and fully type-safe database client designed for ease of use
https://prisma-client-py.readthedocs.io
Apache License 2.0
1.85k stars 81 forks source link

RuntimeError('Event loop is closed') #939

Open sojha-flip opened 5 months ago

sojha-flip commented 5 months ago

Bug description

Getting RuntimeError('Event loop is closed') for every 2nd request

How to reproduce

Prisma client Connect is called once while starting the server as visible below This is what the main.py file looks like

async def main():
    from foo import configuration
    from foo import app

    port = configuration.service_config.port

    server_config = Config()
    server_config.bind = [f"0.0.0.0:{port}"]
    server_config.include_server_header = False
    logger.info(f"server configuration: {server_config}")

    await prisma_client.connect()
    await serve(app=app, config=server_config, mode="wsgi")

if __name__ == "__main__":
    asyncio.run(main())

Every 2nd request fails with the following logs

| Traceback (most recent call last):
|   File "/opt/foo/.venv/lib/python3.11/site-packages/httpcore/_async/http11.py", line 111, in handle_async_request
|     ) = await self._receive_response_headers(**kwargs)
|         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|   File "/opt/foo/.venv/lib/python3.11/site-packages/httpcore/_async/http11.py", line 176, in _receive_response_headers
|     event = await self._receive_event(timeout=timeout)
|             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|   File "/opt/foo/.venv/lib/python3.11/site-packages/httpcore/_async/http11.py", line 212, in _receive_event
|     data = await self._network_stream.read(
|            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|   File "/opt/foo/.venv/lib/python3.11/site-packages/httpcore/_backends/anyio.py", line 34, in read
|     return await self._stream.receive(max_bytes=max_bytes)
|            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|   File "/opt/foo/.venv/lib/python3.11/site-packages/anyio/_backends/_asyncio.py", line 1202, in receive
|     self._transport.resume_reading()
|   File "/usr/local/lib/python3.11/asyncio/selector_events.py", line 852, in resume_reading
|     self._add_reader(self._sock_fd, self._read_ready)
|   File "/usr/local/lib/python3.11/asyncio/selector_events.py", line 917, in _add_reader
|     self._loop._add_reader(fd, callback, *args)
|   File "/usr/local/lib/python3.11/asyncio/selector_events.py", line 266, in _add_reader
|     self._check_closed()
|   File "/usr/local/lib/python3.11/asyncio/base_events.py", line 520, in _check_closed
|     raise RuntimeError('Event loop is closed')
| RuntimeError: Event loop is closed
| 
| During handling of the above exception, another exception occurred:
| ..........
| Traceback (most recent call last):
|                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|     response = await self._prisma_client.servicedependencymap.find_first(
|                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|   File "/opt/foo/.venv/lib/python3.11/site-packages/prisma/actions.py", line 544, in find_first
|     resp = await self._client._execute(
|            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|   File "/opt/foo/.venv/lib/python3.11/site-packages/prisma/_base_client.py", line 533, in _execute
|     return await self._engine.query(builder.build(), tx_id=self._tx_id)
|            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|   File "/opt/foo/.venv/lib/python3.11/site-packages/prisma/engine/_query.py", line 404, in query
|     return await self.request(
|            ^^^^^^^^^^^^^^^^^^^
|   File "/opt/foo/.venv/lib/python3.11/site-packages/prisma/engine/_http.py", line 217, in request
|     response = await self.session.request(method, url, **kwargs)
|                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|   File "/opt/foo/.venv/lib/python3.11/site-packages/prisma/_async_http.py", line 26, in request
|     return Response(await self.session.request(method, url, **kwargs))
|                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|   File "/opt/foo/.venv/lib/python3.11/site-packages/httpx/_client.py", line 1574, in request
|     return await self.send(request, auth=auth, follow_redirects=follow_redirects)
|            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|   File "/opt/foo/.venv/lib/python3.11/site-packages/ddtrace/contrib/httpx/patch.py", line 137, in _wrapped_async_send
|     resp = await wrapped(*args, **kwargs)
|            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|   File "/opt/foo/.venv/lib/python3.11/site-packages/httpx/_client.py", line 1661, in send
|     response = await self._send_handling_auth(
|                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|   File "/opt/foo/.venv/lib/python3.11/site-packages/httpx/_client.py", line 1689, in _send_handling_auth
|     response = await self._send_handling_redirects(
|                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|   File "/opt/foo/.venv/lib/python3.11/site-packages/httpx/_client.py", line 1726, in _send_handling_redirects
|     response = await self._send_single_request(request)
|                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|   File "/opt/foo/.venv/lib/python3.11/site-packages/httpx/_client.py", line 1763, in _send_single_request
|     response = await transport.handle_async_request(request)
|                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|   File "/opt/foo/.venv/lib/python3.11/site-packages/httpx/_transports/default.py", line 373, in handle_async_request
|     resp = await self._pool.handle_async_request(req)
|            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|   File "/opt/foo/.venv/lib/python3.11/site-packages/httpcore/_async/connection_pool.py", line 268, in handle_async_request
|     raise exc
|   File "/opt/foo/.venv/lib/python3.11/site-packages/httpcore/_async/connection_pool.py", line 251, in handle_async_request
|     response = await connection.handle_async_request(request)
|                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|   File "/opt/foo/.venv/lib/python3.11/site-packages/httpcore/_async/connection.py", line 103, in handle_async_request
|     return await self._connection.handle_async_request(request)
|            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|   File "/opt/foo/.venv/lib/python3.11/site-packages/httpcore/_async/http11.py", line 132, in handle_async_request
|     await self._response_closed()
|   File "/opt/foo/.venv/lib/python3.11/site-packages/httpcore/_async/http11.py", line 245, in _response_closed
|     await self.aclose()
|   File "/opt/foo/.venv/lib/python3.11/site-packages/httpcore/_async/http11.py", line 253, in aclose
|     await self._network_stream.aclose()
|   File "/opt/foo/.venv/lib/python3.11/site-packages/httpcore/_backends/anyio.py", line 54, in aclose
|     await self._stream.aclose()
|   File "/opt/foo/.venv/lib/python3.11/site-packages/anyio/_backends/_asyncio.py", line 1261, in aclose
|     self._transport.close()
|   File "/usr/local/lib/python3.11/asyncio/selector_events.py", line 864, in close
|     self._loop.call_soon(self._call_connection_lost, None)
|   File "/usr/local/lib/python3.11/asyncio/base_events.py", line 762, in call_soon
|     self._check_closed()
|   File "/usr/local/lib/python3.11/asyncio/base_events.py", line 520, in _check_closed
|     raise RuntimeError('Event loop is closed')
| RuntimeError: Event loop is closed

Expected behavior

Prisma information

Environment & setup

❯ prisma py version
prisma                  : 5.11.0
prisma client python    : 0.13.1
platform                : darwin
expected engine version : efd2449663b3d73d637ea1fd226bafbcf45b3102
installed extras        : []
install path            : /Users/foo/.venv/lib/python3.11/site-packages/prisma
binary cache dir        : /Users/foo/.cache/prisma-python/binaries/5.11.0/efd2449663b3d73d637ea1fd226bafbcf45b3102
RobertCraigie commented 5 months ago

are you spawning multiple threads?

sojha-flip commented 5 months ago

I am not. The app is being run asyncio as visible in the main() function I added in the problem description. This problem goes away if I explicitly call connect and disconnet before every request.

await prisma_client.connect()

response = await self._prisma_client.dependencymap.find_first(
    where={
        ...
    },
)

await prisma_client.disconnect()