mirror of
https://github.com/moby/moby.git
synced 2022-11-09 12:21:53 -05:00
5b55747a52
While this code was likely called from a single thread before, we have now seen panics, indicating that it could be called in parallel. This change adds a mutex to protect opening and closing of the channel. There may be another root cause associated with this panic, such as something that led to the calling of this in parallel, as this code is old and we had seen this condition until recently. This fix is by no means a permanent fix. Typically, bugs like this indicate misplaced channel ownership. In idiomatic uses, the channel should have a particular "owner" that coordinates sending and closure. In this case, the owner of the channel is unclear, so it gets opened lazily. Synchronizing this access is a decent solution, but a refactor may yield better results. Signed-off-by: Stephen J Day <stephen.day@docker.com>
59 lines
1.3 KiB
Go
59 lines
1.3 KiB
Go
package container
|
|
|
|
import (
|
|
"sync"
|
|
|
|
"github.com/docker/docker/api/types"
|
|
"github.com/sirupsen/logrus"
|
|
)
|
|
|
|
// Health holds the current container health-check state
|
|
type Health struct {
|
|
types.Health
|
|
stop chan struct{} // Write struct{} to stop the monitor
|
|
mu sync.Mutex
|
|
}
|
|
|
|
// String returns a human-readable description of the health-check state
|
|
func (s *Health) String() string {
|
|
// This happens when the monitor has yet to be setup.
|
|
if s.Status == "" {
|
|
return types.Unhealthy
|
|
}
|
|
|
|
switch s.Status {
|
|
case types.Starting:
|
|
return "health: starting"
|
|
default: // Healthy and Unhealthy are clear on their own
|
|
return s.Status
|
|
}
|
|
}
|
|
|
|
// OpenMonitorChannel creates and returns a new monitor channel. If there
|
|
// already is one, it returns nil.
|
|
func (s *Health) OpenMonitorChannel() chan struct{} {
|
|
s.mu.Lock()
|
|
defer s.mu.Unlock()
|
|
|
|
if s.stop == nil {
|
|
logrus.Debug("OpenMonitorChannel")
|
|
s.stop = make(chan struct{})
|
|
return s.stop
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// CloseMonitorChannel closes any existing monitor channel.
|
|
func (s *Health) CloseMonitorChannel() {
|
|
s.mu.Lock()
|
|
defer s.mu.Unlock()
|
|
|
|
if s.stop != nil {
|
|
logrus.Debug("CloseMonitorChannel: waiting for probe to stop")
|
|
close(s.stop)
|
|
s.stop = nil
|
|
// unhealthy when the monitor has stopped for compatibility reasons
|
|
s.Status = types.Unhealthy
|
|
logrus.Debug("CloseMonitorChannel done")
|
|
}
|
|
}
|