Add cloud attributes to feature flags and allow non-cloud servers to use split.io sync (#17028)
* Add cloud installation and group id to feature flag attributes * Add some debug lines * Allow non-cloud servers to use split.io for feature flag management
Этот коммит содержится в:
коммит произвёл
GitHub
родитель
4ad29c3a8d
Коммит
d9484d6ba9
@@ -4,6 +4,8 @@
|
|||||||
package app
|
package app
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"os"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/mattermost/mattermost-server/v5/config"
|
"github.com/mattermost/mattermost-server/v5/config"
|
||||||
@@ -15,16 +17,15 @@ import (
|
|||||||
func (s *Server) setupFeatureFlags() {
|
func (s *Server) setupFeatureFlags() {
|
||||||
s.featureFlagSynchronizerMutex.Lock()
|
s.featureFlagSynchronizerMutex.Lock()
|
||||||
defer s.featureFlagSynchronizerMutex.Unlock()
|
defer s.featureFlagSynchronizerMutex.Unlock()
|
||||||
license := s.License()
|
|
||||||
inCloud := license != nil && *license.Features.Cloud
|
|
||||||
splitKey := *s.Config().ServiceSettings.SplitKey
|
splitKey := *s.Config().ServiceSettings.SplitKey
|
||||||
syncFeatureFlags := inCloud && splitKey != "" && s.IsLeader()
|
splitConfigured := splitKey != ""
|
||||||
|
syncFeatureFlags := splitConfigured && s.IsLeader()
|
||||||
|
|
||||||
s.configStore.PersistFeatures(inCloud)
|
s.configStore.PersistFeatures(splitConfigured)
|
||||||
|
|
||||||
if syncFeatureFlags {
|
if syncFeatureFlags {
|
||||||
if err := s.startFeatureFlagUpdateJob(); err != nil {
|
if err := s.startFeatureFlagUpdateJob(); err != nil {
|
||||||
s.Log.Warn("Unable to setup synchronization with feature flag management. Will fallback to cloud cache.", mlog.Err(err))
|
s.Log.Warn("Unable to setup synchronization with feature flag management. Will fallback to cache.", mlog.Err(err))
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
s.stopFeatureFlagUpdateJob()
|
s.stopFeatureFlagUpdateJob()
|
||||||
@@ -39,7 +40,11 @@ func (s *Server) updateFeatureFlagValuesFromManagment() {
|
|||||||
newCfg := s.configStore.GetNoEnv().Clone()
|
newCfg := s.configStore.GetNoEnv().Clone()
|
||||||
oldFlags := *newCfg.FeatureFlags
|
oldFlags := *newCfg.FeatureFlags
|
||||||
newFlags := s.featureFlagSynchronizer.UpdateFeatureFlagValues(oldFlags)
|
newFlags := s.featureFlagSynchronizer.UpdateFeatureFlagValues(oldFlags)
|
||||||
|
oldFlagsBytes, _ := json.Marshal(oldFlags)
|
||||||
|
newFlagsBytes, _ := json.Marshal(newFlags)
|
||||||
|
s.Log.Debug("Checking feature flags from management service", mlog.String("old_flags", string(oldFlagsBytes)), mlog.String("new_flags", string(newFlagsBytes)))
|
||||||
if oldFlags != newFlags {
|
if oldFlags != newFlags {
|
||||||
|
s.Log.Debug("Feature flag change detected, updating config")
|
||||||
*newCfg.FeatureFlags = newFlags
|
*newCfg.FeatureFlags = newFlags
|
||||||
s.SaveConfig(newCfg, true)
|
s.SaveConfig(newCfg, true)
|
||||||
}
|
}
|
||||||
@@ -56,10 +61,21 @@ func (s *Server) startFeatureFlagUpdateJob() error {
|
|||||||
log = s.Log
|
log = s.Log
|
||||||
}
|
}
|
||||||
|
|
||||||
|
attributes := map[string]interface{}{}
|
||||||
|
|
||||||
|
// if we are part of a cloud installation, add its installation and group id
|
||||||
|
if installationId := os.Getenv("MM_CLOUD_INSTALLATION_ID"); installationId != "" {
|
||||||
|
attributes["installation_id"] = installationId
|
||||||
|
}
|
||||||
|
if groupId := os.Getenv("MM_CLOUD_GROUP_ID"); groupId != "" {
|
||||||
|
attributes["group_id"] = groupId
|
||||||
|
}
|
||||||
|
|
||||||
synchronizer, err := config.NewFeatureFlagSynchronizer(config.FeatureFlagSyncParams{
|
synchronizer, err := config.NewFeatureFlagSynchronizer(config.FeatureFlagSyncParams{
|
||||||
ServerID: s.TelemetryId(),
|
ServerID: s.TelemetryId(),
|
||||||
SplitKey: *s.Config().ServiceSettings.SplitKey,
|
SplitKey: *s.Config().ServiceSettings.SplitKey,
|
||||||
Log: log,
|
Log: log,
|
||||||
|
Attributes: attributes,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ type FeatureFlagSyncParams struct {
|
|||||||
SplitKey string
|
SplitKey string
|
||||||
SyncIntervalSeconds int
|
SyncIntervalSeconds int
|
||||||
Log *mlog.Logger
|
Log *mlog.Logger
|
||||||
|
Attributes map[string]interface{}
|
||||||
}
|
}
|
||||||
|
|
||||||
type FeatureFlagSynchronizer struct {
|
type FeatureFlagSynchronizer struct {
|
||||||
@@ -54,7 +55,7 @@ func NewFeatureFlagSynchronizer(params FeatureFlagSyncParams) (*FeatureFlagSynch
|
|||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// ensureReady blocks until the syncronizer is ready to update feature flag values
|
// EnsureReady blocks until the syncronizer is ready to update feature flag values
|
||||||
func (f *FeatureFlagSynchronizer) EnsureReady() error {
|
func (f *FeatureFlagSynchronizer) EnsureReady() error {
|
||||||
if err := f.client.BlockUntilReady(10); err != nil {
|
if err := f.client.BlockUntilReady(10); err != nil {
|
||||||
return errors.Wrap(err, "split.io client could not initialize")
|
return errors.Wrap(err, "split.io client could not initialize")
|
||||||
@@ -64,7 +65,7 @@ func (f *FeatureFlagSynchronizer) EnsureReady() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (f *FeatureFlagSynchronizer) UpdateFeatureFlagValues(base model.FeatureFlags) model.FeatureFlags {
|
func (f *FeatureFlagSynchronizer) UpdateFeatureFlagValues(base model.FeatureFlags) model.FeatureFlags {
|
||||||
featuresMap := f.client.Treatments(f.ServerID, featureNames, nil)
|
featuresMap := f.client.Treatments(f.ServerID, featureNames, f.Attributes)
|
||||||
ffm := featureFlagsFromMap(featuresMap, base)
|
ffm := featureFlagsFromMap(featuresMap, base)
|
||||||
return ffm
|
return ffm
|
||||||
}
|
}
|
||||||
|
|||||||
Ссылка в новой задаче
Block a user