github.com/moby/docker@v26.1.3+incompatible/container/health.go (about)

     1  package container // import "github.com/docker/docker/container"
     2  
     3  import (
     4  	"context"
     5  	"sync"
     6  
     7  	"github.com/containerd/log"
     8  	"github.com/docker/docker/api/types"
     9  )
    10  
    11  // Health holds the current container health-check state
    12  type Health struct {
    13  	types.Health
    14  	stop chan struct{} // Write struct{} to stop the monitor
    15  	mu   sync.Mutex
    16  }
    17  
    18  // String returns a human-readable description of the health-check state
    19  func (s *Health) String() string {
    20  	status := s.Status()
    21  
    22  	switch status {
    23  	case types.Starting:
    24  		return "health: starting"
    25  	default: // Healthy and Unhealthy are clear on their own
    26  		return status
    27  	}
    28  }
    29  
    30  // Status returns the current health status.
    31  //
    32  // Note that this takes a lock and the value may change after being read.
    33  func (s *Health) Status() string {
    34  	s.mu.Lock()
    35  	defer s.mu.Unlock()
    36  
    37  	// This happens when the monitor has yet to be setup.
    38  	if s.Health.Status == "" {
    39  		return types.Unhealthy
    40  	}
    41  
    42  	return s.Health.Status
    43  }
    44  
    45  // SetStatus writes the current status to the underlying health structure,
    46  // obeying the locking semantics.
    47  //
    48  // Status may be set directly if another lock is used.
    49  func (s *Health) SetStatus(new string) {
    50  	s.mu.Lock()
    51  	defer s.mu.Unlock()
    52  
    53  	s.Health.Status = new
    54  }
    55  
    56  // OpenMonitorChannel creates and returns a new monitor channel. If there
    57  // already is one, it returns nil.
    58  func (s *Health) OpenMonitorChannel() chan struct{} {
    59  	s.mu.Lock()
    60  	defer s.mu.Unlock()
    61  
    62  	if s.stop == nil {
    63  		log.G(context.TODO()).Debug("OpenMonitorChannel")
    64  		s.stop = make(chan struct{})
    65  		return s.stop
    66  	}
    67  	return nil
    68  }
    69  
    70  // CloseMonitorChannel closes any existing monitor channel.
    71  func (s *Health) CloseMonitorChannel() {
    72  	s.mu.Lock()
    73  	defer s.mu.Unlock()
    74  
    75  	if s.stop != nil {
    76  		log.G(context.TODO()).Debug("CloseMonitorChannel: waiting for probe to stop")
    77  		close(s.stop)
    78  		s.stop = nil
    79  		// unhealthy when the monitor has stopped for compatibility reasons
    80  		s.Health.Status = types.Unhealthy
    81  		log.G(context.TODO()).Debug("CloseMonitorChannel done")
    82  	}
    83  }