github.com/juju/juju@v0.0.0-20240327075706-a90865de2538/worker/lease/check.go (about)

     1  // Copyright 2015 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package lease
     5  
     6  import (
     7  	"github.com/juju/errors"
     8  
     9  	"github.com/juju/juju/core/lease"
    10  )
    11  
    12  // token implements lease.Token.
    13  type token struct {
    14  	leaseKey   lease.Key
    15  	holderName string
    16  	secretary  Secretary
    17  	checks     chan<- check
    18  	stop       <-chan struct{}
    19  }
    20  
    21  // Check is part of the lease.Token interface.
    22  func (t token) Check() error {
    23  	// This validation, which could be done at Token creation time, is deferred
    24  	// until this point for historical reasons. In particular, this code was
    25  	// extracted from a *leadership* implementation which has a LeadershipCheck
    26  	// method returning a token; if it returned an error as well it would seem
    27  	// to imply that the method implemented a check itself, rather than a check
    28  	// factory.
    29  	//
    30  	// Fixing that would be great but seems out of scope.
    31  	if err := t.secretary.CheckLease(t.leaseKey); err != nil {
    32  		return errors.Annotatef(err, "cannot check lease %q", t.leaseKey.Lease)
    33  	}
    34  	if err := t.secretary.CheckHolder(t.holderName); err != nil {
    35  		return errors.Annotatef(err, "cannot check holder %q", t.holderName)
    36  	}
    37  	return check{
    38  		leaseKey:   t.leaseKey,
    39  		holderName: t.holderName,
    40  		response:   make(chan error),
    41  		stop:       t.stop,
    42  	}.invoke(t.checks)
    43  }
    44  
    45  // check is used to deliver lease-check requests to a manager's loop
    46  // goroutine on behalf of a token (as returned by LeadershipCheck).
    47  type check struct {
    48  	leaseKey   lease.Key
    49  	holderName string
    50  	response   chan error
    51  	stop       <-chan struct{}
    52  }
    53  
    54  // invoke sends the check on the supplied channel and waits for an error
    55  // response.
    56  func (c check) invoke(ch chan<- check) error {
    57  	for {
    58  		select {
    59  		case <-c.stop:
    60  			return errStopped
    61  		case ch <- c:
    62  			ch = nil
    63  		case err := <-c.response:
    64  			return errors.Trace(err)
    65  		}
    66  	}
    67  }
    68  
    69  // respond notifies the originating invoke of completion status.
    70  func (c check) respond(err error) {
    71  	select {
    72  	case <-c.stop:
    73  	case c.response <- err:
    74  	}
    75  }