MM-28859 Add feature flag managment system using split.io and remove viper. (#15954)
* Add feature flag managment system using split.io and remove viper. * Fixing tests. * Attempt to fix postgres tests. * Fix watch filepath for advanced logging. * Review fixes. * Some error wrapping. * Remove unessisary store interface. * Desanitize SplitKey * Simplify. * Review feedback. * Rename split mlog adatper to split logger. * fsInner * Style. * Restore oldcfg test. * Downgrading non-actionable feature flag errors to warnings. Co-authored-by: Mattermod <mattermod@users.noreply.github.com>
Этот коммит содержится в:
коммит произвёл
GitHub
родитель
8bb772638c
Коммит
1aadd36644
@@ -15,6 +15,7 @@ import (
|
||||
"os"
|
||||
"os/exec"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
@@ -127,7 +128,7 @@ type Server struct {
|
||||
searchConfigListenerId string
|
||||
searchLicenseListenerId string
|
||||
loggerLicenseListenerId string
|
||||
configStore config.Store
|
||||
configStore *config.Store
|
||||
asymmetricSigningKey *ecdsa.PrivateKey
|
||||
postActionCookieSecret []byte
|
||||
|
||||
@@ -178,6 +179,11 @@ type Server struct {
|
||||
// and data corruption.
|
||||
uploadLockMapMut sync.Mutex
|
||||
uploadLockMap map[string]bool
|
||||
|
||||
featureFlagSynchronizer *config.FeatureFlagSynchronizer
|
||||
featureFlagStop chan struct{}
|
||||
featureFlagStopped chan struct{}
|
||||
featureFlagSynchronizerMutex sync.Mutex
|
||||
}
|
||||
|
||||
func NewServer(options ...Option) (*Server, error) {
|
||||
@@ -200,7 +206,11 @@ func NewServer(options ...Option) (*Server, error) {
|
||||
}
|
||||
|
||||
if s.configStore == nil {
|
||||
configStore, err := config.NewFileStore("config.json", true)
|
||||
innerStore, err := config.NewFileStore("config.json", true)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to load config")
|
||||
}
|
||||
configStore, err := config.NewStoreFromBacking(innerStore)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to load config")
|
||||
}
|
||||
@@ -292,27 +302,6 @@ func NewServer(options ...Option) (*Server, error) {
|
||||
return nil, errors.Wrapf(err, "unable to load Mattermost translation files")
|
||||
}
|
||||
|
||||
s.configListenerId = s.AddConfigListener(func(_, _ *model.Config) {
|
||||
s.configOrLicenseListener()
|
||||
|
||||
message := model.NewWebSocketEvent(model.WEBSOCKET_EVENT_CONFIG_CHANGED, "", "", "", nil)
|
||||
|
||||
message.Add("config", s.ClientConfigWithComputed())
|
||||
s.Go(func() {
|
||||
s.Publish(message)
|
||||
})
|
||||
})
|
||||
s.licenseListenerId = s.AddLicenseListener(func(oldLicense, newLicense *model.License) {
|
||||
s.configOrLicenseListener()
|
||||
|
||||
message := model.NewWebSocketEvent(model.WEBSOCKET_EVENT_LICENSE_CHANGED, "", "", "", nil)
|
||||
message.Add("license", s.GetSanitizedClientLicense())
|
||||
s.Go(func() {
|
||||
s.Publish(message)
|
||||
})
|
||||
|
||||
})
|
||||
|
||||
s.initEnterprise()
|
||||
|
||||
if s.newStore == nil {
|
||||
@@ -353,6 +342,27 @@ func NewServer(options ...Option) (*Server, error) {
|
||||
|
||||
s.Store = s.newStore()
|
||||
|
||||
s.configListenerId = s.AddConfigListener(func(_, _ *model.Config) {
|
||||
s.configOrLicenseListener()
|
||||
|
||||
message := model.NewWebSocketEvent(model.WEBSOCKET_EVENT_CONFIG_CHANGED, "", "", "", nil)
|
||||
|
||||
message.Add("config", s.ClientConfigWithComputed())
|
||||
s.Go(func() {
|
||||
s.Publish(message)
|
||||
})
|
||||
})
|
||||
s.licenseListenerId = s.AddLicenseListener(func(oldLicense, newLicense *model.License) {
|
||||
s.configOrLicenseListener()
|
||||
|
||||
message := model.NewWebSocketEvent(model.WEBSOCKET_EVENT_LICENSE_CHANGED, "", "", "", nil)
|
||||
message.Add("license", s.GetSanitizedClientLicense())
|
||||
s.Go(func() {
|
||||
s.Publish(message)
|
||||
})
|
||||
|
||||
})
|
||||
|
||||
s.telemetryService = telemetry.New(s, s.Store, s.SearchEngine, s.Log)
|
||||
|
||||
emailService, err := NewEmailService(s)
|
||||
@@ -365,8 +375,18 @@ func NewServer(options ...Option) (*Server, error) {
|
||||
s.LoadLicense()
|
||||
}
|
||||
|
||||
s.setupFeatureFlags()
|
||||
|
||||
s.initJobs()
|
||||
|
||||
s.clusterLeaderListenerId = s.AddClusterLeaderChangedListener(func() {
|
||||
mlog.Info("Cluster leader changed. Determining if job schedulers should be running:", mlog.Bool("isLeader", s.IsLeader()))
|
||||
if s.Jobs != nil && s.Jobs.Schedulers != nil {
|
||||
s.Jobs.Schedulers.HandleClusterLeaderChange(s.IsLeader())
|
||||
}
|
||||
s.setupFeatureFlags()
|
||||
})
|
||||
|
||||
if s.joinCluster && s.Cluster != nil {
|
||||
s.Cluster.StartInterNodeCommunication()
|
||||
}
|
||||
@@ -389,13 +409,6 @@ func NewServer(options ...Option) (*Server, error) {
|
||||
|
||||
s.regenerateClientConfig()
|
||||
|
||||
s.clusterLeaderListenerId = s.AddClusterLeaderChangedListener(func() {
|
||||
mlog.Info("Cluster leader changed. Determining if job schedulers should be running:", mlog.Bool("isLeader", s.IsLeader()))
|
||||
if s.Jobs != nil && s.Jobs.Schedulers != nil {
|
||||
s.Jobs.Schedulers.HandleClusterLeaderChange(s.IsLeader())
|
||||
}
|
||||
})
|
||||
|
||||
subpath, err := utils.GetSubpathFromConfig(s.Config())
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to parse SiteURL subpath")
|
||||
@@ -480,7 +493,6 @@ func NewServer(options ...Option) (*Server, error) {
|
||||
s.checkPushNotificationServerUrl()
|
||||
|
||||
license := s.License()
|
||||
|
||||
if license == nil {
|
||||
s.UpdateConfig(func(cfg *model.Config) {
|
||||
cfg.TeamSettings.MaxNotificationsPerChannel = &MaxNotificationsPerChannelDefault
|
||||
@@ -618,10 +630,9 @@ func (s *Server) initLogging() error {
|
||||
isJson := config.IsJsonMap(dsn)
|
||||
|
||||
// If this is a file based config we need the full path so it can be watched.
|
||||
if !isJson {
|
||||
if fs, ok := s.configStore.(*config.FileStore); ok {
|
||||
dsn = fs.GetFilePath(dsn)
|
||||
}
|
||||
if !isJson && strings.HasPrefix(s.configStore.String(), "file://") && !filepath.IsAbs(dsn) {
|
||||
configPath := strings.TrimPrefix(s.configStore.String(), "file://")
|
||||
dsn = filepath.Join(filepath.Dir(configPath), dsn)
|
||||
}
|
||||
|
||||
cfg, err := config.NewLogConfigSrc(dsn, isJson, s.configStore)
|
||||
@@ -752,6 +763,8 @@ func (s *Server) Shutdown() error {
|
||||
|
||||
s.Audit.Shutdown()
|
||||
|
||||
s.stopFeatureFlagUpdateJob()
|
||||
|
||||
s.configStore.Close()
|
||||
|
||||
if s.Cluster != nil {
|
||||
|
||||
Ссылка в новой задаче
Block a user