Skip to content

Commit 5ca3730

Browse files
authored
refactor: fightThreshold global variable (#1815)
* Adds DefaultFightThreshold to register.go * Adds fightThreshold member to the Detector struct
1 parent e675841 commit 5ca3730

File tree

7 files changed

+31
-29
lines changed

7 files changed

+31
-29
lines changed

cmd/reconciler/main.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ var (
7171
hydratedLinkDir = flag.String("hydrated-link", "rev",
7272
"The name of (a symlink to) the source directory under --hydrated-root, which contains the hydrated configs")
7373
fightDetectionThreshold = flag.Float64(
74-
"fight-detection-threshold", 5.0,
74+
"fight-detection-threshold", configsync.DefaultFightThreshold,
7575
"The rate of updates per minute to an API Resource at which the Syncer logs warnings about too many updates to the resource.")
7676
fullSyncPeriod = flag.Duration("full-sync-period", configsync.DefaultReconcilerFullSyncPeriod,
7777
"Period of time between forced re-syncs from source (even without a new commit).")

e2e/testcases/remediator_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ func TestSurfaceFightError(t *testing.T) {
5656
nt.Must(nomostest.ValidateMetrics(nt,
5757
nomostest.ReconcilerErrorMetrics(nt, rootSyncLabels, commitHash, metrics.ErrorSummary{})))
5858

59-
// Make the # of updates exceed the fightThreshold defined in pkg/syncer/reconcile/fight_detector.go
59+
// Make the # of updates exceed the DefaultFightThreshold defined in pkg/api/configsync/register.go
6060
ctx, cancel := context.WithCancel(t.Context())
6161
nt.T.Cleanup(func() {
6262
cancel() // cancel in case an assertion failed early

pkg/api/configsync/register.go

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,17 @@ const (
9090

9191
// DefaultHelmReleaseNamespace is the default namespace for a Helm Release which does not have a namespace specified
9292
DefaultHelmReleaseNamespace = "default"
93+
94+
// DefaultFightThreshold is the default threshold of updates per minute to a
95+
// resource before Config Sync reports a fight. A fight occurs when the
96+
// Remediator and another process are both trying to manage the same
97+
// resource.
98+
// When a fight is detected, an error is logged, surfaced in the
99+
// RSync status, and emitted as a metric.
100+
// This value was chosen because a resource being updated more than 5 times
101+
// per minute is a clear sign of a problem, while less frequent updates are
102+
// unlikely to be fights.
103+
DefaultFightThreshold = 5.0
93104
)
94105

95106
// SourceFormat specifies how the Importer should parse the repository.

pkg/reconciler/reconciler.go

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -149,7 +149,6 @@ type RootOptions struct {
149149
func Run(opts Options) {
150150
// Start listening to signals
151151
signalCtx := signals.SetupSignalHandler()
152-
fight.SetFightThreshold(opts.FightDetectionThreshold)
153152

154153
// Get a config to talk to the apiserver.
155154
apiServerTimeout, err := time.ParseDuration(opts.APIServerTimeout)
@@ -190,7 +189,7 @@ func Run(opts Options) {
190189
// Configure the Applier.
191190
applySetID := applyset.IDFromSync(opts.SyncName, opts.ReconcilerScope)
192191
genericClient := syncerclient.New(cl, metrics.APICallDuration)
193-
baseApplier, err := reconcile.NewApplierForMultiRepo(cfg, genericClient, applySetID)
192+
baseApplier, err := reconcile.NewApplierForMultiRepo(cfg, genericClient, applySetID, opts.FightDetectionThreshold)
194193
if err != nil {
195194
klog.Fatalf("Instantiating Applier: %v", err)
196195
}

pkg/syncer/reconcile/apply.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -75,11 +75,11 @@ type clientApplier struct {
7575
var _ Applier = &clientApplier{}
7676

7777
// NewApplierForMultiRepo returns a new clientApplier for callers with multi repo feature enabled.
78-
func NewApplierForMultiRepo(cfg *rest.Config, client *syncerclient.Client, applySetID string) (Applier, error) {
79-
return newApplier(cfg, client, applySetID)
78+
func NewApplierForMultiRepo(cfg *rest.Config, client *syncerclient.Client, applySetID string, fightThreshold float64) (Applier, error) {
79+
return newApplier(cfg, client, applySetID, fightThreshold)
8080
}
8181

82-
func newApplier(cfg *rest.Config, client *syncerclient.Client, applySetID string) (Applier, error) {
82+
func newApplier(cfg *rest.Config, client *syncerclient.Client, applySetID string, fightThreshold float64) (Applier, error) {
8383
c, err := dynamic.NewForConfig(cfg)
8484
if err != nil {
8585
return nil, err
@@ -100,7 +100,7 @@ func newApplier(cfg *rest.Config, client *syncerclient.Client, applySetID string
100100
discoveryClient: dc,
101101
openAPIResources: oa,
102102
client: client,
103-
fights: fight.NewDetector(),
103+
fights: fight.NewDetector(fightThreshold),
104104
applySetID: applySetID,
105105
}, nil
106106
}

pkg/syncer/reconcile/fight/detector.go

Lines changed: 10 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -24,20 +24,6 @@ import (
2424
"sigs.k8s.io/controller-runtime/pkg/client"
2525
)
2626

27-
// fightThreshold is the threshold of updates per minute at which we log to Info
28-
// that the Syncer is fighting over a resource on the API Server with some
29-
// other process.
30-
//
31-
// This value was chosen arbitrarily as updates occurring more frequently are
32-
// obviously problems, and we don't really care about less frequent updates.
33-
var fightThreshold = 5.0
34-
35-
// SetFightThreshold updates the maximum allowed rate of updates to a resource
36-
// per minute before we begin logging errors to the user.
37-
func SetFightThreshold(updatesPerMinute float64) {
38-
fightThreshold = updatesPerMinute
39-
}
40-
4127
// Detector uses a linear differential equation to estimate the frequency
4228
// of updates to resources, then logs to klog.Warning when it detects resources
4329
// needing updates too frequently.
@@ -59,13 +45,18 @@ type Detector struct {
5945
fights map[core.ID]*fight
6046

6147
fLogger *logger
48+
49+
// fightThreshold is the maximum allowed rate of updates to a resource
50+
// per minute before errors are logged to the user, surfaced on the RSync status and emitted as a metric
51+
fightThreshold float64
6252
}
6353

6454
// NewDetector instantiates a fight detector.
65-
func NewDetector() Detector {
55+
func NewDetector(threshold float64) Detector {
6656
return Detector{
67-
fights: make(map[core.ID]*fight),
68-
fLogger: newLogger(),
57+
fights: make(map[core.ID]*fight),
58+
fLogger: newLogger(),
59+
fightThreshold: threshold,
6960
}
7061
}
7162

@@ -79,14 +70,14 @@ func (d *Detector) DetectFight(now time.Time, obj client.Object) (bool, status.R
7970
if d.fights[id] == nil {
8071
d.fights[id] = &fight{}
8172
}
82-
if frequency := d.fights[id].refreshUpdateFrequency(now); frequency >= fightThreshold {
73+
if frequency := d.fights[id].refreshUpdateFrequency(now); frequency >= d.fightThreshold {
8374
fightErr := status.FightError(frequency, obj)
8475
return d.fLogger.logFight(now, fightErr), fightErr
8576
}
8677
return false, nil
8778
}
8879

89-
// fight estimates how often a specific API resource is updated by the Syncer.
80+
// fight estimates how often a specific API resource is updated by the Remediator.
9081
type fight struct {
9182
// heat is an estimate of the number of times a resource is updated per minute.
9283
// It decays exponentially with time when there are no updates to a resource.

pkg/syncer/reconcile/fight/detector_test.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,7 @@ func TestFight(t *testing.T) {
110110

111111
for _, tc := range testCases {
112112
t.Run(tc.name, func(t *testing.T) {
113+
fightThreshold := 5.0
113114
now := time.Now()
114115
f := fight{
115116
heat: tc.startHeat,
@@ -185,7 +186,7 @@ func TestFightDetector(t *testing.T) {
185186

186187
for _, tc := range testCases {
187188
t.Run(tc.name, func(t *testing.T) {
188-
fd := NewDetector()
189+
fd := NewDetector(5.0)
189190

190191
now := time.Now()
191192
for id, updates := range tc.updates {
@@ -195,7 +196,7 @@ func TestFightDetector(t *testing.T) {
195196
logged := false
196197
for i, update := range updates {
197198
logErr, fightErr := fd.DetectFight(now.Add(update), u)
198-
if i+1 >= int(fightThreshold) {
199+
if i+1 >= int(fd.fightThreshold) {
199200
require.Error(t, fightErr)
200201
aboveThreshold = true
201202
if logged {

0 commit comments

Comments
 (0)