Here’s my python fastapi code:
PDF_MIME_TYPE = "application/pdf"
@api_router.get(
"/download_pdf",
response_class=StreamingResponse,
responses={200: {"content": {PDF_MIME_TYPE: {}}}},
)
async def download_pdf():
try:
markdown = await get_answers()
pdf_stream = BytesIO()
pdf_report(markdown, pdf_stream)
headers = {"Content-Disposition": 'attachment; filename="out.pdf"'}
pdf_stream.seek(0)
return StreamingResponse(pdf_stream, headers=headers, media_type=PDF_MIME_TYPE)
except Exception as e:
logging.exception("Error downloading PDF")
return f"error: {e}"
app.include_router(api_router)
It’s working very well in my local environment. But when I deployed on Vercel, it often shows: RuntimeError: Event loop is closed
, just when I access my link a little fast.
Here’s the error log:
INFO:httpx:HTTP Request: POST https://generativelanguage.googleapis.com/v1beta/models/gemini-2.0-flash-exp:generateContent "HTTP/1.1 200 OK"
INFO:httpx:HTTP Request: POST https://generativelanguage.googleapis.com/v1beta/models/gemini-2.0-flash-exp:generateContent "HTTP/1.1 200 OK"
127.0.0.1 - - [18/Dec/2024 10:14:25] "GET /api/download_pdf?path=download_pdf HTTP/1.1" 200 -
it wrap_app_handling_exceptions(app, request)(scope, receive, send)
File "/var/task/starlette/_exception_handler.py", line 53, in wrapped_app
raise exc
File "/var/task/starlette/_exception_handler.py", line 42, in wrapped_app
await app(scope, receive, sender)
File "/var/task/starlette/routing.py", line 73, in app
response = await f(request)
^^^^^^^^^^^^^^^^
File "/var/task/fastapi/routing.py", line 301, in app
raw_response = await run_endpoint_function(
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/var/task/fastapi/routing.py", line 212, in run_endpoint_function
return await dependant.call(**values)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/var/task/api/index.py", line 22, in download_pdf
markdown = await get_answers()
^^^^^^^^^^^^^^^^^^^
File "/var/task/api/deep_thinking.py", line 171, in get_answers
questions = (await reader.run(article)).data
^^^^^^^^^^^^^^^^^^^^^^^^^
File "/var/task/pydantic_ai/agent.py", line 251, in run
model_response, request_cost = await agent_model.request(messages, model_settings)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/var/task/pydantic_ai/models/gemini.py", line 176, in request
async with self._make_request(messages, False, model_settings) as http_response:
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/var/lang/lib/python3.12/contextlib.py", line 210, in __aenter__
return await anext(self.gen)
^^^^^^^^^^^^^^^^^^^^^
File "/var/task/pydantic_ai/models/gemini.py", line 222, in _make_request
async with self.http_client.stream(
^^^^^^^^^^^^^^^^^^^^^^^^
File "/var/lang/lib/python3.12/contextlib.py", line 210, in __aenter__
return await anext(self.gen)
^^^^^^^^^^^^^^^^^^^^^
File "/var/task/httpx/_client.py", line 1628, in stream
response = await self.send(
^^^^^^^^^^^^^^^^
File "/var/task/httpx/_client.py", line 1674, in send
response = await self._send_handling_auth(
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/var/task/httpx/_client.py", line 1702, in _send_handling_auth
response = await self._send_handling_redirects(
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/var/task/httpx/_client.py", line 1739, in _send_handling_redirects
response = await self._send_single_request(request)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/var/task/httpx/_client.py", line 1776, in _send_single_request
response = await transport.handle_async_request(request)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/var/task/httpx/_transports/default.py", line 377, in handle_async_request
resp = await self._pool.handle_async_request(req)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/var/task/httpcore/_async/connection_pool.py", line 256, in handle_async_request
raise exc from None
File "/var/task/httpcore/_async/connection_pool.py", line 229, in handle_async_request
await self._close_connections(closing)
File "/var/task/httpcore/_async/connection_pool.py", line 345, in _close_connections
await connection.aclose()
File "/var/task/httpcore/_async/connection.py", line 173, in aclose
await self._connection.aclose()
File "/var/task/httpcore/_async/http11.py", line 258, in aclose
await self._network_stream.aclose()
File "/var/task/httpcore/_backends/anyio.py", line 53, in aclose
await self._stream.aclose()
File "/var/task/anyio/streams/tls.py", line 201, in aclose
await self.transport_stream.aclose()
File "/var/task/anyio/_backends/_asyncio.py", line 1349, in aclose
self._transport.close()
File "/var/lang/lib/python3.12/asyncio/selector_events.py", line 1210, in close
super().close()
File "/var/lang/lib/python3.12/asyncio/selector_events.py", line 875, in close
self._loop.call_soon(self._call_connection_lost, None)
File "/var/lang/lib/python3.12/asyncio/base_events.py", line 795, in call_soon
self._check_closed()
File "/var/lang/lib/python3.12/asyncio/base_events.py", line 541, in _check_closed
raise RuntimeError('Event loop is closed')
RuntimeError: Event loop is closed
----------------------------------------
I guess this might be the same issue as: Python ASGI runtime creates an event loop on each request · Issue #8477 · vercel/vercel · GitHub but I’m not sure.
Anyone can help?
Thanks.