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

WIP: Expose a handle to cleanly cancel a reflector #6602

Closed
wants to merge 1 commit into from

Conversation

bprashanth
Copy link
Contributor

@lavalamp need opinions before I move on.

This is the first step in teaching kubectl stop to watch status.replicas of an rc, the unittest has a fairly complete example of how I plan to use reflector cancellation in creating an edge trigger watcher (watches a resource for a single value, in this case status.replicas=0).

This PR exposes a CancellationController capable of dictating when a reflector should cleanup and unwind the listAndWatch stack. The cancellation controller uses a single channel as a conduit for cancellation signals. The signal might take the form of either a timeout (resync period of the reflector) or a stop event sent from some client of the reflector that no longer cares about what it's watching (all the resizers in kubectl).

For this to WAI we also need to send a stop signal to reflector.RunUnti, or the reflector will just retry. This is how we'd get the stop signal to stop watching, while the resync timeout will not stop watching.

Also fixes #6488

@lavalamp
Copy link
Member

lavalamp commented Apr 8, 2015

This is pretty complicated, it's not clear to me what problem you're solving. Please see my pending #6546. I think once that is in you should be able to easily wait on a condition with something like the below (can package this up into a few lines of code for easy usage multiple places).

    outputChan := make(chan interface{})
    stopCh := make(chan struct{})
    checkFunc := func(obj interface{}) {
        if /* obj meets condition */ {
            close(stopCh)
            outputChan <- obj
        }
    }

    _, controller := framework.NewInformer(
        c.createAssignedPodLW(),
        &api.Pod{},
        time.Second*30,
        framework.ResourceEventHandlerFuncs{
            AddFunc: checkFunc,
            UpdateFunc: checkFunc,
        },
    )
    go controller.Run(stopCh)
    obj := <- outputChan


// Stopping the watcher should be idempotent and if we return from this function there's no way
// we're coming back in with the same watch interface.
defer w.Stop()
Copy link
Member

Choose a reason for hiding this comment

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

This line's change is good :)

But otherwise, I think I pretty strongly prefer just plumbing two channels down to watchHandler. 'exitWatch' can be renamed to resyncChan and we can add a 'stopCh'. Resyncing and stopping are just two different things. Also--go design style--if you're using both mutexes and channels, something is wrong. :)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Agree about the refactor, don't completely agree about the difference between resync and stop. In general I feel like they're different, but the way listAndWatch behaves today, they feel essentially the same. A resync is a cancel unless called from withing a while loop.

@bprashanth
Copy link
Contributor Author

feedback received, will iterate in another pr that addresses both RunUntil stopping and the leaked channel

@bprashanth bprashanth closed this Apr 9, 2015
@bprashanth bprashanth deleted the edge_watcher branch October 26, 2015 00:40
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.

Reflector shouldn't leak io watcher on error events
3 participants