Forráskód Böngészése

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>
Michael Crosby 11 éve
szülő
commit
972c894931
1 módosított fájl, 41 hozzáadás és 9 törlés
  1. 41 9
      daemon/monitor.go

+ 41 - 9
daemon/monitor.go

@@ -35,6 +35,11 @@ type containerMonitor struct {
 	// either because docker or the user asked for the container to be stopped
 	// either because docker or the user asked for the container to be stopped
 	shouldStop bool
 	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
 	// timeIncrement is the amount of time to wait between restarts
 	// this is in milliseconds
 	// this is in milliseconds
 	timeIncrement int
 	timeIncrement int
@@ -45,6 +50,7 @@ func newContainerMonitor(container *Container, policy runconfig.RestartPolicy) *
 		container:     container,
 		container:     container,
 		restartPolicy: policy,
 		restartPolicy: policy,
 		timeIncrement: defaultTimeIncrement,
 		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
 // for exits the next time the process dies
 func (m *containerMonitor) ExitOnNext() {
 func (m *containerMonitor) ExitOnNext() {
 	m.mux.Lock()
 	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()
 	m.mux.Unlock()
 }
 }
 
 
@@ -87,7 +100,7 @@ func (m *containerMonitor) Start() error {
 	// reset the restart count
 	// reset the restart count
 	m.container.RestartCount = -1
 	m.container.RestartCount = -1
 
 
-	for !m.shouldStop {
+	for {
 		m.container.RestartCount++
 		m.container.RestartCount++
 
 
 		if err := m.container.startLoggingToDisk(); err != nil {
 		if err := m.container.startLoggingToDisk(); err != nil {
@@ -109,21 +122,33 @@ func (m *containerMonitor) Start() error {
 		if m.shouldRestart(exitStatus) {
 		if m.shouldRestart(exitStatus) {
 			m.container.State.SetRestarting(exitStatus)
 			m.container.State.SetRestarting(exitStatus)
 
 
+			m.container.LogEvent("die")
+
 			m.resetContainer()
 			m.resetContainer()
 
 
 			// sleep with a small time increment between each restart to help avoid issues cased by quickly
 			// 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... )
 			// 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
 			continue
 		}
 		}
 
 
-		break
-	}
+		m.container.State.SetStopped(exitStatus)
+
+		m.container.LogEvent("die")
 
 
-	m.container.State.SetStopped(exitStatus)
+		m.resetContainer()
 
 
-	m.resetContainer()
+		break
+	}
 
 
 	return err
 	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
 // shouldRestart checks the restart policy and applies the rules to determine if
 // the container's process should be restarted
 // the container's process should be restarted
 func (m *containerMonitor) shouldRestart(exitStatus int) bool {
 func (m *containerMonitor) shouldRestart(exitStatus int) bool {
@@ -221,8 +255,6 @@ func (m *containerMonitor) resetContainer() {
 		container.stdin, container.stdinPipe = io.Pipe()
 		container.stdin, container.stdinPipe = io.Pipe()
 	}
 	}
 
 
-	container.LogEvent("die")
-
 	c := container.command.Cmd
 	c := container.command.Cmd
 
 
 	container.command.Cmd = exec.Cmd{
 	container.command.Cmd = exec.Cmd{