In ReadRemoteConfig, that have no less than one remote providers, but only retrieve the first found configuration. Is there a specific reason?
// Retrieve the first found remote configuration.
func (v *Viper) getKeyValueConfig() error {
if RemoteConfig == nil {
return RemoteConfigError("Enable the remote features by doing a blank import of the viper/remote package: '_ github.com/spf13/viper/remote'")
}
for _, rp := range v.remoteProviders {
val, err := v.getRemoteConfig(rp)
if err != nil {
continue
}
v.kvstore = val
return nil
}
return RemoteConfigError("No Files Found")
}
Comment From: kingmorning
maybe should modify the line: v.kvstore = val
merge the old value and new value.
v.kvstore should store all val from remoteProviders.
Comment From: gangxie112
So, due to this, there is no away to load multiple remote config. Wonder why it's designed/implemented like this? really unthoughtful.
Comment From: iatoz
I can confirm this issue still exists in v1.20.1. I've just spent some time debugging this exact problem and traced it back to the getKeyValueConfig function in remote.go.
The analysis from the original poster is spot on. The function has two main issues:
- Assignment instead of Merging: The line
v.kvstore = valoverwrites the entire configuration map with the values from the current provider, rather than merging them. - Premature Return: The
return nilstatement at the end of the loop causes the function to exit after successfully reading the very first provider, ignoring all others in thev.remoteProvidersslice. Suggested Fix
A potential fix would involve iterating through all providers, fetching their configuration, and merging the results into v.kvstore.
Here is a conceptual implementation of the fix:
// In getKeyValueConfig:
// ...
for _, rp := range v.remoteProviders {
...
// Merge val into v.kvstore
for k, v := range val {
v.kvstore[k] = v
}
}
return nil // Return after the loop finishes
// In getRemoteConfig:
func (v *Viper) getRemoteConfig(provider RemoteProvider) (map[string]any, error) {
reader, err := RemoteConfig.Get(provider)
if err != nil {
return nil, err
}
var newVals map[string]any
err = v.unmarshalReader(reader, &newVals)
return newVals, err
}