Improve wait during restart

We need to do this so that when a user asks docker to stop the container
and it is currently in the restart loop we don't want to have to wait
for the duration of the restart time increment before ack. the stop.

Signed-off-by: Michael Crosby <michael@docker.com>
This commit is contained in:
Michael Crosby 2014-08-11 15:00:55 -07:00
parent c4a00d549d
commit 972c894931
1 changed files with 41 additions and 9 deletions

View File

@ -35,6 +35,11 @@ type containerMonitor struct {
// either because docker or the user asked for the container to be stopped
shouldStop bool
// stopChan is used to signal to the monitor whenever there is a wait for the
// next restart so that the timeIncrement is not honored and the user is not
// left waiting for nothing to happen during this time
stopChan chan struct{}
// timeIncrement is the amount of time to wait between restarts
// this is in milliseconds
timeIncrement int
@ -45,6 +50,7 @@ func newContainerMonitor(container *Container, policy runconfig.RestartPolicy) *
container: container,
restartPolicy: policy,
timeIncrement: defaultTimeIncrement,
stopChan: make(chan struct{}, 1),
}
}
@ -52,7 +58,14 @@ func newContainerMonitor(container *Container, policy runconfig.RestartPolicy) *
// for exits the next time the process dies
func (m *containerMonitor) ExitOnNext() {
m.mux.Lock()
m.shouldStop = true
// we need to protect having a double close of the channel when stop is called
// twice or else we will get a panic
if !m.shouldStop {
m.shouldStop = true
close(m.stopChan)
}
m.mux.Unlock()
}
@ -87,7 +100,7 @@ func (m *containerMonitor) Start() error {
// reset the restart count
m.container.RestartCount = -1
for !m.shouldStop {
for {
m.container.RestartCount++
if err := m.container.startLoggingToDisk(); err != nil {
@ -109,22 +122,34 @@ func (m *containerMonitor) Start() error {
if m.shouldRestart(exitStatus) {
m.container.State.SetRestarting(exitStatus)
m.container.LogEvent("die")
m.resetContainer()
// sleep with a small time increment between each restart to help avoid issues cased by quickly
// restarting the container because of some types of errors ( networking cut out, etc... )
time.Sleep(time.Duration(m.timeIncrement) * time.Millisecond)
m.waitForNextRestart()
// we need to check this before reentering the loop because the waitForNextRestart could have
// been terminated by a request from a user
if m.shouldStop {
m.container.State.SetStopped(exitStatus)
return err
}
continue
}
m.container.State.SetStopped(exitStatus)
m.container.LogEvent("die")
m.resetContainer()
break
}
m.container.State.SetStopped(exitStatus)
m.resetContainer()
return err
}
@ -145,6 +170,15 @@ func (m *containerMonitor) resetMonitor(successful bool) {
}
}
// waitForNextRestart waits with the default time increment to restart the container unless
// a user or docker asks to container to be stopped
func (m *containerMonitor) waitForNextRestart() {
select {
case <-time.After(time.Duration(m.timeIncrement) * time.Millisecond):
case <-m.stopChan:
}
}
// shouldRestart checks the restart policy and applies the rules to determine if
// the container's process should be restarted
func (m *containerMonitor) shouldRestart(exitStatus int) bool {
@ -221,8 +255,6 @@ func (m *containerMonitor) resetContainer() {
container.stdin, container.stdinPipe = io.Pipe()
}
container.LogEvent("die")
c := container.command.Cmd
container.command.Cmd = exec.Cmd{