From 0790f66627cd56135874a567d2277da604d69970 Mon Sep 17 00:00:00 2001 From: Deluan Date: Thu, 12 Mar 2026 17:07:34 -0400 Subject: [PATCH] fix(scanner): increase watcher channel buffers to prevent dropped filesystem events When files were moved between libraries, the small channel buffers (size 1) throughout the watcher pipeline caused backpressure that led to dropped filesystem events. This meant only some of the affected folders were scanned, preventing cross-library move detection from working correctly. Increase all watcher channel buffers to 500 and switch to blocking sends to ensure no filesystem events are silently dropped. --- core/storage/local/watcher.go | 4 ++-- scanner/watcher.go | 10 +++------- scanner/watcher_test.go | 2 +- 3 files changed, 6 insertions(+), 10 deletions(-) diff --git a/core/storage/local/watcher.go b/core/storage/local/watcher.go index e2418f4c..1b8a4e0c 100644 --- a/core/storage/local/watcher.go +++ b/core/storage/local/watcher.go @@ -17,8 +17,8 @@ func (s *localStorage) Start(ctx context.Context) (<-chan string, error) { if !s.watching.CompareAndSwap(false, true) { return nil, errors.New("watcher already started") } - input := make(chan notify.EventInfo, 1) - output := make(chan string, 1) + input := make(chan notify.EventInfo, 500) + output := make(chan string, 500) started := make(chan struct{}) go func() { diff --git a/scanner/watcher.go b/scanner/watcher.go index 62fcc934..376db910 100644 --- a/scanner/watcher.go +++ b/scanner/watcher.go @@ -48,7 +48,7 @@ func GetWatcher(ds model.DataStore, s model.Scanner) Watcher { ds: ds, scanner: s, triggerWait: conf.Server.Scanner.WatcherWait, - watcherNotify: make(chan scanNotification, 1), + watcherNotify: make(chan scanNotification, 500), libraryWatchers: make(map[int]*libraryWatcherInstance), } }) @@ -272,12 +272,8 @@ func (w *watcher) processLibraryEvents(ctx context.Context, lib *model.Library, continue } - // Notify the main watcher of changes - select { - case w.watcherNotify <- scanNotification{Library: lib, FolderPath: folderPath}: - default: - // Channel is full, notification already pending - } + // Notify the main watcher of changes. This will trigger a scan after the debounce period. + w.watcherNotify <- scanNotification{Library: lib, FolderPath: folderPath} } } } diff --git a/scanner/watcher_test.go b/scanner/watcher_test.go index 7a431d5a..e1600db3 100644 --- a/scanner/watcher_test.go +++ b/scanner/watcher_test.go @@ -27,7 +27,7 @@ var _ = Describe("Watcher", func() { DeferCleanup(configtest.SetupConfig()) conf.Server.Scanner.WatcherWait = 50 * time.Millisecond // Short wait for tests - ctx, cancel = context.WithCancel(context.Background()) + ctx, cancel = context.WithCancel(GinkgoT().Context()) DeferCleanup(cancel) lib = &model.Library{