优化结构
This commit is contained in:
@@ -63,7 +63,8 @@ func NewStore(config *Config) *Store {
|
||||
return store
|
||||
}
|
||||
|
||||
// LoadStore loads the initial snapshot and starts watching its source file.
|
||||
// LoadStore loads the initial snapshot and starts the single process-wide
|
||||
// Viper-backed watcher.
|
||||
func LoadStore(path string) (*Store, error) {
|
||||
config, err := Load(path)
|
||||
if err != nil {
|
||||
@@ -260,13 +261,29 @@ func (r *Store) watchLoop(watcher *fsnotify.Watcher, stop <-chan struct{}, done
|
||||
timerC = timer.C
|
||||
case <-timerC:
|
||||
timerC = nil
|
||||
config, err := Load(path)
|
||||
next, err := Load(path)
|
||||
if err != nil {
|
||||
// Keep the last valid snapshot. A partially-written file must not
|
||||
// take down a running process or publish invalid state.
|
||||
continue
|
||||
}
|
||||
r.Replace(config)
|
||||
current := r.Snapshot()
|
||||
if next.Admin == nil {
|
||||
next.Admin = &Admin{}
|
||||
}
|
||||
// Storage and Email move to database-backed integration settings after
|
||||
// first initialization. External config file edits must not erase the
|
||||
// active values when those sections are absent from config.yaml.
|
||||
if current != nil && current.Admin != nil {
|
||||
if next.Admin.Storage == nil {
|
||||
next.Admin.Storage = cloneStorage(current.Admin.Storage)
|
||||
}
|
||||
if next.Admin.Email == nil && current.Admin.Email != nil {
|
||||
email := *current.Admin.Email
|
||||
next.Admin.Email = &email
|
||||
}
|
||||
}
|
||||
r.Replace(next)
|
||||
case _, ok := <-errors:
|
||||
// fsnotify errors are intentionally non-fatal; the watcher remains
|
||||
// useful for subsequent events and Close always terminates it.
|
||||
|
||||
@@ -116,3 +116,32 @@ func TestStoreWatchReloadAndClose(t *testing.T) {
|
||||
}
|
||||
t.Fatalf("watcher did not reload configuration: %#v", store.Snapshot())
|
||||
}
|
||||
|
||||
func TestStoreWatchPreservesDatabaseBackedIntegrationSettings(t *testing.T) {
|
||||
dir := t.TempDir()
|
||||
path := filepath.Join(dir, "config.yaml")
|
||||
writeConfig(t, path, "data: {}\nadmin: {}\n")
|
||||
store, err := LoadStore(path)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer store.Close()
|
||||
current := store.Snapshot()
|
||||
current.Admin.Storage = &Storage{Type: "local"}
|
||||
current.Admin.Email = &Email{Host: "smtp.example.com"}
|
||||
store.Replace(current)
|
||||
|
||||
writeConfig(t, path, "data:\n redis:\n addr: 127.0.0.1:6379\nadmin: {}\n")
|
||||
deadline := time.Now().Add(3 * time.Second)
|
||||
for time.Now().Before(deadline) {
|
||||
value := store.Snapshot()
|
||||
if value != nil && value.Data != nil && value.Data.Redis != nil && value.Data.Redis.Addr != "" {
|
||||
if value.Admin == nil || value.Admin.Storage == nil || value.Admin.Storage.Type != "local" || value.Admin.Email == nil || value.Admin.Email.Host != "smtp.example.com" {
|
||||
t.Fatalf("database-backed settings were lost: %#v", value.Admin)
|
||||
}
|
||||
return
|
||||
}
|
||||
time.Sleep(20 * time.Millisecond)
|
||||
}
|
||||
t.Fatal("watcher did not publish the changed file")
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user