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

Permit sending into a watch::Sender without active Receivers #4165

Closed
thombles opened this issue Oct 11, 2021 · 1 comment · Fixed by #4195
Closed

Permit sending into a watch::Sender without active Receivers #4165

thombles opened this issue Oct 11, 2021 · 1 comment · Fixed by #4195
Labels
A-tokio Area: The main tokio crate C-feature-request Category: A feature request. M-sync Module: tokio/sync

Comments

@thombles
Copy link

Is your feature request related to a problem? Please describe.

Relates to #3757. The newly-public subscribe() function works very nicely for allowing consumers to monitor a value which is being maintained elsewhere. (Thank you!) There is a rough edge, however, that it can "recover" from a receiver-less situation automatically, but you are unable to introduce new values in the meantime.

    let (tx, _) = watch::channel(1usize);
    assert_eq!(*tx.borrow(), 1);
    
    let r1 = tx.subscribe();
    assert_eq!(*r1.borrow(), 1);
    drop(r1);
    
    let res = tx.send(2);
    assert!(res.is_err());

    let r2 = tx.subscribe();
    // wouldn't it be nice if this was `2`?
    assert_eq!(*r2.borrow(), 1);

(Playground)

The code sending new values into the channel is probably not closely aware of the coming-and-going of subscribers. In a use-case where it is expected that the receiver count will sometimes drop to 0, it complicates the sending code that you will get an Err result at arbitrary times.

Describe the solution you'd like

Sending into a watch channel with no receivers will succeed, becoming the most-recent (already seen) value for any new subscribers.

Describe alternatives you've considered

It is possible to work around this, provided the code that is issuing calls to send() and the code that is creating new subscribers both share exclusive/mutable access to the watch::Sender.

    let (tx, _) = watch::channel(1usize);
    let sender_mtx = std::sync::Mutex::new(tx);
    
    {
        let mut s = sender_mtx.lock().unwrap();
        if s.send(2).is_err() {
            *s = watch::channel(2).0;
        }
    }
    
    let r = sender_mtx.lock().unwrap().subscribe();
    assert_eq!(*r.borrow(), 2);

Additional context

This request feels a little selfish—hypothetically I can think of use cases where you really do want your sender to error when nobody is interested in the value any more. I don't have any of those use cases today. I'm not sure if these two different use cases should even be served by the same type.

I'm not going to strongly advocate for the solution presented above. Mostly I want to highlight that it feels slightly awkward right now, and maybe there is a better way to iterate on it?

@thombles thombles added A-tokio Area: The main tokio crate C-feature-request Category: A feature request. labels Oct 11, 2021
@Darksonn Darksonn added the M-sync Module: tokio/sync label Oct 11, 2021
@Darksonn
Copy link
Contributor

Well, unfortunately this isn't really something we can change now because it's a breaking change. We could in principle introduce a new separate send method.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-tokio Area: The main tokio crate C-feature-request Category: A feature request. M-sync Module: tokio/sync
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants