| 294 | } |
| 295 | |
| 296 | func (s *userServer) runLoop() { |
| 297 | maxSleepTime := 30 * time.Second |
| 298 | consecutiveFailures := float64(0) |
| 299 | var timeOfLastFailure time.Time |
| 300 | for { |
| 301 | s.mu.RLock() |
| 302 | closed := s.closed |
| 303 | s.mu.RUnlock() |
| 304 | if closed { |
| 305 | return |
| 306 | } |
| 307 | |
| 308 | err := s.run() |
| 309 | now := time.Now() |
| 310 | timeSinceLastFailure := now.Sub(timeOfLastFailure) |
| 311 | timeOfLastFailure = now |
| 312 | if timeSinceLastFailure < maxSleepTime { |
| 313 | consecutiveFailures++ |
| 314 | } else { |
| 315 | consecutiveFailures = 1 |
| 316 | } |
| 317 | sleepTime := time.Duration(math.Pow(2, consecutiveFailures)) * time.Millisecond |
| 318 | if sleepTime > maxSleepTime { |
| 319 | sleepTime = maxSleepTime |
| 320 | } |
| 321 | s.logf("user server % v stopped with error %v, will try again in %v", s.executable, err, sleepTime) |
| 322 | time.Sleep(sleepTime) |
| 323 | } |
| 324 | } |
| 325 | |
| 326 | // Run runs the user server using the configured executable. This function only |
| 327 | // works on UNIX systems, but those are the only ones on which we use |