Skip to content

Conversation

@james-garner-canonical
Copy link
Contributor

@james-garner-canonical james-garner-canonical commented Mar 12, 2025

Description

Fixes: #1252

QA Steps

Test should keep passing.

Notes & Discussion

I wonder if we need to bump our minimum websockets version.

@james-garner-canonical james-garner-canonical force-pushed the 2025-03/fix/websockets-connectionclosed branch from 479d75f to d670e79 Compare March 12, 2025 00:13
Copy link
Contributor

@dimaqq dimaqq left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There seems to be 3 cases of raise ConnectionClose*** in the codebase.

Pls check if those other invocations also need a fix or could use a simplification.

@james-garner-canonical james-garner-canonical force-pushed the 2025-03/fix/websockets-connectionclosed branch from 60b6c10 to ec3420f Compare March 12, 2025 01:34
@james-garner-canonical
Copy link
Contributor Author

The two in juju/client/connection.py seem like they should be fine.

On line 383 we have raise websockets.exceptions.ConnectionClosedOK(None, None)

On line 571 we have raise websockets.exceptions.ConnectionClosed(...) with a single argument, which should also be fine with the logic that causes #1252

I've updated the instance in tests/unit/test_connection.py to hopefully be more future proof. I guess our tests are using older websockets where this isn't a problem, so it's nice that things are passing there, but should we be using the new websockets version?

@dimaqq
Copy link
Contributor

dimaqq commented Mar 12, 2025

This repo CI would ideally run against oldest and newest supported versions of dependencies.
Then again, i'm hesitant to invest time in that up front.
So, let's do a manual spot check and call it a day :)

@james-garner-canonical
Copy link
Contributor Author

Sounds good. What would a manual spot check entail in this case?

@dimaqq
Copy link
Contributor

dimaqq commented Mar 12, 2025

Raising these exceptions using oldest/newest versions of websockets that we support.
I think that should do it.

@dimaqq
Copy link
Contributor

dimaqq commented Mar 12, 2025

Another possibility is to look if the code should be raising ConnectionClosedOK or ConnectionClosedError and not the base class.

@dimaqq
Copy link
Contributor

dimaqq commented Mar 12, 2025

See https://websockets.readthedocs.io/en/stable/reference/exceptions.html#websockets.exceptions.ConnectionClosed

The signature was changed in websockets 10.0, but there's no direct guidance how to "update your code".

My take is that we should either not supply any arguments, or supply the minimal arguments that are required.

@dimaqq
Copy link
Contributor

dimaqq commented Mar 12, 2025

P.S. ugh websockets==13.1 release was not made form the 13.x maintenance branch 🙈

@dimaqq
Copy link
Contributor

dimaqq commented Mar 12, 2025

Let's update every single place this package raises a websockets exception:

  • raise ConnectionClosedOK() whenever it seems that the situation is OK
    • current code has OK
    • or current code has code 1000 or 1001
  • raise ConnectionClosedError() otherwise

As far as I can see, websockets versions that are new enough don't require arguments for these exception classes.

Edit: as James rightfully points out below, raise ConnectionClosedOK|Error(None, None).

Two arguments are required, rcvd and sent, both of which should be a
`websockets.frames.Closed` object or None. If neither are None, the
third argument should also be provided to say in which order sent and
rcvd occurred.

The existing style appears to have been based on an older API which
looks more similar to raising a `Closed` object directly (a code and
reason are provided).

The exception types are exposed on websockets directly, so I've also
removed references to websockets.exceptions.ConnectionClosed.
@james-garner-canonical
Copy link
Contributor Author

james-garner-canonical commented Mar 17, 2025

It seems that for the oldest version of websockets that we support (13.0.1) and for the latest release (15.0.1) the ConnectionClosed exceptions require both rcvd and sent arguments. These should be websockets.frames.Closed objects or None. If both are Closed objects, then the third argument is also required, to specify which order they occurred in.

The instance that caused our users problems here did raise ConnectionClosed(int_code, str_reason), which may be an older API, or may just be wrong -- it's using the arguments expected for a Closed object. ConnectionClosed only checks if the arguments are None, so it doesn't complain -- except that it now requires the third argument if they're both non-None, which is what we're hitting here.

I'm not sure what's expected typically, but in the cases where we raise a ConnectionClosed manually, I don't see an obvious thing to put in sent and rcvd other than None, so I've gone with that. This gives the message 'no close frame received or sent', which I guess is fine here.

For a little bit more user facing information, I've changed them to ConnectionClosedOK in connection.py since they seem to be for cases where the socket already closed cleanly, and to ConnectionClosedError in model/__init__.py -- but maybe that should be ConnectionClosedOK too?

Oh and the exception types are exposed on websockets directly, so I've removed the use of websockets.exceptions just to clean up.

@james-garner-canonical
Copy link
Contributor Author

Test coverage is clearly not great here, as it didn't catch the issue our users encountered, nor did it catch my original broken 'fix' of raising with no arguments (two arguments are required), but I've manually verified on oldest (13.0.1) and newest (15.0.1) versions of websockets that the current exceptions raise cleanly.

@dimaqq
Copy link
Contributor

dimaqq commented Mar 18, 2025

I suspect that bundle errors are unrelated.
I've made #1256 to test that theory.

@dimaqq
Copy link
Contributor

dimaqq commented Mar 18, 2025

I think the latest anbox bundle is broken: https://bugs.launchpad.net/anbox-cloud/+bug/2103485
And the dummy PR fails in the very same way as this.

@dimaqq
Copy link
Contributor

dimaqq commented Mar 18, 2025

/build

@dimaqq
Copy link
Contributor

dimaqq commented Mar 18, 2025

/merge

@dimaqq dimaqq marked this pull request as ready for review March 18, 2025 06:14
@jujubot jujubot merged commit daeb873 into juju:main Mar 18, 2025
60 of 76 checks passed
@dimaqq dimaqq mentioned this pull request Mar 18, 2025
jujubot added a commit that referenced this pull request Mar 19, 2025
#1257

## What's Changed
* chore: fix changelog format by @dimaqq in #1248
* docs: move docs from juju.is by @tmihoc in #1244
* chore: type hint improvements from the helper thread branch by @dimaqq in #1250
* chore: remove pyrfc3339 and change to datetime.datetime.fromisoformat… by @EdmilsonRodrigues in #1247
* fix: create websockets ConnectionClosed error correctly by @james-garner-canonical in #1255
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

Successfully merging this pull request may close these issues.

libjuju failure when trying to raise a websocket connection closed exception

3 participants