github.com/juju/juju@v0.0.0-20240430160146-1752b71fcf00/core/watcher/interface.go (about)

     1  // Copyright 2015 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package watcher
     5  
     6  import (
     7  	"github.com/juju/worker/v3"
     8  )
     9  
    10  // CoreWatcher encodes some features of a watcher. The most obvious one:
    11  //
    12  //	Changes() <-chan <T>
    13  //
    14  // ...can't be expressed cleanly; and this is annoying because every such chan
    15  // needs to share common behaviours for the abstraction to be generally helpful.
    16  // The critical features of a Changes chan are as follows:
    17  //
    18  //   - The channel should never be closed.
    19  //
    20  //   - The channel should send a single baseline value, representing the change
    21  //     from a nil state; and subsequently send values representing deltas from
    22  //     whatever had previously been sent.
    23  //
    24  //   - The channel should really never be closed. Many existing watchers *do*
    25  //     close their channels when the watcher stops; this is harmful because it
    26  //     mixes lifetime-handling into change-handling at the cost of clarity (and
    27  //     in some cases correctness). So long as a watcher implements Worker, it
    28  //     can be safely managed with the worker/catacomb package; of course, all
    29  //     sensible clients will still check for closed channels (never trust a
    30  //     contract...) but can treat that scenario as a simple error.
    31  //
    32  //     (This rule only applies to watchers outside the API; watchers inside the
    33  //     API boundary need to close their changes channel so that the .Next()
    34  //     method implementations inside the API server (see apiserver/watcher.go)
    35  //     finish correctly.)
    36  //
    37  // To convert a state/watcher.Watcher to a CoreWatcher, ensure that the watcher
    38  // no longer closes its Changes() channel; and replace Stop() and Err() with the
    39  // usual worker boilerplate. Namely:
    40  //
    41  //	// Kill is part of the worker.Worker interface.
    42  //	func (w *watcher) Kill() {
    43  //	    w.tomb.Kill(nil)
    44  //	}
    45  //
    46  //	// Wait is part of the worker.Worker interface.
    47  //	func (w *watcher) Wait() error {
    48  //	    return w.tomb.Wait()
    49  //	}
    50  //
    51  // Tests using state/testing/{$Kind}WatcherC should be converted to use the
    52  // equivalents in watcher/watchertest.
    53  type CoreWatcher interface {
    54  	worker.Worker
    55  }