Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Can't catch exception raised during execution of an asyncio.Task if running with --opt #387

Closed
dwarfcrank opened this issue Aug 24, 2024 · 1 comment · Fixed by #452
Closed
Labels
wontfix This will not be worked on

Comments

@dwarfcrank
Copy link

  • OS: macOS 14.5
  • Python version: 3.12.2
  • Granian version: built from commit 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 😅

@gi0baro
Copy link
Member

gi0baro commented Aug 26, 2024

Yes, this is kinda a duplicate of #323, at least the root cause is the same.

Given the README states:

Due to the nature of such handlers some libraries and specific application code relying on asyncio internals might not work.

I will just keep this open for knowledge and add the wontfix label until I figure out what to do with --opt in the future.

@gi0baro gi0baro added the wontfix This will not be worked on label Aug 26, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
wontfix This will not be worked on
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants