Plugins: Enable feature toggle pluginsDynamicAngularDetectionPatterns by default (#84723)

* Enable feature toggle pluginsDynamicAngularDetectionPatterns by default

* Change backgroundJobInterval to 24h

* re-generate feature toggles

* Use different intervals for cloud vs on-prem

* temporarily switch interval log to info level

* debug level again

* Simplify provideDynamic for tests

* re-generated feature toggles files

* PR review feedback

* PR review feedback: removed dependency from plugin management config
This commit is contained in:
Giuseppe Guerra
2024-03-21 17:22:06 +01:00
committed by GitHub
parent 6c1de260a2
commit eb31f71f60
7 changed files with 106 additions and 66 deletions

View File

@@ -510,9 +510,10 @@ var (
{
Name: "pluginsDynamicAngularDetectionPatterns",
Description: "Enables fetching Angular detection patterns for plugins from GCOM and fallback to hardcoded ones",
Stage: FeatureStageExperimental,
Stage: FeatureStageGeneralAvailability,
FrontendOnly: false,
Owner: grafanaPluginsPlatformSquad,
Expression: "true", // enabled by default
},
{
Name: "vizAndWidgetSplit",

View File

@@ -67,7 +67,7 @@ frontendSandboxMonitorOnly,experimental,@grafana/plugins-platform-backend,false,
sqlDatasourceDatabaseSelection,preview,@grafana/dataviz-squad,false,false,true
lokiFormatQuery,experimental,@grafana/observability-logs,false,false,true
recordedQueriesMulti,GA,@grafana/observability-metrics,false,false,false
pluginsDynamicAngularDetectionPatterns,experimental,@grafana/plugins-platform-backend,false,false,false
pluginsDynamicAngularDetectionPatterns,GA,@grafana/plugins-platform-backend,false,false,false
vizAndWidgetSplit,experimental,@grafana/dashboards-squad,false,false,true
prometheusIncrementalQueryInstrumentation,experimental,@grafana/observability-metrics,false,false,true
logsExploreTableVisualisation,GA,@grafana/observability-logs,false,false,true
1 Name Stage Owner requiresDevMode RequiresRestart FrontendOnly
67 sqlDatasourceDatabaseSelection preview @grafana/dataviz-squad false false true
68 lokiFormatQuery experimental @grafana/observability-logs false false true
69 recordedQueriesMulti GA @grafana/observability-metrics false false false
70 pluginsDynamicAngularDetectionPatterns experimental GA @grafana/plugins-platform-backend false false false
71 vizAndWidgetSplit experimental @grafana/dashboards-squad false false true
72 prometheusIncrementalQueryInstrumentation experimental @grafana/observability-metrics false false true
73 logsExploreTableVisualisation GA @grafana/observability-logs false false true

View File

@@ -441,12 +441,15 @@
{
"metadata": {
"name": "pluginsDynamicAngularDetectionPatterns",
"resourceVersion": "1709648236447",
"creationTimestamp": "2024-03-05T14:17:16Z"
"resourceVersion": "1710847676897",
"creationTimestamp": "2024-03-05T14:17:16Z",
"annotations": {
"grafana.app/updatedTimestamp": "2024-03-19 11:27:56.897962695 +0000 UTC"
}
},
"spec": {
"description": "Enables fetching Angular detection patterns for plugins from GCOM and fallback to hardcoded ones",
"stage": "experimental",
"stage": "GA",
"codeowner": "@grafana/plugins-platform-backend"
}
},

View File

@@ -12,18 +12,21 @@ import (
"sync"
"time"
"github.com/grafana/grafana/pkg/plugins/config"
"github.com/grafana/grafana/pkg/plugins/log"
"github.com/grafana/grafana/pkg/plugins/manager/loader/angular/angulardetector"
"github.com/grafana/grafana/pkg/services/featuremgmt"
"github.com/grafana/grafana/pkg/services/pluginsintegration/angularpatternsstore"
"github.com/grafana/grafana/pkg/setting"
)
var errNotModified = errors.New("not modified")
// backgroundJobInterval is the interval that passes between background job runs.
// It can be overwritten in tests.
var backgroundJobInterval = time.Hour * 1
// Intervals that passes between background job runs.
// Can be overwritten in tests.
var (
backgroundJobIntervalOnPrem = time.Hour * 24
backgroundJobIntervalCloud = time.Hour * 1
)
// Dynamic is an angulardetector.DetectorsProvider that calls GCOM to get Angular detection patterns,
// converts them to detectors and caches them for all future calls.
@@ -45,20 +48,32 @@ type Dynamic struct {
// mux is the mutex used to read/write the cached detectors in a concurrency-safe way.
mux sync.RWMutex
// backgroundJobInterval is the interval that passes between background job runs.
backgroundJobInterval time.Duration
}
func ProvideDynamic(cfg *config.PluginManagementCfg, store angularpatternsstore.Service, features featuremgmt.FeatureToggles) (*Dynamic, error) {
func ProvideDynamic(cfg *setting.Cfg, store angularpatternsstore.Service, features featuremgmt.FeatureToggles) (*Dynamic, error) {
backgroundJobInterval := backgroundJobIntervalOnPrem
if cfg.StackID != "" {
// Use a shorter interval for cloud.
// (in cloud, cfg.StackID is always set).
backgroundJobInterval = backgroundJobIntervalCloud
}
d := &Dynamic{
log: log.New("plugin.angulardetectorsprovider.dynamic"),
features: features,
store: store,
httpClient: makeHttpClient(),
baseURL: cfg.GrafanaComURL,
log: log.New("plugin.angulardetectorsprovider.dynamic"),
features: features,
store: store,
httpClient: makeHttpClient(),
baseURL: cfg.GrafanaComURL,
backgroundJobInterval: backgroundJobInterval,
}
if d.IsDisabled() {
// Do not attempt to restore if the background service is disabled (no feature flag)
return d, nil
}
d.log.Debug("Providing dynamic angular detection patterns", "baseURL", d.baseURL, "interval", d.backgroundJobInterval)
// Perform the initial restore from db
st := time.Now()
@@ -224,7 +239,7 @@ func (d *Dynamic) IsDisabled() bool {
}
// randomSkew returns a random time.Duration between 0 and maxSkew.
// This can be added to backgroundJobInterval to skew it by a random amount.
// This can be added to d.backgroundJobInterval to skew it by a random amount.
func (d *Dynamic) randomSkew(maxSkew time.Duration) time.Duration {
return time.Duration(rand.Float64() * float64(maxSkew))
}
@@ -242,15 +257,15 @@ func (d *Dynamic) Run(ctx context.Context) error {
// Offset the background job interval a bit to skew GCOM calls from all instances,
// so GCOM is not overwhelmed with lots of requests all at the same time.
// Important when lots of HG instances restart at the same time.
skew := d.randomSkew(backgroundJobInterval / 4)
backgroundJobInterval += skew
skew := d.randomSkew(d.backgroundJobInterval / 4)
d.backgroundJobInterval += skew
d.log.Debug(
"Applied background job skew",
"skew", backgroundJobInterval, "interval", backgroundJobInterval,
"skew", d.backgroundJobInterval, "interval", d.backgroundJobInterval,
)
nextRunUntil := time.Until(lastUpdate.Add(backgroundJobInterval))
ticker := time.NewTicker(backgroundJobInterval)
nextRunUntil := time.Until(lastUpdate.Add(d.backgroundJobInterval))
ticker := time.NewTicker(d.backgroundJobInterval)
defer ticker.Stop()
var tick <-chan time.Time
@@ -286,7 +301,7 @@ func (d *Dynamic) Run(ctx context.Context) error {
d.log.Info("Patterns update finished", "duration", time.Since(st))
// Restore default ticker if we run with a shorter interval the first time
ticker.Reset(backgroundJobInterval)
ticker.Reset(d.backgroundJobInterval)
tick = ticker.C
case <-ctx.Done():
return ctx.Err()

View File

@@ -14,10 +14,10 @@ import (
"github.com/stretchr/testify/require"
"github.com/grafana/grafana/pkg/infra/kvstore"
"github.com/grafana/grafana/pkg/plugins/config"
"github.com/grafana/grafana/pkg/plugins/manager/loader/angular/angulardetector"
"github.com/grafana/grafana/pkg/services/featuremgmt"
"github.com/grafana/grafana/pkg/services/pluginsintegration/angularpatternsstore"
"github.com/grafana/grafana/pkg/setting"
)
func TestDynamicAngularDetectorsProvider(t *testing.T) {
@@ -314,6 +314,22 @@ func TestDynamicAngularDetectorsProvider(t *testing.T) {
})
}
func TestDynamicAngularDetectorsProviderCloudVsOnPrem(t *testing.T) {
gcom := newDefaultGCOMScenario()
srv := gcom.newHTTPTestServer()
t.Cleanup(srv.Close)
t.Run("should use cloud interval if stack_id is set", func(t *testing.T) {
svc := provideDynamic(t, srv.URL, provideDynamicOpts{cfg: &setting.Cfg{StackID: "1234"}})
require.Equal(t, backgroundJobIntervalCloud, svc.backgroundJobInterval)
})
t.Run("should use on-prem interval if stack_id is not set", func(t *testing.T) {
svc := provideDynamic(t, srv.URL, provideDynamicOpts{cfg: &setting.Cfg{StackID: ""}})
require.Equal(t, backgroundJobIntervalOnPrem, svc.backgroundJobInterval)
})
}
func TestDynamicAngularDetectorsProviderBackgroundService(t *testing.T) {
mockGCOMPatterns := newMockGCOMPatterns()
gcom := newDefaultGCOMScenario()
@@ -321,10 +337,10 @@ func TestDynamicAngularDetectorsProviderBackgroundService(t *testing.T) {
t.Cleanup(srv.Close)
t.Run("background service", func(t *testing.T) {
oldBackgroundJobInterval := backgroundJobInterval
backgroundJobInterval = time.Millisecond * 500
oldBackgroundJobInterval := backgroundJobIntervalOnPrem
backgroundJobIntervalOnPrem = time.Millisecond * 500
t.Cleanup(func() {
backgroundJobInterval = oldBackgroundJobInterval
backgroundJobIntervalOnPrem = oldBackgroundJobInterval
})
t.Run("is disabled if feature flag is not present", func(t *testing.T) {
@@ -563,6 +579,7 @@ func newError500GCOMScenario() *gcomScenario {
type provideDynamicOpts struct {
store angularpatternsstore.Service
cfg *setting.Cfg
}
func provideDynamic(t *testing.T, gcomURL string, opts ...provideDynamicOpts) *Dynamic {
@@ -573,8 +590,12 @@ func provideDynamic(t *testing.T, gcomURL string, opts ...provideDynamicOpts) *D
if opt.store == nil {
opt.store = angularpatternsstore.ProvideService(kvstore.NewFakeKVStore())
}
if opt.cfg == nil {
opt.cfg = setting.NewCfg()
}
opt.cfg.GrafanaComURL = gcomURL
d, err := ProvideDynamic(
&config.PluginManagementCfg{GrafanaComURL: gcomURL},
opt.cfg,
opt.store,
featuremgmt.WithFeatures(featuremgmt.FlagPluginsDynamicAngularDetectionPatterns),
)

View File

@@ -7,19 +7,19 @@ import (
"github.com/stretchr/testify/require"
"github.com/grafana/grafana/pkg/infra/kvstore"
"github.com/grafana/grafana/pkg/plugins/config"
"github.com/grafana/grafana/pkg/plugins/manager/loader/angular/angulardetector"
"github.com/grafana/grafana/pkg/plugins/manager/loader/angular/angularinspector"
"github.com/grafana/grafana/pkg/services/featuremgmt"
"github.com/grafana/grafana/pkg/services/pluginsintegration/angulardetectorsprovider"
"github.com/grafana/grafana/pkg/services/pluginsintegration/angularpatternsstore"
"github.com/grafana/grafana/pkg/setting"
)
func TestProvideService(t *testing.T) {
t.Run("uses hardcoded inspector if feature flag is not present", func(t *testing.T) {
features := featuremgmt.WithFeatures()
dynamic, err := angulardetectorsprovider.ProvideDynamic(
&config.PluginManagementCfg{},
setting.NewCfg(),
angularpatternsstore.ProvideService(kvstore.NewFakeKVStore()),
features,
)
@@ -37,7 +37,7 @@ func TestProvideService(t *testing.T) {
featuremgmt.FlagPluginsDynamicAngularDetectionPatterns,
)
dynamic, err := angulardetectorsprovider.ProvideDynamic(
&config.PluginManagementCfg{},
setting.NewCfg(),
angularpatternsstore.ProvideService(kvstore.NewFakeKVStore()),
features,
)