Merge pull request #680 from printfcoder/master

fix file watcher event bug on Linux
This commit is contained in:
Asim Aslam 2019-08-19 08:34:21 +01:00 committed by GitHub
commit 718ae42808
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 134 additions and 0 deletions

View File

@ -1,6 +1,7 @@
package config
import (
"encoding/json"
"fmt"
"os"
"path/filepath"
@ -8,10 +9,15 @@ import (
"testing"
"time"
"github.com/google/uuid"
"github.com/micro/go-micro/config/source/env"
"github.com/micro/go-micro/config/source/file"
)
var (
sep = string(os.PathSeparator)
)
func createFileForIssue18(t *testing.T, content string) *os.File {
data := []byte(content)
path := filepath.Join(os.TempDir(), fmt.Sprintf("file.%d", time.Now().UnixNano()))
@ -116,3 +122,57 @@ func TestConfigMerge(t *testing.T) {
actualHost)
}
}
func TestFileChange(t *testing.T) {
// create a temp file
fileName := uuid.New().String() + "testWatcher.json"
f, err := os.OpenFile("."+sep+fileName, os.O_WRONLY|os.O_CREATE, 0666)
if err != nil {
t.Error(err)
}
defer f.Close()
defer os.Remove("." + sep + fileName)
// load the file
if err := Load(file.NewSource(
file.WithPath("." + sep + fileName),
)); err != nil {
t.Error(err)
}
// watch changes
watcher, err := Watch()
if err != nil {
t.Error(err)
}
changeTimes := 0
go func() {
for {
v, err := watcher.Next()
if err != nil {
t.Error(err)
return
}
changeTimes++
t.Logf("file change%s", string(v.Bytes()))
}
}()
content := map[int]string{}
// change the file
for i := 0; i < 5; i++ {
content[i] = time.Now().String()
bytes, _ := json.Marshal(content)
f.Truncate(0)
f.Seek(0, 0)
if _, err := f.Write(bytes); err != nil {
t.Error(err)
}
time.Sleep(time.Second)
}
if changeTimes != 4 {
t.Error(fmt.Errorf("watcher error: change times %d is not enough", changeTimes))
}
}

View File

@ -1,3 +1,5 @@
//+build !linux
package file
import (

View File

@ -0,0 +1,72 @@
//+build linux
package file
import (
"errors"
"os"
"github.com/fsnotify/fsnotify"
"github.com/micro/go-micro/config/source"
)
type watcher struct {
f *file
fw *fsnotify.Watcher
exit chan bool
}
func newWatcher(f *file) (source.Watcher, error) {
fw, err := fsnotify.NewWatcher()
if err != nil {
return nil, err
}
fw.Add(f.path)
return &watcher{
f: f,
fw: fw,
exit: make(chan bool),
}, nil
}
func (w *watcher) Next() (*source.ChangeSet, error) {
// is it closed?
select {
case <-w.exit:
return nil, errors.New("watcher stopped")
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)
}
}
c, err := w.f.Read()
if err != nil {
return nil, err
}
// 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, errors.New("watcher stopped")
}
}
func (w *watcher) Stop() error {
return w.fw.Close()
}