-
Notifications
You must be signed in to change notification settings - Fork 43
Support parameter subscriptions #238
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
Support parameter subscriptions #238
Conversation
In the example here, when I'm connected to the app and edit a value, I see duplicated messages with the updated parameters. I think we're notifying the client as the originator of the new parameters, and also as a subscriber. This isn't a big deal, but is probably unnecessary; I wonder if we should skip the former if subscribed. |
So these callbacks notify when a parameter is first subscribed to our last unsubscribed to. Which is why I removed the client from the signature. Which client triggered that doesn't really matter and might confuse the user into thinking they have to do the bookkeeping. The idea is it lets you know when you need to start being concerned about a parameter and when you can stop.
Yeah, that makes sense to me. |
That's a good point. I'm not sure the ws-protocol spec lets us skip the response though? I wonder what we should do 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.
This looks good, but could use some python tests or be added to the params example so it has some usage.
ed96314
to
1d7d287
Compare
OK, that makes sense, and I agree with omitting the client ID; thank you
I don't quite understand the use case here, though. Why would a server only be concerned about a parameter if a client is subscribed to it? Clients could be polling with |
There is a difference in the two messages today, since one of them has an ID. I think we should leave it alone as it's not going to cause problems, but could look at optimizing it down the line. This may evolve away from ws-protocol anyway. |
I updated the example so it sort of explains how the subscription callbacks work. I also added a very basic unit test that includes the listener subscription calls; more to assert that the listener isn't abstract. I've also removed the "parametersSubscribe" per discussion above; see updated PR decsription. |
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.
LG, just some minor comments.
@@ -138,16 +138,13 @@ pub struct RemoveStatus { | |||
} | |||
|
|||
/// A capability that the websocket server advertises to its clients. | |||
#[derive(Debug, Serialize, Eq, PartialEq, Hash)] | |||
#[derive(Debug, Serialize, Eq, PartialEq, Hash, Clone)] |
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.
Make it Copy
too, while you're at it.
let result: PyResult<()> = Python::with_gil(|py| { | ||
let args = (param_names,); | ||
self.listener | ||
.bind(py) | ||
.call_method("on_parameters_unsubscribe", args, None)?; | ||
|
||
Ok(()) | ||
}); |
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.
@eloff this is an example of why I feel uncomfortable about holding locks while making callbacks. In this context, the client poll loop is holding the server.subscribed_parameters
mutex, and now we have to grab the GIL in order to invoke the python callback implementation.
If we ever have a case where a call from python might acquire the server.subscribed_parameters
mutex (we don't have such a case today), that's an AB/BA deadlock waiting to happen (unless we're careful about dropping the GIL first).
@@ -159,17 +156,36 @@ pub enum Capability { | |||
Services, | |||
} | |||
|
|||
/// ws-protocol includes a "parametersSubscribe" capability in addition to "parameters". | |||
/// Because the SDK handles subscription management internally, we only expose the latter publicly. | |||
#[derive(Debug, Serialize, Eq, PartialEq, Hash)] |
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.
Might as well make this Clone & Copy too.
@@ -138,16 +138,13 @@ pub struct RemoveStatus { | |||
} | |||
|
|||
/// A capability that the websocket server advertises to its clients. | |||
#[derive(Debug, Serialize, Eq, PartialEq, Hash)] | |||
#[derive(Debug, Serialize, Eq, PartialEq, Hash, Clone)] | |||
#[serde(rename_all = "camelCase")] | |||
pub enum Capability { |
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.
With this change, it starts to feel like this more abstracted Capability
should move up to crate::websocket
, since it is no longer strictly part of the protocol.
This builds on #231 to add parameter subscription support to the Python SDK. The SDK takes care of all bookkeeping and this is purely informational for an implementer.
This also removes "parametersSubscribe" from the public SDK. Because the SDK manages the subscriptions itself, as long as the client advertises the "parameters" capability, the SDK will automatically include the former capability. This does mean that the server listener callbacks would be called regardless, but both languages provide default no-op implementations.