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

feat(server): add TowerService::on_session_close #1284

Merged
merged 4 commits into from
Feb 6, 2024
Merged

Conversation

niklasad1
Copy link
Member

This PR adds another builder option to the TowerServiceBuilder get subscribe to when the connection/session has closed because when TowerService::call resolves it means that HTTP call has been finished but doesn't mean that WebSocket connection has closed.

Thus, to know that we need another future sadly but worth the effort because otherwise the only way for folks it use the low-level API.

Resolves #1264

@niklasad1 niklasad1 requested a review from a team as a code owner February 5, 2024 18:13
@niklasad1 niklasad1 changed the title add TowerService build and notify on session close feat(server): add TowerServiceBuilder::build_and_notify_on_session_close Feb 5, 2024
@niklasad1 niklasad1 changed the title feat(server): add TowerServiceBuilder::build_and_notify_on_session_close feat(server): add TowerService::on_session_close Feb 6, 2024
pub(crate) fn session_close() -> (SessionClose, SessionClosedFuture) {
// SessionClosedFuture is closed after one message has been recevied
// and max one message is handled then it's closed.
let (tx, rx) = tokio::sync::broadcast::channel(1);
Copy link
Collaborator

Choose a reason for hiding this comment

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

Tokio's API is a bit strange I feel here; you can only create a pair, but then you can also call subscribe() on a tx to get another rx!

Copy link
Member Author

Choose a reason for hiding this comment

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

Yepp, I think the implementation is quite complicated/clever as the Receiver is not clone.

I think it just clone the message(s) to other receivers which is probably quite nice to avoid having a separate state for each receiver

n.closed()
} else {
let (session_close, fut) = session_close();
self.rpc_middleware.on_session_close = Some(session_close);
Copy link
Collaborator

@jsdw jsdw Feb 6, 2024

Choose a reason for hiding this comment

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

Is there any likelihood of a race where the session is closing already or something, and only then you cann on_session_closed and then get back a future that's never called or something?

I don't think it really matters though because why would you subscribe to this so late on

Copy link
Member Author

Choose a reason for hiding this comment

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

Added some extra docs on it, it's possible.

Also it's a little bit weird that TowerService::call can be used several times, in practice I don't think that's the case but a footgun.

That on_session_close on works the subsequent TowerService::call as it does Option::take

Copy link
Collaborator

@jsdw jsdw left a comment

Choose a reason for hiding this comment

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

LGTM I think! Is there a way to test this?

fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
match self.0.poll_next_unpin(cx) {
Poll::Pending => Poll::Pending,
// A message is only sent when
Copy link
Contributor

Choose a reason for hiding this comment

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

nit: when the connection is closed


impl SessionClose {
pub(crate) fn close(self) {
let _ = self.0.send(());
Copy link
Contributor

Choose a reason for hiding this comment

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

nit: Could this be implemented also on Drop? And if we already called close() we'd do nothing on drop, otherwise, we'll call self.0.send()?

Copy link
Member Author

Choose a reason for hiding this comment

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

I skipped it because I'm scared of that as the tower stuff requires Clone and I'm not sure whether something is dropped at some point.

Copy link
Contributor

Choose a reason for hiding this comment

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

Makes sense, thanks!

@niklasad1 niklasad1 merged commit 8470f2b into master Feb 6, 2024
11 checks passed
@niklasad1 niklasad1 deleted the na-fix-1264 branch February 6, 2024 13:39
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.

jsonrpsee TowerService: how to detect when a WebSocket connection is closed.
3 participants