-
Notifications
You must be signed in to change notification settings - Fork 2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
concurrent map writes panic #268
Comments
Not sure what you use Viper for, but the common use case is to use it for configuration -- and to set up that in one thread before the real application starts. If we should do something on the Viper side it would be to force people into this init -> use by removing all the setters and take all in via constructor funcs. |
the issue Im reporting is that viper doesn't handle concurrency. Regardless of my use case it is an issue, which could be easily solved with a mutex (https://golang.org/pkg/sync/#Mutex). If you intend to force users into 'the common use case' your tool just becomes less useful. |
I do not intend to do anything about this, I was just suggesting.This is a @spf13 project, he will probably decide if it is worth the extra work/tests to sprinkle the project with mutex locking to support a rare use case. |
bump - @lyondhill , do you have a test case you can share? Thanks. |
I no longer have the code that I was using that would make it happen. But it is very easy to force to happen. The problem really lies in that viper is updating a map in a non concurrent safe way.
|
I agree. I believe basic getters/setters should be thread-safe. There are many uses cases where you'd need to grab configs/values during post-boot runtime of your app (e.g. queues, buffers, etc...) |
Grab as in "get", I assume. But what are the use cases for concurrently read/write? |
Viper is not thread-safe. Using some typical Go techniques, I re-implemented a small core of Viper with JSON support and support for basic Consul watchers (not the most ideal implementation, since it uses polling.) You can find the small sample rewrite here: github.com/rbastic/mvga FYI, my use case is for microservices requiring dynamic configuration reloading. |
Without proper locking, using any of the watch functions is unsafe. This includes WatchConfig and WatchRemoteConfigOnChannel. |
Got this race and that was unexpected... |
Got same problem, but race appears in a place, which is totally unexpected to face it: Here is small test, which fails for me in 50% of cases: package main
import (
"fmt"
"testing"
"github.com/stretchr/testify/require"
"github.com/spf13/afero"
"github.com/spf13/viper"
)
type Setting struct {
TestValue *string `json:"testValue,omitempty" mapstructure:"testvalue"`
}
func TestConcurrency(t *testing.T) {
content := []byte(`{"settings": {"A": {"value": "value A"}, "B": {"value": "value B"}}}`)
aferoFS := afero.NewMemMapFs()
require.NoError(t, afero.WriteFile(aferoFS, "conf.json", content, 0755))
v := viper.New()
v.SetConfigType("json")
v.SetFs(aferoFS)
v.SetConfigFile("conf.json")
require.NoError(t, v.ReadInConfig())
for i := 1; i < 100; i++ {
t.Run(fmt.Sprintf("flow #%d", i), func(tt *testing.T) {
tt.Parallel()
settings := make(map[string]*Setting)
require.NotPanics(t, func() {
require.NoError(t, v.UnmarshalKey("settings", &settings))
})
})
}
} In my case problem is with |
Is this fixed by 9e56dac that was committed yesterday? |
I use viper in production and this do kill me. |
Got bit by this today, using |
Agree docs should be updated to note it's not thread-safe. However, it doesn't necessarily mean viper should be thread-safe as that does come with a performance cost. You can always implement a wrapper around viper of you want concurrent access. |
IIRC the main problem was with reloading config on changes. So on reload, viper writes new option values to the internal map without any locks and does it in a separate goroutine. If anyone tries to read an option from this map (and this happens obviously in another goroutine) at the same time then we will get a concurrent access error. This problem cannot be solved with a kind of external wrapper with its own locks. As a result, this feature of viper is not completely usable. |
Doing concurrent |
Since the update in go to the map concurrent write check viper occasionally fails
The line numbers no longer match the current master branch but the issue for this specific one would be found here now:
https://github.com/spf13/viper/blob/master/viper.go#L1052
The text was updated successfully, but these errors were encountered: