monitorWatch starts the filesystem watching and retries every minute on failure. It should not be used except in startWatch.
(ctx context.Context)
| 1054 | // monitorWatch starts the filesystem watching and retries every minute on failure. |
| 1055 | // It should not be used except in startWatch. |
| 1056 | func (f *folder) monitorWatch(ctx context.Context) { |
| 1057 | failTimer := time.NewTimer(0) |
| 1058 | aggrCtx, aggrCancel := context.WithCancel(ctx) |
| 1059 | var err error |
| 1060 | var eventChan <-chan fs.Event |
| 1061 | var errChan <-chan error |
| 1062 | warnedOutside := false |
| 1063 | var lastWatch time.Time |
| 1064 | pause := time.Minute |
| 1065 | // Subscribe to folder summaries only on kqueue systems, to warn about potential high resource usage |
| 1066 | var summarySub events.Subscription |
| 1067 | var summaryChan <-chan events.Event |
| 1068 | if fs.WatchKqueue && !f.warnedKqueue { |
| 1069 | summarySub = f.evLogger.Subscribe(events.FolderSummary) |
| 1070 | summaryChan = summarySub.C() |
| 1071 | } |
| 1072 | defer func() { |
| 1073 | aggrCancel() // aggrCancel might e re-assigned -> call within closure |
| 1074 | if summaryChan != nil { |
| 1075 | summarySub.Unsubscribe() |
| 1076 | } |
| 1077 | }() |
| 1078 | for { |
| 1079 | select { |
| 1080 | case <-failTimer.C: |
| 1081 | eventChan, errChan, err = f.mtimefs.Watch(".", f.ignores, ctx, f.IgnorePerms) |
| 1082 | // We do this once per minute initially increased to |
| 1083 | // max one hour in case of repeat failures. |
| 1084 | f.scanOnWatchErr() |
| 1085 | f.setWatchError(err, pause) |
| 1086 | if err != nil { |
| 1087 | failTimer.Reset(pause) |
| 1088 | if pause < 60*time.Minute { |
| 1089 | pause *= 2 |
| 1090 | } |
| 1091 | continue |
| 1092 | } |
| 1093 | lastWatch = time.Now() |
| 1094 | watchaggregator.Aggregate(aggrCtx, eventChan, f.watchChan, f.FolderConfiguration, f.model.cfg, f.evLogger) |
| 1095 | f.sl.DebugContext(ctx, "Started filesystem watcher") |
| 1096 | case err = <-errChan: |
| 1097 | var next time.Duration |
| 1098 | if dur := time.Since(lastWatch); dur > pause { |
| 1099 | pause = time.Minute |
| 1100 | next = 0 |
| 1101 | } else { |
| 1102 | next = pause - dur |
| 1103 | if pause < 60*time.Minute { |
| 1104 | pause *= 2 |
| 1105 | } |
| 1106 | } |
| 1107 | failTimer.Reset(next) |
| 1108 | f.setWatchError(err, next) |
| 1109 | // This error was previously a panic and should never occur, so generate |
| 1110 | // a warning, but don't do it repetitively. |
| 1111 | var errOutside *fs.WatchEventOutsideRootError |
| 1112 | if errors.As(err, &errOutside) { |
| 1113 | if !warnedOutside { |
no test coverage detected