fix file watcher event bug on Linux
the watcher can not normally get events of file changes on linux. it just can get the first two changes.
This commit is contained in:
parent
9c820445a4
commit
2413cbcd80
@ -1,6 +1,7 @@
|
|||||||
package config
|
package config
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
@ -8,10 +9,15 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/google/uuid"
|
||||||
"github.com/micro/go-micro/config/source/env"
|
"github.com/micro/go-micro/config/source/env"
|
||||||
"github.com/micro/go-micro/config/source/file"
|
"github.com/micro/go-micro/config/source/file"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
sep = string(os.PathSeparator)
|
||||||
|
)
|
||||||
|
|
||||||
func createFileForIssue18(t *testing.T, content string) *os.File {
|
func createFileForIssue18(t *testing.T, content string) *os.File {
|
||||||
data := []byte(content)
|
data := []byte(content)
|
||||||
path := filepath.Join(os.TempDir(), fmt.Sprintf("file.%d", time.Now().UnixNano()))
|
path := filepath.Join(os.TempDir(), fmt.Sprintf("file.%d", time.Now().UnixNano()))
|
||||||
@ -116,3 +122,57 @@ func TestConfigMerge(t *testing.T) {
|
|||||||
actualHost)
|
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))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
//+build !linux
|
||||||
|
|
||||||
package file
|
package file
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
72
config/source/file/watcher_linux.go
Normal file
72
config/source/file/watcher_linux.go
Normal 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()
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user