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

Ping task exception was never retrieved #26

Closed
katichev opened this issue Nov 22, 2021 · 4 comments
Closed

Ping task exception was never retrieved #26

katichev opened this issue Nov 22, 2021 · 4 comments

Comments

@katichev
Copy link

Hi folks,
I'm using sse-starlette in my project and I've recently tried to upgrade starlette 0.14.2 -> 0.16.0 After this I'm getting sporadic warning message:

Task exception was never retrieved
future: <Task finished name='Task-31378' coro=<EventSourceResponse._ping() done, defined at sse_starlette/sse.py:268> exception=ClosedResourceError()>"

Unfortunately I cannot reproduce this issue locally. I did some investigations and found out that run_until_first_complete at sse.py throws CancelledError so stop_streaming is not executed.

My guess is that behaviour is due to anyio in starlette 0.16.0. I've tried to wrap code in __call__ in CancelScope like so:

    async def __call__(self, scope: Scope, receive: Receive, send: Send) -> None:
       with CancelScope(shield=True):
           await run_until_first_complete(
                (self.stream_response, {"send": send}),
                (self.listen_for_disconnect, {"receive": receive}),
                (self.listen_for_exit_signal, {}),
            )
            self.stop_streaming()
            # ... and so on

This seems to work but I'm not pretty sure this is the right way to fix the issue.

Any ideas how to deal with it?

@sysid
Copy link
Owner

sysid commented Nov 24, 2021

Thank you @katichev for your detailed analysis!
Will try to reproduce the issue on my setup and investigate it.

@daxartio
Copy link

daxartio commented Dec 10, 2021

it should be like this

...
    async def __call__(self, scope: Scope, receive: Receive, send: Send) -> None:
        async with anyio.create_task_group() as task_group:

            async def wrap(func: Callable[[], Coroutine[None, None, None]]) -> None:
                await func()
                task_group.cancel_scope.cancel()

            task_group.start_soon(wrap, partial(self.stream_response, send))
            task_group.start_soon(wrap, partial(self._ping, send))
            task_group.start_soon(wrap, self.listen_for_exit_signal)
            await wrap(partial(self.listen_for_disconnect, receive))
        if self.background is not None:
            await self.background()

@sysid
Copy link
Owner

sysid commented Dec 15, 2021

Thanks @daxartio for pointing into the right direction! I updated the code accordingly.

@sysid sysid closed this as completed Dec 15, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants