773f99790e66b4865529da353a270052b7020a42
I've managed to reproduce this on Ubuntu with Python 3.10 and an older Granian version as well, so not sure if the above version info is really relevant, just included for good measure.
The issue is that with --opt
, if you run and await a coroutine with asyncio.create_task()
, any exceptions raised in the task can't be caught from the outside.
Repro case repro.py
:
import asyncio
async def _raise_error():
await asyncio.sleep(0)
raise RuntimeError("This is an error")
async def app(scope, receive, send):
if scope["type"] == "http":
try:
match await receive():
case {"type": "http.request"} if scope.get("path") == "/ok":
await send({"type": "http.response.start", "status": 200, "headers": []})
await send({"type": "http.response.body", "body": b"Everything works"})
case {"type": "http.request"} if scope.get("path") == "/error":
await asyncio.create_task(_raise_error())
case _:
pass
except Exception as e:
await send({"type": "http.response.start", "status": 500, "headers": []})
await send({"type": "http.response.body", "body": str(e).encode()})
else:
raise RuntimeError(scope["type"])
When running the app without --opt
, we get the expected response:
$ granian --interface asginl repro:app
...
$ curl http://localhost:8000/error
This is an error
But the same request with --opt
enabled results in this:
$ granian --interface asginl --opt repro:app
[INFO] Starting granian (main PID: 37716)
[INFO] Listening at: http://127.0.0.1:8000
[INFO] Spawning worker-1 with pid: 37718
[INFO] Started worker-1
[INFO] Started worker-1 runtime-1
[ERROR] Application callable raised an exception
Traceback (most recent call last):
File "/Users/crank/dev/granian-issue/repro.py", line 5, in _raise_error
raise RuntimeError("This is an error")
RuntimeError: This is an error
Exception in callback <built-in method _loop_wake of builtins.CallbackTaskHTTP object at 0x102109bb0>
handle: <Handle CallbackTaskHTTP._loop_wake>
Traceback (most recent call last):
File "uvloop/cbhandles.pyx", line 63, in uvloop.loop.Handle._run
StopIteration
And the custom error response is not returned:
$ curl http://localhost:8000/error
Internal server error
While writing this issue, I noticed that if I move the whole try ... except
block inside the function that's wrapped in a task everything works as expected, so this seems to be less of an issue than I originally thought.
Anyway, this issue seems somewhat related to #323, so if you still feel like just dropping --opt
in the future feel free to close this as wontfix
π
Pay now to fund the work behind this issue.
Get updates on progress being made.
Maintainer is rewarded once the issue is completed.
You're funding impactful open source efforts
You want to contribute to this effort
You want to get funding like this too