spf13 / viper

Go configuration with fangs
MIT License
26.77k stars 2.01k forks source link

fix(watch remote config cause panic):change #1635

Closed shifengbin closed 11 months ago

shifengbin commented 11 months ago

if we used watch remote config function,when the configuration changes, I happen to be reading the configuration and panic occurs.

You can use the following code to reproduce the problem.

My idea is to copy on write, replacing the original map with a new one when the configuration changes.


type remoteConfigProvider struct{}

func (rc remoteConfigProvider) Get(rp viper.RemoteProvider) (io.Reader, error) {
    log.Println("Getting config from remote", rp)
    r := bytes.NewReader([]byte("{\"a\":1}"))
    //time.Sleep(time.Second)
    return r, nil
}

func (rc remoteConfigProvider) Watch(rp viper.RemoteProvider) (io.Reader, error) {

    log.Println("Watching config from remote", rp)
    s := fmt.Sprintf(`{"app":{"name":"test","version":%d}}`, time.Now().Unix())
    r := bytes.NewReader([]byte(s))
    //time.Sleep(time.Second)
    return r, nil
}

func (rc remoteConfigProvider) WatchChannel(rp viper.RemoteProvider) (<-chan *viper.RemoteResponse, chan bool) {
    log.Println("Watching  Channel config from remote", rp)
    ch := make(chan *viper.RemoteResponse)
    go func() {
        defer close(ch)

        for i := 0; ; i++ {
            ch <- &viper.RemoteResponse{
                Value: []byte(fmt.Sprintf(`{"app":{"name":"test","version":%d}}`, time.Now().Unix())),
            }
            time.Sleep(time.Second)
        }

    }()
    return ch, nil
}
func init() {
    viper.RemoteConfig = remoteConfigProvider{}
    viper.SupportedRemoteProviders = []string{"app"}
}

func main() {

        viper.SetConfigType("json")
    viper.AddRemoteProvider("app", ":8080", "/aabb/cc")
    viper.ReadRemoteConfig()
    fmt.Println("-----------", viper.GetInt64("b"))
     viper.WatchRemoteConfig()
    viper.GetViper().WatchRemoteConfigOnChannel()

       for i := 0; i < 10000; i++ {
            fmt.Println(viper.GetInt64("A"), viper.Get("app"), viper.AllKeys())
            // if i%1000 == 0 {
            //  time.Sleep(time.Second)
            // }
            //time.Sleep(time.Second)
    }
}
github-actions[bot] commented 11 months ago

👋 Thanks for contributing to Viper! You are awesome! 🎉

A maintainer will take a look at your pull request shortly. 👀

In the meantime: We are working on Viper v2 and we would love to hear your thoughts about what you like or don't like about Viper, so we can improve or fix those issues.

⏰ If you have a couple minutes, please take some time and share your thoughts: https://forms.gle/R6faU74qPRPAzchZ9

📣 If you've already given us your feedback, you can still help by spreading the news, either by sharing the above link or telling people about this on Twitter:

https://twitter.com/sagikazarmark/status/1306904078967074816

Thank you! ❤️