lib/model: Delay watch setup on errors (fixes #5731) (#6544)

This commit is contained in:
Simon Frei 2020-04-17 17:43:42 +02:00 committed by GitHub
parent 171b8139ab
commit 49798552f2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -634,7 +634,7 @@ func (f *folder) stopWatch() {
f.watchMut.Lock() f.watchMut.Lock()
f.watchCancel() f.watchCancel()
f.watchMut.Unlock() f.watchMut.Unlock()
f.setWatchError(nil) f.setWatchError(nil, 0)
} }
// scheduleWatchRestart makes sure watching is restarted from the main for loop // scheduleWatchRestart makes sure watching is restarted from the main for loop
@ -677,22 +677,39 @@ func (f *folder) monitorWatch(ctx context.Context) {
var eventChan <-chan fs.Event var eventChan <-chan fs.Event
var errChan <-chan error var errChan <-chan error
warnedOutside := false warnedOutside := false
var lastWatch time.Time
pause := time.Minute
for { for {
select { select {
case <-failTimer.C: case <-failTimer.C:
eventChan, errChan, err = f.Filesystem().Watch(".", f.ignores, ctx, f.IgnorePerms) eventChan, errChan, err = f.Filesystem().Watch(".", f.ignores, ctx, f.IgnorePerms)
// We do this at most once per minute which is the // We do this once per minute initially increased to
// default rescan time without watcher. // max one hour in case of repeat failures.
f.scanOnWatchErr() f.scanOnWatchErr()
f.setWatchError(err) f.setWatchError(err, pause)
if err != nil { if err != nil {
failTimer.Reset(time.Minute) failTimer.Reset(pause)
if pause < 60*time.Minute {
pause *= 2
}
continue continue
} }
lastWatch = time.Now()
watchaggregator.Aggregate(aggrCtx, eventChan, f.watchChan, f.FolderConfiguration, f.model.cfg, f.evLogger) watchaggregator.Aggregate(aggrCtx, eventChan, f.watchChan, f.FolderConfiguration, f.model.cfg, f.evLogger)
l.Debugln("Started filesystem watcher for folder", f.Description()) l.Debugln("Started filesystem watcher for folder", f.Description())
case err = <-errChan: case err = <-errChan:
f.setWatchError(err) var next time.Duration
if dur := time.Since(lastWatch); dur > pause {
pause = time.Minute
next = 0
} else {
next = pause - dur
if pause < 60*time.Minute {
pause *= 2
}
}
failTimer.Reset(next)
f.setWatchError(err, next)
// This error was previously a panic and should never occur, so generate // This error was previously a panic and should never occur, so generate
// a warning, but don't do it repetitively. // a warning, but don't do it repetitively.
if !warnedOutside { if !warnedOutside {
@ -704,7 +721,6 @@ func (f *folder) monitorWatch(ctx context.Context) {
aggrCancel() aggrCancel()
errChan = nil errChan = nil
aggrCtx, aggrCancel = context.WithCancel(ctx) aggrCtx, aggrCancel = context.WithCancel(ctx)
failTimer.Reset(time.Minute)
case <-ctx.Done(): case <-ctx.Done():
return return
} }
@ -713,7 +729,7 @@ func (f *folder) monitorWatch(ctx context.Context) {
// setWatchError sets the current error state of the watch and should be called // setWatchError sets the current error state of the watch and should be called
// regardless of whether err is nil or not. // regardless of whether err is nil or not.
func (f *folder) setWatchError(err error) { func (f *folder) setWatchError(err error, nextTryIn time.Duration) {
f.watchMut.Lock() f.watchMut.Lock()
prevErr := f.watchErr prevErr := f.watchErr
f.watchErr = err f.watchErr = err
@ -733,7 +749,7 @@ func (f *folder) setWatchError(err error) {
if err == nil { if err == nil {
return return
} }
msg := fmt.Sprintf("Error while trying to start filesystem watcher for folder %s, trying again in 1min: %v", f.Description(), err) msg := fmt.Sprintf("Error while trying to start filesystem watcher for folder %s, trying again in %v: %v", f.Description(), nextTryIn, err)
if prevErr != err { if prevErr != err {
l.Infof(msg) l.Infof(msg)
return return