From 7c997a1980e1e302e973a6583de65fb73fb405a3 Mon Sep 17 00:00:00 2001 From: liujian Date: Thu, 14 Apr 2022 21:47:42 +0800 Subject: [PATCH 01/11] fix: not following system proxy --- protocol/http/request.go | 1 + 1 file changed, 1 insertion(+) diff --git a/protocol/http/request.go b/protocol/http/request.go index 72202cb..b657f12 100644 --- a/protocol/http/request.go +++ b/protocol/http/request.go @@ -62,6 +62,7 @@ var ( func getDefaultTransport(insecureSkipVerify bool) *http.Transport { once.Do(func() { defaultTransport = &http.Transport{ + Proxy: http.ProxyFromEnvironment, MaxIdleConns: defaultMaxConnsPerHost, MaxIdleConnsPerHost: defaultMaxConnsPerHost, DialContext: (&net.Dialer{ From d186b76f7f7a5d96a102e5d78de21eeaf45cae0b Mon Sep 17 00:00:00 2001 From: liujian Date: Thu, 14 Apr 2022 22:00:09 +0800 Subject: [PATCH 02/11] fix: failed to skip SSL --- protocol/http/request.go | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/protocol/http/request.go b/protocol/http/request.go index b657f12..b05561b 100644 --- a/protocol/http/request.go +++ b/protocol/http/request.go @@ -18,6 +18,7 @@ package http import ( + "context" "crypto/tls" "errors" "fmt" @@ -69,11 +70,12 @@ func getDefaultTransport(insecureSkipVerify bool) *http.Transport { KeepAlive: defaultKeepAliveSecond, Timeout: defaultTimeoutBySecond, }).DialContext, - } - if insecureSkipVerify { - defaultTransport.TLSClientConfig = &tls.Config{ - InsecureSkipVerify: insecureSkipVerify, - } + DialTLSContext: func(ctx context.Context, network, addr string) (net.Conn, error) { + tlsConfig := &tls.Config{ + InsecureSkipVerify: insecureSkipVerify, + } + return tls.Dial(network, addr, tlsConfig) + }, } }) return defaultTransport From c8d34117043bd420b070861c336cd9431b9b2488 Mon Sep 17 00:00:00 2001 From: zander Date: Sun, 17 Apr 2022 22:27:22 +0800 Subject: [PATCH 03/11] =?UTF-8?q?=E6=94=AF=E6=8C=81=E5=AE=A2=E6=88=B7?= =?UTF-8?q?=E7=AB=AF=E6=A0=87=E7=AD=BE=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- component/remote/async.go | 5 +++-- component/remote/sync.go | 5 +++-- env/config/config.go | 1 + 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/component/remote/async.go b/component/remote/async.go index edbd239..586326b 100644 --- a/component/remote/async.go +++ b/component/remote/async.go @@ -59,12 +59,13 @@ func (*asyncApolloConfig) GetNotifyURLSuffix(notifications string, config config } func (*asyncApolloConfig) GetSyncURI(config config.AppConfig, namespaceName string) string { - return fmt.Sprintf("configs/%s/%s/%s?releaseKey=%s&ip=%s", + return fmt.Sprintf("configs/%s/%s/%s?releaseKey=%s&ip=%s&label=%s", url.QueryEscape(config.AppID), url.QueryEscape(config.Cluster), url.QueryEscape(namespaceName), url.QueryEscape(config.GetCurrentApolloConfig().GetReleaseKey(namespaceName)), - utils.GetInternal()) + utils.GetInternal(), + url.QueryEscape(config.Label)) } func (a *asyncApolloConfig) Sync(appConfigFunc func() config.AppConfig) []*config.ApolloConfig { diff --git a/component/remote/sync.go b/component/remote/sync.go index 2a43782..b347d76 100644 --- a/component/remote/sync.go +++ b/component/remote/sync.go @@ -47,11 +47,12 @@ func (*syncApolloConfig) GetNotifyURLSuffix(notifications string, config config. } func (*syncApolloConfig) GetSyncURI(config config.AppConfig, namespaceName string) string { - return fmt.Sprintf("configfiles/json/%s/%s/%s?&ip=%s", + return fmt.Sprintf("configfiles/json/%s/%s/%s?&ip=%s&label=%s", url.QueryEscape(config.AppID), url.QueryEscape(config.Cluster), url.QueryEscape(namespaceName), - utils.GetInternal()) + utils.GetInternal(), + url.QueryEscape(config.Label)) } func (*syncApolloConfig) CallBack(namespace string) http.CallBack { diff --git a/env/config/config.go b/env/config/config.go index 420e047..cea37e4 100644 --- a/env/config/config.go +++ b/env/config/config.go @@ -48,6 +48,7 @@ type AppConfig struct { IsBackupConfig bool `default:"true" json:"isBackupConfig"` BackupConfigPath string `json:"backupConfigPath"` Secret string `json:"secret"` + Label string `json:"label"` SyncServerTimeout int `json:"syncServerTimeout"` // MustStart 可用于控制第一次同步必须成功 MustStart bool `default:"false"` From 3d3d654072ea67138312b07047769ba6b4a76ec7 Mon Sep 17 00:00:00 2001 From: liujian Date: Mon, 18 Apr 2022 23:52:01 +0800 Subject: [PATCH 04/11] =?UTF-8?q?fix:=20=E6=81=A2=E5=A4=8D=E6=97=A7?= =?UTF-8?q?=E7=89=88=E6=9C=ACgo=E7=9A=84=E6=96=B9=E5=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- protocol/http/request.go | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/protocol/http/request.go b/protocol/http/request.go index b05561b..b657f12 100644 --- a/protocol/http/request.go +++ b/protocol/http/request.go @@ -18,7 +18,6 @@ package http import ( - "context" "crypto/tls" "errors" "fmt" @@ -70,12 +69,11 @@ func getDefaultTransport(insecureSkipVerify bool) *http.Transport { KeepAlive: defaultKeepAliveSecond, Timeout: defaultTimeoutBySecond, }).DialContext, - DialTLSContext: func(ctx context.Context, network, addr string) (net.Conn, error) { - tlsConfig := &tls.Config{ - InsecureSkipVerify: insecureSkipVerify, - } - return tls.Dial(network, addr, tlsConfig) - }, + } + if insecureSkipVerify { + defaultTransport.TLSClientConfig = &tls.Config{ + InsecureSkipVerify: insecureSkipVerify, + } } }) return defaultTransport From fd92c4c9360db00f2e06143a14950e9ff72d88f5 Mon Sep 17 00:00:00 2001 From: zander Date: Tue, 19 Apr 2022 21:42:00 +0800 Subject: [PATCH 05/11] =?UTF-8?q?=E8=A1=A5=E5=85=85=E5=8D=95=E5=85=83?= =?UTF-8?q?=E6=B5=8B=E8=AF=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- component/remote/async_test.go | 56 +++++++++++++++++++++++++++++----- component/remote/sync_test.go | 30 ++++++++++++++++++ 2 files changed, 78 insertions(+), 8 deletions(-) diff --git a/component/remote/async_test.go b/component/remote/async_test.go index 4e2244c..dcb428e 100644 --- a/component/remote/async_test.go +++ b/component/remote/async_test.go @@ -46,14 +46,25 @@ func init() { } const configResponseStr = `{ - "appId": "100004458", - "cluster": "default", - "namespaceName": "application", - "configurations": { - "key1":"value1", - "key2":"value2" - }, - "releaseKey": "20170430092936-dee2d58e74515ff3" + "appId": "100004458", + "cluster": "default", + "namespaceName": "application", + "configurations": { + "key1":"value1", + "key2":"value2" + }, + "releaseKey": "20170430092936-dee2d58e74515ff3" +}` + +const grayConfigResponseStr = `{ + "appId": "100004458", + "cluster": "default", + "namespaceName": "application", + "configurations": { + "key1":"gray_value1", + "key2":"gray_value2" + }, + "releaseKey": "20170430092936-dee2d58e74515ff3" }` const configFilesResponseStr = `{ @@ -61,6 +72,11 @@ const configFilesResponseStr = `{ "key2":"value2" }` +const grayConfigFilesResponseStr = `{ + "key1":"gray_value1", + "key2":"gray_value2" +}` + const configAbc1ResponseStr = `{ "appId": "100004458", "cluster": "default", @@ -77,6 +93,13 @@ const tworesponseStr = `[{"namespaceName":"application","notificationId":%d},{"n func onlyNormalConfigResponse(rw http.ResponseWriter, req *http.Request) { rw.WriteHeader(http.StatusOK) + + label, ok := req.URL.Query()["label"] + if ok && len(label) > 0 && label[0] == grayLabel { + fmt.Fprintf(rw, grayConfigResponseStr) + return + } + fmt.Fprintf(rw, configResponseStr) } @@ -192,6 +215,23 @@ func TestApolloConfig_SyncTwoOk(t *testing.T) { Assert(t, appConfig.GetNotificationsMap().GetNotify("abc1"), Equal(int64(3))) } +func TestApolloConfig_GraySync(t *testing.T) { + server := initMockNotifyAndConfigServer() + appConfig := initNotifications() + appConfig.IP = server.URL + appConfig.Label = grayLabel + apolloConfigs := asyncApollo.Sync(func() config.AppConfig { + return *appConfig + }) + //err keep nil + Assert(t, apolloConfigs, NotNilVal()) + Assert(t, len(apolloConfigs), Equal(1)) + + apolloConfig := apolloConfigs[0] + Assert(t, "gray_value1", Equal(apolloConfig.Configurations["key1"])) + Assert(t, "gray_value2", Equal(apolloConfig.Configurations["key2"])) +} + func TestApolloConfig_SyncABC1Error(t *testing.T) { server := initMockNotifyAndConfigServerWithTwoErrResponse() appConfig := initNotifications() diff --git a/component/remote/sync_test.go b/component/remote/sync_test.go index 28dfceb..4c37f8c 100644 --- a/component/remote/sync_test.go +++ b/component/remote/sync_test.go @@ -37,6 +37,7 @@ import ( ) var ( + grayLabel = "gray" normalConfigCount = 1 syncApollo *syncApolloConfig ) @@ -60,6 +61,14 @@ func runNormalConfigResponse() *httptest.Server { ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { normalConfigCount++ if normalConfigCount%2 == 0 { + label, ok := r.URL.Query()["label"] + if ok && len(label) > 0 && label[0] == grayLabel { + w.WriteHeader(http.StatusOK) + w.Write([]byte(grayConfigFilesResponseStr)) + + return + } + w.WriteHeader(http.StatusOK) w.Write([]byte(configFilesResponseStr)) } else { @@ -153,3 +162,24 @@ func TestAutoSyncConfigServicesError(t *testing.T) { Assert(t, len(apolloConfigs), Equal(0)) } + +func TestClientLabelConfigService(t *testing.T) { + server := runNormalConfigResponse() + newAppConfig := initNotifications() + newAppConfig.IP = server.URL + newAppConfig.Label = grayLabel + + apolloConfigs := syncApollo.Sync(func() config.AppConfig { + return *newAppConfig + }) + + Assert(t, apolloConfigs, NotNilVal()) + Assert(t, len(apolloConfigs), Equal(1)) + + apolloConfig := apolloConfigs[0] + newAppConfig.GetCurrentApolloConfig().Set(newAppConfig.NamespaceName, &apolloConfig.ApolloConnConfig) + c := newAppConfig.GetCurrentApolloConfig().Get()[newAppConfig.NamespaceName] + Assert(t, "application", Equal(c.NamespaceName)) + Assert(t, "gray_value1", Equal(apolloConfig.Configurations["key1"])) + Assert(t, "gray_value2", Equal(apolloConfig.Configurations["key2"])) +} From d31afb1a43b0de2ce5199fb8652a775d40168111 Mon Sep 17 00:00:00 2001 From: weihaoyu <444216978@qq.com> Date: Sun, 15 May 2022 14:29:31 +0800 Subject: [PATCH 06/11] add GetValueNotWait func --- go.mod | 1 + go.sum | 2 + storage/repository.go | 148 ++++++++++++++++++++++--------------- storage/repository_test.go | 42 +++++++++-- 4 files changed, 126 insertions(+), 67 deletions(-) diff --git a/go.mod b/go.mod index 1f5c1f5..7252cb7 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,7 @@ module github.com/apolloconfig/agollo/v4 require ( + github.com/pkg/errors v0.9.1 github.com/spf13/viper v1.7.1 github.com/tevid/gohamcrest v1.1.1 ) diff --git a/go.sum b/go.sum index 3dfc818..fc6808b 100644 --- a/go.sum +++ b/go.sum @@ -130,6 +130,8 @@ github.com/pelletier/go-toml v1.2.0 h1:T5zMGML61Wp+FlcbWjRDT7yAxhJNAiPPLOFECq181 github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= diff --git a/storage/repository.go b/storage/repository.go index 684f955..663f38c 100644 --- a/storage/repository.go +++ b/storage/repository.go @@ -24,16 +24,17 @@ import ( "sync" "sync/atomic" - "github.com/apolloconfig/agollo/v4/env/config" + "github.com/pkg/errors" "github.com/apolloconfig/agollo/v4/agcache" "github.com/apolloconfig/agollo/v4/component/log" + "github.com/apolloconfig/agollo/v4/env/config" "github.com/apolloconfig/agollo/v4/extension" "github.com/apolloconfig/agollo/v4/utils" ) const ( - //1 minute + // 1 minute configCacheExpireTime = 120 defaultNamespace = "application" @@ -47,7 +48,7 @@ type Cache struct { changeListeners *list.List } -//GetConfig 根据namespace获取apollo配置 +// GetConfig 根据namespace获取apollo配置 func (c *Cache) GetConfig(namespace string) *Config { if namespace == "" { return nil @@ -62,9 +63,9 @@ func (c *Cache) GetConfig(namespace string) *Config { return config.(*Config) } -//CreateNamespaceConfig 根据namespace初始化agollo内润配置 +// CreateNamespaceConfig 根据namespace初始化agollo内润配置 func CreateNamespaceConfig(namespace string) *Cache { - //config from apollo + // config from apollo var apolloConfigCache sync.Map config.SplitNamespaces(namespace, func(namespace string) { if _, ok := apolloConfigCache.Load(namespace); ok { @@ -89,7 +90,7 @@ func initConfig(namespace string, factory agcache.CacheFactory) *Config { return c } -//Config apollo配置项 +// Config apollo配置项 type Config struct { namespace string cache agcache.CacheInterface @@ -97,45 +98,63 @@ type Config struct { waitInit sync.WaitGroup } -//GetIsInit 获取标志 +// GetIsInit 获取标志 func (c *Config) GetIsInit() bool { return c.isInit.Load().(bool) } -//GetWaitInit 获取标志 +// GetWaitInit 获取标志 func (c *Config) GetWaitInit() *sync.WaitGroup { return &c.waitInit } -//GetCache 获取cache +// GetCache 获取cache func (c *Config) GetCache() agcache.CacheInterface { return c.cache } -//getConfigValue 获取配置值 -func (c *Config) getConfigValue(key string) interface{} { +// getConfigValue 获取配置值 +func (c *Config) getConfigValue(key string, waitInit bool) (value interface{}, err error) { b := c.GetIsInit() if !b { + if !waitInit { + err = errors.Errorf("get config fail, init not done") + return + } c.waitInit.Wait() } if c.cache == nil { - log.Errorf("get config value fail!namespace:%s is not exist!", c.namespace) - return nil + err = errors.Errorf("get config value fail!namespace:%s is not exist!", c.namespace) + return + } + + if value, err = c.cache.Get(key); err != nil { + err = errors.Errorf("get config value fail!key:%s,err:%s", key, err) + return } - value, err := c.cache.Get(key) + return +} + +// GetValueNotWait 获取配置值,不阻塞(string) +func (c *Config) GetValueNotWait(key string) (string, error) { + value, err := c.getConfigValue(key, false) if err != nil { - log.Errorf("get config value fail!key:%s,err:%s", key, err) - return nil + return utils.Empty, err } - return value + v, ok := value.(string) + if !ok { + return utils.Empty, errors.Errorf("convert to string fail ! source type:%T", value) + } + return v, nil } -//GetValue 获取配置值(string) +// GetValue 获取配置值(string) func (c *Config) GetValue(key string) string { - value := c.getConfigValue(key) - if value == nil { + value, err := c.getConfigValue(key, true) + if err != nil { + log.Errorf(err.Error()) return utils.Empty } @@ -147,7 +166,7 @@ func (c *Config) GetValue(key string) string { return v } -//GetStringValue 获取配置值(string),获取不到则取默认值 +// GetStringValue 获取配置值(string),获取不到则取默认值 func (c *Config) GetStringValue(key string, defaultValue string) string { value := c.GetValue(key) if value == utils.Empty { @@ -157,12 +176,14 @@ func (c *Config) GetStringValue(key string, defaultValue string) string { return value } -//GetStringSliceValue 获取配置值([]string) +// GetStringSliceValue 获取配置值([]string) func (c *Config) GetStringSliceValue(key string, defaultValue []string) []string { - value := c.getConfigValue(key) - if value == nil { + value, err := c.getConfigValue(key, true) + if err != nil { + log.Errorf(err.Error()) return defaultValue } + v, ok := value.([]string) if !ok { log.Debug("convert to []string fail ! source type:%T", value) @@ -171,12 +192,14 @@ func (c *Config) GetStringSliceValue(key string, defaultValue []string) []string return v } -//GetIntSliceValue 获取配置值([]int) +// GetIntSliceValue 获取配置值([]int) func (c *Config) GetIntSliceValue(key string, defaultValue []int) []int { - value := c.getConfigValue(key) - if value == nil { + value, err := c.getConfigValue(key, true) + if err != nil { + log.Errorf(err.Error()) return defaultValue } + v, ok := value.([]int) if !ok { log.Debug("convert to []int fail ! source type:%T", value) @@ -185,12 +208,14 @@ func (c *Config) GetIntSliceValue(key string, defaultValue []int) []int { return v } -//GetSliceValue 获取配置值([]interface) +// GetSliceValue 获取配置值([]interface) func (c *Config) GetSliceValue(key string, defaultValue []interface{}) []interface{} { - value := c.getConfigValue(key) - if value == nil { + value, err := c.getConfigValue(key, true) + if err != nil { + log.Errorf(err.Error()) return defaultValue } + v, ok := value.([]interface{}) if !ok { log.Debug("convert to []interface{} fail ! source type:%T", value) @@ -199,13 +224,14 @@ func (c *Config) GetSliceValue(key string, defaultValue []interface{}) []interfa return v } -//GetIntValue 获取配置值(int),获取不到则取默认值 +// GetIntValue 获取配置值(int),获取不到则取默认值 func (c *Config) GetIntValue(key string, defaultValue int) int { - value := c.getConfigValue(key) - - if value == nil { + value, err := c.getConfigValue(key, true) + if err != nil { + log.Errorf(err.Error()) return defaultValue } + v, ok := value.(int) if !ok { log.Debug("convert to int fail ! source type:%T", value) @@ -214,11 +240,11 @@ func (c *Config) GetIntValue(key string, defaultValue int) int { return v } -//GetFloatValue 获取配置值(float),获取不到则取默认值 +// GetFloatValue 获取配置值(float),获取不到则取默认值 func (c *Config) GetFloatValue(key string, defaultValue float64) float64 { - value := c.getConfigValue(key) - - if value == nil { + value, err := c.getConfigValue(key, true) + if err != nil { + log.Errorf(err.Error()) return defaultValue } @@ -230,9 +256,13 @@ func (c *Config) GetFloatValue(key string, defaultValue float64) float64 { return v } -//GetBoolValue 获取配置值(bool),获取不到则取默认值 +// GetBoolValue 获取配置值(bool),获取不到则取默认值 func (c *Config) GetBoolValue(key string, defaultValue bool) bool { - value := c.getConfigValue(key) + value, err := c.getConfigValue(key, true) + if err != nil { + log.Errorf(err.Error()) + return defaultValue + } v, ok := value.(bool) if !ok { @@ -242,8 +272,8 @@ func (c *Config) GetBoolValue(key string, defaultValue bool) bool { return v } -//UpdateApolloConfig 根据config server返回的内容更新内存 -//并判断是否需要写备份文件 +// UpdateApolloConfig 根据config server返回的内容更新内存 +// 并判断是否需要写备份文件 func (c *Cache) UpdateApolloConfig(apolloConfig *config.ApolloConfig, appConfigFunc func() config.AppConfig) { if apolloConfig == nil { log.Error("apolloConfig is null,can't update!") @@ -251,33 +281,33 @@ func (c *Cache) UpdateApolloConfig(apolloConfig *config.ApolloConfig, appConfigF } appConfig := appConfigFunc() - //update apollo connection config + // update apollo connection config appConfig.SetCurrentApolloConfig(&apolloConfig.ApolloConnConfig) - //get change list + // get change list changeList := c.UpdateApolloConfigCache(apolloConfig.Configurations, configCacheExpireTime, apolloConfig.NamespaceName) notify := appConfig.GetNotificationsMap().GetNotify(apolloConfig.NamespaceName) - //push all newest changes + // push all newest changes c.pushNewestChanges(apolloConfig.NamespaceName, apolloConfig.Configurations, notify) if len(changeList) > 0 { - //create config change event base on change list + // create config change event base on change list event := createConfigChangeEvent(changeList, apolloConfig.NamespaceName, notify) - //push change event to channel + // push change event to channel c.pushChangeEvent(event) } if appConfig.GetIsBackupConfig() { - //write config file async + // write config file async apolloConfig.AppID = appConfig.AppID go extension.GetFileHandler().WriteConfigFile(apolloConfig, appConfig.GetBackupConfigPath()) } } -//UpdateApolloConfigCache 根据conf[ig server返回的内容更新内存 +// UpdateApolloConfigCache 根据conf[ig server返回的内容更新内存 func (c *Cache) UpdateApolloConfigCache(configurations map[string]interface{}, expireTime int, namespace string) map[string]*ConfigChange { config := c.GetConfig(namespace) if config == nil { @@ -302,7 +332,7 @@ func (c *Cache) UpdateApolloConfigCache(configurations map[string]interface{}, e return nil } - //get old keys + // get old keys mp := map[string]bool{} config.cache.Range(func(key, value interface{}) bool { mp[key.(string)] = true @@ -315,12 +345,12 @@ func (c *Cache) UpdateApolloConfigCache(configurations map[string]interface{}, e // update new // keys for key, value := range configurations { - //key state insert or update - //insert + // key state insert or update + // insert if !mp[key] { changes[key] = createAddConfigChange(value) } else { - //update + // update oldValue, _ := config.cache.Get(key) if !reflect.DeepEqual(oldValue, value) { changes[key] = createModifyConfigChange(oldValue, value) @@ -336,7 +366,7 @@ func (c *Cache) UpdateApolloConfigCache(configurations map[string]interface{}, e // remove del keys for key := range mp { - //get old value and del + // get old value and del oldValue, _ := config.cache.Get(key) changes[key] = createDeletedConfigChange(oldValue) @@ -347,7 +377,7 @@ func (c *Cache) UpdateApolloConfigCache(configurations map[string]interface{}, e return changes } -//GetContent 获取配置文件内容 +// GetContent 获取配置文件内容 func (c *Config) GetContent() string { return convertToProperties(c.cache) } @@ -364,12 +394,12 @@ func convertToProperties(cache agcache.CacheInterface) string { return properties } -//GetDefaultNamespace 获取默认命名空间 +// GetDefaultNamespace 获取默认命名空间 func GetDefaultNamespace() string { return defaultNamespace } -//AddChangeListener 增加变更监控 +// AddChangeListener 增加变更监控 func (c *Cache) AddChangeListener(listener ChangeListener) { if listener == nil { return @@ -377,7 +407,7 @@ func (c *Cache) AddChangeListener(listener ChangeListener) { c.changeListeners.PushBack(listener) } -//RemoveChangeListener 增加变更监控 +// RemoveChangeListener 增加变更监控 func (c *Cache) RemoveChangeListener(listener ChangeListener) { if listener == nil { return @@ -395,7 +425,7 @@ func (c *Cache) GetChangeListeners() *list.List { return c.changeListeners } -//push config change event +// push config change event func (c *Cache) pushChangeEvent(event *ChangeEvent) { c.pushChange(func(listener ChangeListener) { go listener.OnChange(event) diff --git a/storage/repository_test.go b/storage/repository_test.go index 6767cca..1b98555 100644 --- a/storage/repository_test.go +++ b/storage/repository_test.go @@ -26,6 +26,7 @@ import ( "github.com/apolloconfig/agollo/v4/env/config" jsonFile "github.com/apolloconfig/agollo/v4/env/file/json" "github.com/apolloconfig/agollo/v4/extension" + "github.com/apolloconfig/agollo/v4/utils" _ "github.com/apolloconfig/agollo/v4/agcache/memory" "github.com/apolloconfig/agollo/v4/env" @@ -36,7 +37,7 @@ import ( _ "github.com/apolloconfig/agollo/v4/utils/parse/properties" ) -//init param +// init param func init() { extension.SetCacheFactory(&memory.DefaultCacheFactory{}) extension.SetFileHandler(&jsonFile.FileHandler{}) @@ -54,7 +55,6 @@ func creatTestApolloConfig(configurations map[string]interface{}, namespace stri return *appConfig }) return c - } func TestUpdateApolloConfigNull(t *testing.T) { @@ -87,7 +87,6 @@ func TestUpdateApolloConfigNull(t *testing.T) { Assert(t, apolloConfig.Cluster, Equal(config.Cluster)) Assert(t, "", Equal(config.ReleaseKey)) Assert(t, len(apolloConfig.Configurations), Equal(5)) - } func TestGetDefaultNamespace(t *testing.T) { @@ -108,26 +107,26 @@ func TestGetConfig(t *testing.T) { config := c.GetConfig("test") Assert(t, config, NotNilVal()) - //string + // string s := config.GetStringValue("string", "s") Assert(t, s, Equal(configurations["string"])) s = config.GetStringValue("s", "s") Assert(t, s, Equal("s")) - //int + // int i := config.GetIntValue("int", 3) Assert(t, i, Equal(2)) i = config.GetIntValue("i", 3) Assert(t, i, Equal(3)) - //float + // float f := config.GetFloatValue("float", 2) Assert(t, f, Equal(1.9)) f = config.GetFloatValue("f", 2) Assert(t, f, Equal(float64(2))) - //bool + // bool b := config.GetBoolValue("bool", true) Assert(t, b, Equal(false)) @@ -143,7 +142,7 @@ func TestGetConfig(t *testing.T) { sliceInter := config.GetSliceValue("sliceInter", []interface{}{}) Assert(t, sliceInter, Equal([]interface{}{1, "2", 3})) - //content + // content content := config.GetContent() hasFloat := strings.Contains(content, "float=1") Assert(t, hasFloat, Equal(true)) @@ -225,3 +224,30 @@ func TestDispatchInRepository(t *testing.T) { _, ok = l.Keys["modify"] Assert(t, ok, Equal(false)) } + +func TestGetValueNotWait(t *testing.T) { + c := initConfig("namespace", extension.GetCacheFactory()) + + res, err := c.GetValueNotWait("namespace") + Assert(t, res, Equal(utils.Empty)) + Assert(t, err.Error(), Equal("get config fail, init not done")) + + c.isInit.Store(true) + res, err = c.GetValueNotWait("namespace") + Assert(t, res, Equal(utils.Empty)) + Assert(t, err.Error(), Equal("get config value fail!key:namespace,err:load default cache fail")) + + res, err = c.GetValueNotWait("namespace1") + Assert(t, res, Equal(utils.Empty)) + Assert(t, err.Error(), Equal("get config value fail!key:namespace1,err:load default cache fail")) + + c.cache.Set("namespace", 1, 3) + res, err = c.GetValueNotWait("namespace") + Assert(t, res, Equal(utils.Empty)) + Assert(t, err.Error(), Equal("convert to string fail ! source type:int")) + + c.cache.Set("namespace", "config", 3) + res, err = c.GetValueNotWait("namespace") + Assert(t, res, Equal("config")) + Assert(t, err, Equal(nil)) +} From 17a982f1c6d5a82c510c17cbb2b37ac85cb39c17 Mon Sep 17 00:00:00 2001 From: weihaoyu <444216978@qq.com> Date: Mon, 16 May 2022 11:22:41 +0800 Subject: [PATCH 07/11] GetValueImmediately --- go.mod | 1 - go.sum | 3 +- storage/repository.go | 171 ++++++++++++++++++++++++++++--------- storage/repository_test.go | 66 +++++++++++--- 4 files changed, 188 insertions(+), 53 deletions(-) diff --git a/go.mod b/go.mod index 7252cb7..1f5c1f5 100644 --- a/go.mod +++ b/go.mod @@ -1,7 +1,6 @@ module github.com/apolloconfig/agollo/v4 require ( - github.com/pkg/errors v0.9.1 github.com/spf13/viper v1.7.1 github.com/tevid/gohamcrest v1.1.1 ) diff --git a/go.sum b/go.sum index fc6808b..18af665 100644 --- a/go.sum +++ b/go.sum @@ -129,9 +129,8 @@ github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FI github.com/pelletier/go-toml v1.2.0 h1:T5zMGML61Wp+FlcbWjRDT7yAxhJNAiPPLOFECq181zc= github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= -github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= diff --git a/storage/repository.go b/storage/repository.go index 663f38c..969ecc8 100644 --- a/storage/repository.go +++ b/storage/repository.go @@ -24,8 +24,6 @@ import ( "sync" "sync/atomic" - "github.com/pkg/errors" - "github.com/apolloconfig/agollo/v4/agcache" "github.com/apolloconfig/agollo/v4/component/log" "github.com/apolloconfig/agollo/v4/env/config" @@ -114,47 +112,148 @@ func (c *Config) GetCache() agcache.CacheInterface { } // getConfigValue 获取配置值 -func (c *Config) getConfigValue(key string, waitInit bool) (value interface{}, err error) { +func (c *Config) getConfigValue(key string, waitInit bool) interface{} { b := c.GetIsInit() if !b { if !waitInit { - err = errors.Errorf("get config fail, init not done") - return + log.Errorf("getConfigValue fail, init not done, namespace:%s key:%s", c.namespace, key) + return nil } c.waitInit.Wait() } if c.cache == nil { - err = errors.Errorf("get config value fail!namespace:%s is not exist!", c.namespace) - return + log.Errorf("get config value fail!namespace:%s is not exist!", c.namespace) + return nil } - if value, err = c.cache.Get(key); err != nil { - err = errors.Errorf("get config value fail!key:%s,err:%s", key, err) - return + value, err := c.cache.Get(key) + if err != nil { + log.Errorf("get config value fail!key:%s,err:%s", key, err) + return nil } - return + return value } -// GetValueNotWait 获取配置值,不阻塞(string) -func (c *Config) GetValueNotWait(key string) (string, error) { - value, err := c.getConfigValue(key, false) - if err != nil { - return utils.Empty, err +// GetValueImmediately 获取配置值(string),立即返回,初始化未完成直接返回错误 +func (c *Config) GetValueImmediately(key string) string { + value := c.getConfigValue(key, false) + if value == nil { + return utils.Empty } v, ok := value.(string) if !ok { - return utils.Empty, errors.Errorf("convert to string fail ! source type:%T", value) + log.Debug("convert to string fail ! source type:%T", value) + return utils.Empty } - return v, nil + return v +} + +// GetStringValue 获取配置值(string),获取不到则取默认值,立即返回,初始化未完成直接返回错误 +func (c *Config) GetStringValueImmediately(key string, defaultValue string) string { + value := c.GetValueImmediately(key) + if value == utils.Empty { + return defaultValue + } + + return value +} + +// GetStringSliceValueImmediately 获取配置值([]string),立即返回,初始化未完成直接返回错误 +func (c *Config) GetStringSliceValueImmediately(key string, defaultValue []string) []string { + value := c.getConfigValue(key, false) + if value == nil { + return defaultValue + } + + v, ok := value.([]string) + if !ok { + log.Debug("convert to []string fail ! source type:%T", value) + return defaultValue + } + return v +} + +// GetIntSliceValueImmediately 获取配置值([]int),立即返回,初始化未完成直接返回错误 +func (c *Config) GetIntSliceValueImmediately(key string, defaultValue []int) []int { + value := c.getConfigValue(key, false) + if value == nil { + return defaultValue + } + + v, ok := value.([]int) + if !ok { + log.Debug("convert to []int fail ! source type:%T", value) + return defaultValue + } + return v +} + +// GetSliceValueImmediately 获取配置值([]interface),立即返回,初始化未完成直接返回错误 +func (c *Config) GetSliceValueImmediately(key string, defaultValue []interface{}) []interface{} { + value := c.getConfigValue(key, false) + if value == nil { + return defaultValue + } + + v, ok := value.([]interface{}) + if !ok { + log.Debug("convert to []interface{} fail ! source type:%T", value) + return defaultValue + } + return v +} + +// GetIntValueImmediately 获取配置值(int),获取不到则取默认值,立即返回,初始化未完成直接返回错误 +func (c *Config) GetIntValueImmediately(key string, defaultValue int) int { + value := c.getConfigValue(key, false) + if value == nil { + return defaultValue + } + + v, ok := value.(int) + if !ok { + log.Debug("convert to int fail ! source type:%T", value) + return defaultValue + } + return v +} + +// GetFloatValueImmediately 获取配置值(float),获取不到则取默认值,立即返回,初始化未完成直接返回错误 +func (c *Config) GetFloatValueImmediately(key string, defaultValue float64) float64 { + value := c.getConfigValue(key, false) + if value == nil { + return defaultValue + } + + v, ok := value.(float64) + if !ok { + log.Debug("convert to float64 fail ! source type:%T", value) + return defaultValue + } + return v +} + +// GetBoolValueImmediately 获取配置值(bool),获取不到则取默认值,立即返回,初始化未完成直接返回错误 +func (c *Config) GetBoolValueImmediately(key string, defaultValue bool) bool { + value := c.getConfigValue(key, false) + if value == nil { + return defaultValue + } + + v, ok := value.(bool) + if !ok { + log.Debug("convert to bool fail ! source type:%T", value) + return defaultValue + } + return v } // GetValue 获取配置值(string) func (c *Config) GetValue(key string) string { - value, err := c.getConfigValue(key, true) - if err != nil { - log.Errorf(err.Error()) + value := c.getConfigValue(key, true) + if value == nil { return utils.Empty } @@ -178,9 +277,8 @@ func (c *Config) GetStringValue(key string, defaultValue string) string { // GetStringSliceValue 获取配置值([]string) func (c *Config) GetStringSliceValue(key string, defaultValue []string) []string { - value, err := c.getConfigValue(key, true) - if err != nil { - log.Errorf(err.Error()) + value := c.getConfigValue(key, true) + if value == nil { return defaultValue } @@ -194,9 +292,8 @@ func (c *Config) GetStringSliceValue(key string, defaultValue []string) []string // GetIntSliceValue 获取配置值([]int) func (c *Config) GetIntSliceValue(key string, defaultValue []int) []int { - value, err := c.getConfigValue(key, true) - if err != nil { - log.Errorf(err.Error()) + value := c.getConfigValue(key, true) + if value == nil { return defaultValue } @@ -210,9 +307,8 @@ func (c *Config) GetIntSliceValue(key string, defaultValue []int) []int { // GetSliceValue 获取配置值([]interface) func (c *Config) GetSliceValue(key string, defaultValue []interface{}) []interface{} { - value, err := c.getConfigValue(key, true) - if err != nil { - log.Errorf(err.Error()) + value := c.getConfigValue(key, true) + if value == nil { return defaultValue } @@ -226,9 +322,8 @@ func (c *Config) GetSliceValue(key string, defaultValue []interface{}) []interfa // GetIntValue 获取配置值(int),获取不到则取默认值 func (c *Config) GetIntValue(key string, defaultValue int) int { - value, err := c.getConfigValue(key, true) - if err != nil { - log.Errorf(err.Error()) + value := c.getConfigValue(key, true) + if value == nil { return defaultValue } @@ -242,9 +337,8 @@ func (c *Config) GetIntValue(key string, defaultValue int) int { // GetFloatValue 获取配置值(float),获取不到则取默认值 func (c *Config) GetFloatValue(key string, defaultValue float64) float64 { - value, err := c.getConfigValue(key, true) - if err != nil { - log.Errorf(err.Error()) + value := c.getConfigValue(key, true) + if value == nil { return defaultValue } @@ -258,9 +352,8 @@ func (c *Config) GetFloatValue(key string, defaultValue float64) float64 { // GetBoolValue 获取配置值(bool),获取不到则取默认值 func (c *Config) GetBoolValue(key string, defaultValue bool) bool { - value, err := c.getConfigValue(key, true) - if err != nil { - log.Errorf(err.Error()) + value := c.getConfigValue(key, true) + if value == nil { return defaultValue } diff --git a/storage/repository_test.go b/storage/repository_test.go index 1b98555..dcf03aa 100644 --- a/storage/repository_test.go +++ b/storage/repository_test.go @@ -225,29 +225,73 @@ func TestDispatchInRepository(t *testing.T) { Assert(t, ok, Equal(false)) } -func TestGetValueNotWait(t *testing.T) { +func TestGetValueImmediately(t *testing.T) { c := initConfig("namespace", extension.GetCacheFactory()) - res, err := c.GetValueNotWait("namespace") + res := c.GetValueImmediately("namespace") Assert(t, res, Equal(utils.Empty)) - Assert(t, err.Error(), Equal("get config fail, init not done")) c.isInit.Store(true) - res, err = c.GetValueNotWait("namespace") + res = c.GetValueImmediately("namespace") Assert(t, res, Equal(utils.Empty)) - Assert(t, err.Error(), Equal("get config value fail!key:namespace,err:load default cache fail")) - res, err = c.GetValueNotWait("namespace1") + res = c.GetValueImmediately("namespace1") Assert(t, res, Equal(utils.Empty)) - Assert(t, err.Error(), Equal("get config value fail!key:namespace1,err:load default cache fail")) c.cache.Set("namespace", 1, 3) - res, err = c.GetValueNotWait("namespace") + res = c.GetValueImmediately("namespace") Assert(t, res, Equal(utils.Empty)) - Assert(t, err.Error(), Equal("convert to string fail ! source type:int")) c.cache.Set("namespace", "config", 3) - res, err = c.GetValueNotWait("namespace") + res = c.GetValueImmediately("namespace") Assert(t, res, Equal("config")) - Assert(t, err, Equal(nil)) +} + +func TestGetConfigImmediately(t *testing.T) { + configurations := make(map[string]interface{}) + configurations["string"] = "string2" + configurations["int"] = 2 + configurations["float"] = 1.9 + configurations["bool"] = false + configurations["sliceString"] = []string{"1", "2", "3"} + configurations["sliceInt"] = []int{1, 2, 3} + configurations["sliceInter"] = []interface{}{1, "2", 3} + c := creatTestApolloConfig(configurations, "test") + config := c.GetConfig("test") + Assert(t, config, NotNilVal()) + + // string + s := config.GetStringValueImmediately("string", "s") + Assert(t, s, Equal(configurations["string"])) + + s = config.GetStringValueImmediately("s", "s") + Assert(t, s, Equal("s")) + + // int + i := config.GetIntValueImmediately("int", 3) + Assert(t, i, Equal(2)) + i = config.GetIntValueImmediately("i", 3) + Assert(t, i, Equal(3)) + + // float + f := config.GetFloatValueImmediately("float", 2) + Assert(t, f, Equal(1.9)) + f = config.GetFloatValueImmediately("f", 2) + Assert(t, f, Equal(float64(2))) + + // bool + b := config.GetBoolValueImmediately("bool", true) + Assert(t, b, Equal(false)) + + b = config.GetBoolValueImmediately("b", false) + Assert(t, b, Equal(false)) + + slice := config.GetStringSliceValueImmediately("sliceString", []string{}) + Assert(t, slice, Equal([]string{"1", "2", "3"})) + + sliceInt := config.GetIntSliceValueImmediately("sliceInt", []int{}) + Assert(t, sliceInt, Equal([]int{1, 2, 3})) + + sliceInter := config.GetSliceValueImmediately("sliceInter", []interface{}{}) + Assert(t, sliceInter, Equal([]interface{}{1, "2", 3})) } From 9d7975995526bd3b986eff13d1d3078e70c1bd76 Mon Sep 17 00:00:00 2001 From: weihaoyu <444216978@qq.com> Date: Mon, 16 May 2022 11:22:41 +0800 Subject: [PATCH 08/11] GetValueImmediately --- go.mod | 1 - go.sum | 3 +- storage/repository.go | 171 ++++++++++++++++++++++++++++--------- storage/repository_test.go | 66 +++++++++++--- 4 files changed, 188 insertions(+), 53 deletions(-) diff --git a/go.mod b/go.mod index 7252cb7..1f5c1f5 100644 --- a/go.mod +++ b/go.mod @@ -1,7 +1,6 @@ module github.com/apolloconfig/agollo/v4 require ( - github.com/pkg/errors v0.9.1 github.com/spf13/viper v1.7.1 github.com/tevid/gohamcrest v1.1.1 ) diff --git a/go.sum b/go.sum index fc6808b..18af665 100644 --- a/go.sum +++ b/go.sum @@ -129,9 +129,8 @@ github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FI github.com/pelletier/go-toml v1.2.0 h1:T5zMGML61Wp+FlcbWjRDT7yAxhJNAiPPLOFECq181zc= github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= -github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= diff --git a/storage/repository.go b/storage/repository.go index 663f38c..5efd51f 100644 --- a/storage/repository.go +++ b/storage/repository.go @@ -24,8 +24,6 @@ import ( "sync" "sync/atomic" - "github.com/pkg/errors" - "github.com/apolloconfig/agollo/v4/agcache" "github.com/apolloconfig/agollo/v4/component/log" "github.com/apolloconfig/agollo/v4/env/config" @@ -114,47 +112,148 @@ func (c *Config) GetCache() agcache.CacheInterface { } // getConfigValue 获取配置值 -func (c *Config) getConfigValue(key string, waitInit bool) (value interface{}, err error) { +func (c *Config) getConfigValue(key string, waitInit bool) interface{} { b := c.GetIsInit() if !b { if !waitInit { - err = errors.Errorf("get config fail, init not done") - return + log.Errorf("getConfigValue fail, init not done, namespace:%s key:%s", c.namespace, key) + return nil } c.waitInit.Wait() } if c.cache == nil { - err = errors.Errorf("get config value fail!namespace:%s is not exist!", c.namespace) - return + log.Errorf("get config value fail!namespace:%s is not exist!", c.namespace) + return nil } - if value, err = c.cache.Get(key); err != nil { - err = errors.Errorf("get config value fail!key:%s,err:%s", key, err) - return + value, err := c.cache.Get(key) + if err != nil { + log.Errorf("get config value fail!key:%s,err:%s", key, err) + return nil } - return + return value } -// GetValueNotWait 获取配置值,不阻塞(string) -func (c *Config) GetValueNotWait(key string) (string, error) { - value, err := c.getConfigValue(key, false) - if err != nil { - return utils.Empty, err +// GetValueImmediately 获取配置值(string),立即返回,初始化未完成直接返回错误 +func (c *Config) GetValueImmediately(key string) string { + value := c.getConfigValue(key, false) + if value == nil { + return utils.Empty } v, ok := value.(string) if !ok { - return utils.Empty, errors.Errorf("convert to string fail ! source type:%T", value) + log.Debug("convert to string fail ! source type:%T", value) + return utils.Empty } - return v, nil + return v +} + +// GetStringValueImmediately 获取配置值(string),获取不到则取默认值,立即返回,初始化未完成直接返回错误 +func (c *Config) GetStringValueImmediately(key string, defaultValue string) string { + value := c.GetValueImmediately(key) + if value == utils.Empty { + return defaultValue + } + + return value +} + +// GetStringSliceValueImmediately 获取配置值([]string),立即返回,初始化未完成直接返回错误 +func (c *Config) GetStringSliceValueImmediately(key string, defaultValue []string) []string { + value := c.getConfigValue(key, false) + if value == nil { + return defaultValue + } + + v, ok := value.([]string) + if !ok { + log.Debug("convert to []string fail ! source type:%T", value) + return defaultValue + } + return v +} + +// GetIntSliceValueImmediately 获取配置值([]int),立即返回,初始化未完成直接返回错误 +func (c *Config) GetIntSliceValueImmediately(key string, defaultValue []int) []int { + value := c.getConfigValue(key, false) + if value == nil { + return defaultValue + } + + v, ok := value.([]int) + if !ok { + log.Debug("convert to []int fail ! source type:%T", value) + return defaultValue + } + return v +} + +// GetSliceValueImmediately 获取配置值([]interface),立即返回,初始化未完成直接返回错误 +func (c *Config) GetSliceValueImmediately(key string, defaultValue []interface{}) []interface{} { + value := c.getConfigValue(key, false) + if value == nil { + return defaultValue + } + + v, ok := value.([]interface{}) + if !ok { + log.Debug("convert to []interface{} fail ! source type:%T", value) + return defaultValue + } + return v +} + +// GetIntValueImmediately 获取配置值(int),获取不到则取默认值,立即返回,初始化未完成直接返回错误 +func (c *Config) GetIntValueImmediately(key string, defaultValue int) int { + value := c.getConfigValue(key, false) + if value == nil { + return defaultValue + } + + v, ok := value.(int) + if !ok { + log.Debug("convert to int fail ! source type:%T", value) + return defaultValue + } + return v +} + +// GetFloatValueImmediately 获取配置值(float),获取不到则取默认值,立即返回,初始化未完成直接返回错误 +func (c *Config) GetFloatValueImmediately(key string, defaultValue float64) float64 { + value := c.getConfigValue(key, false) + if value == nil { + return defaultValue + } + + v, ok := value.(float64) + if !ok { + log.Debug("convert to float64 fail ! source type:%T", value) + return defaultValue + } + return v +} + +// GetBoolValueImmediately 获取配置值(bool),获取不到则取默认值,立即返回,初始化未完成直接返回错误 +func (c *Config) GetBoolValueImmediately(key string, defaultValue bool) bool { + value := c.getConfigValue(key, false) + if value == nil { + return defaultValue + } + + v, ok := value.(bool) + if !ok { + log.Debug("convert to bool fail ! source type:%T", value) + return defaultValue + } + return v } // GetValue 获取配置值(string) func (c *Config) GetValue(key string) string { - value, err := c.getConfigValue(key, true) - if err != nil { - log.Errorf(err.Error()) + value := c.getConfigValue(key, true) + if value == nil { return utils.Empty } @@ -178,9 +277,8 @@ func (c *Config) GetStringValue(key string, defaultValue string) string { // GetStringSliceValue 获取配置值([]string) func (c *Config) GetStringSliceValue(key string, defaultValue []string) []string { - value, err := c.getConfigValue(key, true) - if err != nil { - log.Errorf(err.Error()) + value := c.getConfigValue(key, true) + if value == nil { return defaultValue } @@ -194,9 +292,8 @@ func (c *Config) GetStringSliceValue(key string, defaultValue []string) []string // GetIntSliceValue 获取配置值([]int) func (c *Config) GetIntSliceValue(key string, defaultValue []int) []int { - value, err := c.getConfigValue(key, true) - if err != nil { - log.Errorf(err.Error()) + value := c.getConfigValue(key, true) + if value == nil { return defaultValue } @@ -210,9 +307,8 @@ func (c *Config) GetIntSliceValue(key string, defaultValue []int) []int { // GetSliceValue 获取配置值([]interface) func (c *Config) GetSliceValue(key string, defaultValue []interface{}) []interface{} { - value, err := c.getConfigValue(key, true) - if err != nil { - log.Errorf(err.Error()) + value := c.getConfigValue(key, true) + if value == nil { return defaultValue } @@ -226,9 +322,8 @@ func (c *Config) GetSliceValue(key string, defaultValue []interface{}) []interfa // GetIntValue 获取配置值(int),获取不到则取默认值 func (c *Config) GetIntValue(key string, defaultValue int) int { - value, err := c.getConfigValue(key, true) - if err != nil { - log.Errorf(err.Error()) + value := c.getConfigValue(key, true) + if value == nil { return defaultValue } @@ -242,9 +337,8 @@ func (c *Config) GetIntValue(key string, defaultValue int) int { // GetFloatValue 获取配置值(float),获取不到则取默认值 func (c *Config) GetFloatValue(key string, defaultValue float64) float64 { - value, err := c.getConfigValue(key, true) - if err != nil { - log.Errorf(err.Error()) + value := c.getConfigValue(key, true) + if value == nil { return defaultValue } @@ -258,9 +352,8 @@ func (c *Config) GetFloatValue(key string, defaultValue float64) float64 { // GetBoolValue 获取配置值(bool),获取不到则取默认值 func (c *Config) GetBoolValue(key string, defaultValue bool) bool { - value, err := c.getConfigValue(key, true) - if err != nil { - log.Errorf(err.Error()) + value := c.getConfigValue(key, true) + if value == nil { return defaultValue } diff --git a/storage/repository_test.go b/storage/repository_test.go index 1b98555..dcf03aa 100644 --- a/storage/repository_test.go +++ b/storage/repository_test.go @@ -225,29 +225,73 @@ func TestDispatchInRepository(t *testing.T) { Assert(t, ok, Equal(false)) } -func TestGetValueNotWait(t *testing.T) { +func TestGetValueImmediately(t *testing.T) { c := initConfig("namespace", extension.GetCacheFactory()) - res, err := c.GetValueNotWait("namespace") + res := c.GetValueImmediately("namespace") Assert(t, res, Equal(utils.Empty)) - Assert(t, err.Error(), Equal("get config fail, init not done")) c.isInit.Store(true) - res, err = c.GetValueNotWait("namespace") + res = c.GetValueImmediately("namespace") Assert(t, res, Equal(utils.Empty)) - Assert(t, err.Error(), Equal("get config value fail!key:namespace,err:load default cache fail")) - res, err = c.GetValueNotWait("namespace1") + res = c.GetValueImmediately("namespace1") Assert(t, res, Equal(utils.Empty)) - Assert(t, err.Error(), Equal("get config value fail!key:namespace1,err:load default cache fail")) c.cache.Set("namespace", 1, 3) - res, err = c.GetValueNotWait("namespace") + res = c.GetValueImmediately("namespace") Assert(t, res, Equal(utils.Empty)) - Assert(t, err.Error(), Equal("convert to string fail ! source type:int")) c.cache.Set("namespace", "config", 3) - res, err = c.GetValueNotWait("namespace") + res = c.GetValueImmediately("namespace") Assert(t, res, Equal("config")) - Assert(t, err, Equal(nil)) +} + +func TestGetConfigImmediately(t *testing.T) { + configurations := make(map[string]interface{}) + configurations["string"] = "string2" + configurations["int"] = 2 + configurations["float"] = 1.9 + configurations["bool"] = false + configurations["sliceString"] = []string{"1", "2", "3"} + configurations["sliceInt"] = []int{1, 2, 3} + configurations["sliceInter"] = []interface{}{1, "2", 3} + c := creatTestApolloConfig(configurations, "test") + config := c.GetConfig("test") + Assert(t, config, NotNilVal()) + + // string + s := config.GetStringValueImmediately("string", "s") + Assert(t, s, Equal(configurations["string"])) + + s = config.GetStringValueImmediately("s", "s") + Assert(t, s, Equal("s")) + + // int + i := config.GetIntValueImmediately("int", 3) + Assert(t, i, Equal(2)) + i = config.GetIntValueImmediately("i", 3) + Assert(t, i, Equal(3)) + + // float + f := config.GetFloatValueImmediately("float", 2) + Assert(t, f, Equal(1.9)) + f = config.GetFloatValueImmediately("f", 2) + Assert(t, f, Equal(float64(2))) + + // bool + b := config.GetBoolValueImmediately("bool", true) + Assert(t, b, Equal(false)) + + b = config.GetBoolValueImmediately("b", false) + Assert(t, b, Equal(false)) + + slice := config.GetStringSliceValueImmediately("sliceString", []string{}) + Assert(t, slice, Equal([]string{"1", "2", "3"})) + + sliceInt := config.GetIntSliceValueImmediately("sliceInt", []int{}) + Assert(t, sliceInt, Equal([]int{1, 2, 3})) + + sliceInter := config.GetSliceValueImmediately("sliceInter", []interface{}{}) + Assert(t, sliceInter, Equal([]interface{}{1, "2", 3})) } From 4e2cc88acb23939f39fcb91b266ce9a84f09ae67 Mon Sep 17 00:00:00 2001 From: weihaoyu <444216978@qq.com> Date: Mon, 16 May 2022 11:27:13 +0800 Subject: [PATCH 09/11] apidoc --- storage/repository.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/storage/repository.go b/storage/repository.go index 5efd51f..52422b8 100644 --- a/storage/repository.go +++ b/storage/repository.go @@ -150,7 +150,7 @@ func (c *Config) GetValueImmediately(key string) string { return v } -// GetStringValueImmediately 获取配置值(string),获取不到则取默认值,立即返回,初始化未完成直接返回错误 +// GetStringValueImmediately 获取配置值(string),立即返回,初始化未完成直接返回错误 func (c *Config) GetStringValueImmediately(key string, defaultValue string) string { value := c.GetValueImmediately(key) if value == utils.Empty { From ad5176637cc8cf11fc37912c60689ec173810a5f Mon Sep 17 00:00:00 2001 From: weihaoyu <444216978@qq.com> Date: Tue, 17 May 2022 13:40:39 +0800 Subject: [PATCH 10/11] change go.sum --- go.sum | 1 - 1 file changed, 1 deletion(-) diff --git a/go.sum b/go.sum index 18af665..3dfc818 100644 --- a/go.sum +++ b/go.sum @@ -129,7 +129,6 @@ github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FI github.com/pelletier/go-toml v1.2.0 h1:T5zMGML61Wp+FlcbWjRDT7yAxhJNAiPPLOFECq181zc= github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= From c3eb3db82bfbf5fc750fb2167c69fe336eb478f8 Mon Sep 17 00:00:00 2001 From: Joe Zou Date: Wed, 18 May 2022 23:41:50 +0800 Subject: [PATCH 11/11] =?UTF-8?q?[Fix]=20=E4=BF=AE=E5=A4=8D=20changeListen?= =?UTF-8?q?ers=20=E7=9A=84=20data=20race=20=E9=97=AE=E9=A2=98=20=20(#231)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * add lock for the operation of changeListeners * fix mutex --- storage/repository.go | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/storage/repository.go b/storage/repository.go index 52422b8..957ba20 100644 --- a/storage/repository.go +++ b/storage/repository.go @@ -44,6 +44,7 @@ const ( type Cache struct { apolloConfigCache sync.Map changeListeners *list.List + rw sync.RWMutex } // GetConfig 根据namespace获取apollo配置 @@ -497,6 +498,8 @@ func (c *Cache) AddChangeListener(listener ChangeListener) { if listener == nil { return } + c.rw.Lock() + defer c.rw.Unlock() c.changeListeners.PushBack(listener) } @@ -505,6 +508,8 @@ func (c *Cache) RemoveChangeListener(listener ChangeListener) { if listener == nil { return } + c.rw.Lock() + defer c.rw.Unlock() for i := c.changeListeners.Front(); i != nil; i = i.Next() { apolloListener := i.Value.(ChangeListener) if listener == apolloListener { @@ -515,7 +520,14 @@ func (c *Cache) RemoveChangeListener(listener ChangeListener) { // GetChangeListeners 获取配置修改监听器列表 func (c *Cache) GetChangeListeners() *list.List { - return c.changeListeners + if c.changeListeners == nil { + return nil + } + c.rw.RLock() + defer c.rw.RUnlock() + l := list.New() + l.PushBackList(c.changeListeners) + return l } // push config change event @@ -538,11 +550,12 @@ func (c *Cache) pushNewestChanges(namespace string, configuration map[string]int func (c *Cache) pushChange(f func(ChangeListener)) { // if channel is null ,mean no listener,don't need to push msg - if c.changeListeners == nil || c.changeListeners.Len() == 0 { + listeners := c.GetChangeListeners() + if listeners == nil || listeners.Len() == 0 { return } - for i := c.changeListeners.Front(); i != nil; i = i.Next() { + for i := listeners.Front(); i != nil; i = i.Next() { listener := i.Value.(ChangeListener) f(listener) }