From dcf785677fbb8d9ada7a63e7d088271236aae697 Mon Sep 17 00:00:00 2001 From: Z Date: Fri, 7 Aug 2020 01:21:09 +0800 Subject: [PATCH] Fix: file-watcher bugs (#1897) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Fix: file-watcher bugs * Update watcher_linux.go Co-authored-by: 杨铭哲 Co-authored-by: Asim Aslam --- config/source/file/file.go | 1 + config/source/file/watcher.go | 42 +++++++++++++++---------- config/source/file/watcher_linux.go | 49 +++++++++++++++++------------ 3 files changed, 56 insertions(+), 36 deletions(-) diff --git a/config/source/file/file.go b/config/source/file/file.go index 17067447..6b42fd19 100644 --- a/config/source/file/file.go +++ b/config/source/file/file.go @@ -10,6 +10,7 @@ import ( type file struct { path string + data []byte opts source.Options } diff --git a/config/source/file/watcher.go b/config/source/file/watcher.go index 39c20a71..953050b5 100644 --- a/config/source/file/watcher.go +++ b/config/source/file/watcher.go @@ -39,26 +39,36 @@ func (w *watcher) Next() (*source.ChangeSet, error) { default: } - // try get the event - select { - case event, _ := <-w.fw.Events: - if event.Op == fsnotify.Rename { - // check existence of file, and add watch again - _, err := os.Stat(event.Name) - if err == nil || os.IsExist(err) { - w.fw.Add(event.Name) + for { + // try get the event + select { + case event, _ := <-w.fw.Events: + if event.Op == fsnotify.Rename { + // check existence of file, and add watch again + _, err := os.Stat(event.Name) + if err == nil || os.IsExist(err) { + w.fw.Add(event.Name) + } } - } - c, err := w.f.Read() - if err != nil { + // ARCH: Darwin Kernel Version 18.7.0 + // ioutil.WriteFile truncates it before writing, but the problem is that + // you will receive two events(fsnotify.Chmod and fsnotify.Write). + // We can solve this problem by ignoring fsnotify.Chmod event. + if event.Op&fsnotify.Write != fsnotify.Write { + continue + } + + c, err := w.f.Read() + if err != nil { + return nil, err + } + return c, nil + case err := <-w.fw.Errors: return nil, err + case <-w.exit: + return nil, source.ErrWatcherStopped } - return c, nil - case err := <-w.fw.Errors: - return nil, err - case <-w.exit: - return nil, source.ErrWatcherStopped } } diff --git a/config/source/file/watcher_linux.go b/config/source/file/watcher_linux.go index b8957bf9..4f8be6da 100644 --- a/config/source/file/watcher_linux.go +++ b/config/source/file/watcher_linux.go @@ -4,6 +4,7 @@ package file import ( "os" + "reflect" "github.com/fsnotify/fsnotify" "github.com/micro/go-micro/v3/config/source" @@ -39,30 +40,38 @@ func (w *watcher) Next() (*source.ChangeSet, error) { default: } - // try get the event - select { - case event, _ := <-w.fw.Events: - if event.Op == fsnotify.Rename { - // check existence of file, and add watch again - _, err := os.Stat(event.Name) - if err == nil || os.IsExist(err) { - w.fw.Add(event.Name) + for { + // try get the event + select { + case event, _ := <-w.fw.Events: + if event.Op == fsnotify.Rename { + // check existence of file, and add watch again + _, err := os.Stat(event.Name) + if err == nil || os.IsExist(err) { + w.fw.Add(event.Name) + } } - } - c, err := w.f.Read() - if err != nil { + c, err := w.f.Read() + if err != nil { + return nil, err + } + + // ARCH: Linux centos-7.shared 3.10.0-693.5.2.el7.x86_64 + // Sometimes, ioutil.WriteFile triggers multiple fsnotify.Write events, which may be a bug. + + // Detect if the file has changed + if reflect.DeepEqual(c.Data, w.f.data) { + continue + } + w.f.data = c.Data + + return c, nil + case err := <-w.fw.Errors: return nil, err + case <-w.exit: + return nil, source.ErrWatcherStopped } - - // add path again for the event bug of fsnotify - w.fw.Add(w.f.path) - - return c, nil - case err := <-w.fw.Errors: - return nil, err - case <-w.exit: - return nil, source.ErrWatcherStopped } }