Skip to content

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

Merged

Conversation

bryfox
Copy link
Contributor

@bryfox bryfox commented Feb 24, 2025

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.

Copy link

linear bot commented Feb 24, 2025

@bryfox bryfox requested review from gasmith and eloff February 24, 2025 21:58
@bryfox
Copy link
Contributor Author

bryfox commented Feb 24, 2025

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.

@eloff
Copy link
Contributor

eloff commented Feb 24, 2025

This builds on #231 to add parameter subscription support to the Python SDK.

As I understand it, the SDK takes care of all bookkeeping and this is purely informational for an implementer.

For discussion

As-is, the callback does not seem particularly useful: as a caller, I'm given a list of parameter names and no other information. I think we could consider either (a) including a client ID in the callback, or (b) removing these callbacks entirely. I think (a) makes the callback potentially meaningful, but risks a user thinking they need to implement bookkeeping.

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.

In any case, I think we should also consider automatically advertising the ParametersSubscribe support if the user specifies the Parameters capability, since the SDK itself is capable of managing the subscription. In other words, we only surface the Parameters capability to users of the SDK, and deal with the other one internally.

Yeah, that makes sense to me.

@eloff
Copy link
Contributor

eloff commented Feb 24, 2025

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.

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.

Copy link
Contributor

@eloff eloff left a 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.

Base automatically changed from bryan/fg-10186-python-allow-user-to-set-parameters to main February 25, 2025 14:44
@bryfox bryfox force-pushed the bryan/fg-10183-python-add-parameter-callbacks-to-listener branch from ed96314 to 1d7d287 Compare February 25, 2025 14:59
@bryfox
Copy link
Contributor Author

bryfox commented Feb 25, 2025

So these callbacks notify when a parameter is first subscribed to our last unsubscribed to.

OK, that makes sense, and I agree with omitting the client ID; thank you

The idea is it lets you know when you need to start being concerned about a parameter and when you can stop.

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 getParameters .

@bryfox
Copy link
Contributor Author

bryfox commented Feb 25, 2025

I'm not sure the ws-protocol spec lets us skip the response though? I wonder what we should do here.

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.

@bryfox
Copy link
Contributor Author

bryfox commented Feb 25, 2025

This looks good, but could use some python tests or be added to the params example so it has some usage.

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.

@bryfox bryfox requested a review from eloff February 25, 2025 17:22
Copy link
Contributor

@gasmith gasmith left a 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)]
Copy link
Contributor

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.

Comment on lines +151 to +158
let result: PyResult<()> = Python::with_gil(|py| {
let args = (param_names,);
self.listener
.bind(py)
.call_method("on_parameters_unsubscribe", args, None)?;

Ok(())
});
Copy link
Contributor

@gasmith gasmith Feb 25, 2025

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)]
Copy link
Contributor

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 {
Copy link
Contributor

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.

@bryfox bryfox merged commit be31a49 into main Feb 25, 2025
29 checks passed
@bryfox bryfox deleted the bryan/fg-10183-python-add-parameter-callbacks-to-listener branch February 25, 2025 20:24
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

Successfully merging this pull request may close these issues.

3 participants