-
-
Notifications
You must be signed in to change notification settings - Fork 954
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
collect errors more reliably from websocket test client #2814
Conversation
@Kludex I think this fixed it |
What was the issue? |
The exception bubbling out of the _run was not being collected properly, and I think the queue EOF/shutdown thing also |
c2049a7
to
c210c27
Compare
This reverts commit c210c27.
I'd recommend reviewing this in side by side view: https://github.com/encode/starlette/pull/2814/files?diff=split |
tg.cancel_scope.cancel() | ||
self.should_close.set() | ||
finally: | ||
self._send_queue.put(EOF) # TODO: use self._send_queue.shutdown() on 3.13+ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should we use the if sys.version_info
here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it's better to stick to the EOF approach until someone puts up a Queue.shutdown backport, or we can use a MemoryObjectStream with portal
message = self._send_queue.get() | ||
if message is EOF: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there an analogous to EOF from the standard library on 3.13?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It raises an exception
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As long as this passes the tests, I'm fine with whatever refactor you think is the best here.
except anyio.get_cancelled_exc_class(): | ||
cancelled = True | ||
raise |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why is the cancelled exception here? Is this because this except was removed?
The addition of that except
was on purpose, if I recall correctly.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this is instead of websocket.should_close.is_set() as it no longer exists - so we need to find out that the async function ran and was cancelled
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
did you mean to ask about this one: https://github.com/encode/starlette/pull/2814/files#diff-aca25e5f16c4fd49338ccdf3631f72455309335fee1e27f3d3b6016fa94ecedfL145 ?
this is because it's no longer possible to get a intentional cancelled_exc here because it will be caught by the CancelScope
if you do get an cancelled_exc here it's because someone incorrectly issued a native asyncio cancel or manually raised a trio cancel, both of which should be propagated out of the websocket_connect cmgr
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Got it.
So the point is: since the WebSocket doesn't call send
it can't receive a disconnect exception, and since it doesn't call receive
, it doesn't receive a websocket.disconnected
message. Then, the TestClient
here will propagate the cancellation exception here, but the user shouldn't worry about it because the TestClient
will catch it anyway.
Right?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yeah, we use a CancelScope passed out with task_status.started(cs), this is then used to cancel the task on completion and collect a result. The CancelScope catches the cancellation that it causes to raise in the coro, unless there's another reason for cancellation which is then propagated, this is a fatal case and so the user should be notified
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So if there's a cancelled exception that is not from the TestClient, the user will see it, right?
I'm good with this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah the only way is if the user was calling .cancel() directly or manually raising constructing a trio cancel (bypassing the private constructor protections)
if isinstance(message, BaseException): | ||
raise message | ||
raise message # pragma: no cover (defensive, should be impossible) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why it should be impossible?
The except BaseException as exc
below doesn't have a pragma: no cover
, so I assume it's being hit?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this is impossible because the exit stack will raise the exception out of fut.result() and so the queue won't be consumed.
This is only possible to be hit if ws.receive()
is interrupted (eg with a KI) while waiting for an exception or message to be placed on the queue.
I'm currently sketching out another slight refactor that uses MemoryObjectStreams here instead that should clean this up a bit
…iddleware' children
Co-authored-by: Thomas Grainger [email protected]
Co-authored-by: Nikita Gashkov [email protected]
Summary
Checklist