1
0
Fork 0
mirror of https://github.com/arangodb/kube-arangodb.git synced 2024-12-14 11:57:37 +00:00

[Feature] Reconciliation Loop Interval option (#1395)

This commit is contained in:
Adam Janikowski 2023-09-02 02:17:01 +02:00 committed by GitHub
parent 9ad18931d1
commit ecb3482f34
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 175 additions and 1 deletions

View file

@ -11,6 +11,7 @@
- (Bugfix) Fix CRD yaml (chart) - (Bugfix) Fix CRD yaml (chart)
- (Bugfix) (EE) Fix MemberMaintenance Context and ClusterMaintenance discovery - (Bugfix) (EE) Fix MemberMaintenance Context and ClusterMaintenance discovery
- (Feature) Add proper Prometheus endpoint compression + 204 response code - (Feature) Add proper Prometheus endpoint compression + 204 response code
- (Feature) Reconciliation Loop Interval option
## [1.2.32](https://github.com/arangodb/kube-arangodb/tree/1.2.32) (2023-08-07) ## [1.2.32](https://github.com/arangodb/kube-arangodb/tree/1.2.32) (2023-08-07)
- (Feature) Backup lifetime - remove Backup once its lifetime has been reached - (Feature) Backup lifetime - remove Backup once its lifetime has been reached

View file

@ -136,6 +136,8 @@ var (
alpineImage, metricsExporterImage, arangoImage string alpineImage, metricsExporterImage, arangoImage string
reconciliationDelay time.Duration
singleMode bool singleMode bool
scope string scope string
} }
@ -224,6 +226,7 @@ func init() {
f.DurationVar(&shutdownOptions.delay, "shutdown.delay", defaultShutdownDelay, "The delay before running shutdown handlers") f.DurationVar(&shutdownOptions.delay, "shutdown.delay", defaultShutdownDelay, "The delay before running shutdown handlers")
f.DurationVar(&shutdownOptions.timeout, "shutdown.timeout", defaultShutdownTimeout, "Timeout for shutdown handlers") f.DurationVar(&shutdownOptions.timeout, "shutdown.timeout", defaultShutdownTimeout, "Timeout for shutdown handlers")
f.BoolVar(&operatorOptions.scalingIntegrationEnabled, "internal.scaling-integration", false, "Enable Scaling Integration") f.BoolVar(&operatorOptions.scalingIntegrationEnabled, "internal.scaling-integration", false, "Enable Scaling Integration")
f.DurationVar(&operatorOptions.reconciliationDelay, "reconciliation.delay", 0, "Delay between reconciliation loops (<= 0 -> Disabled)")
f.Int64Var(&operatorKubernetesOptions.maxBatchSize, "kubernetes.max-batch-size", globals.DefaultKubernetesRequestBatchSize, "Size of batch during objects read") f.Int64Var(&operatorKubernetesOptions.maxBatchSize, "kubernetes.max-batch-size", globals.DefaultKubernetesRequestBatchSize, "Size of batch during objects read")
f.Float32Var(&operatorKubernetesOptions.qps, "kubernetes.qps", kclient.DefaultQPS, "Number of queries per second for k8s API") f.Float32Var(&operatorKubernetesOptions.qps, "kubernetes.qps", kclient.DefaultQPS, "Number of queries per second for k8s API")
f.IntVar(&operatorKubernetesOptions.burst, "kubernetes.burst", kclient.DefaultBurst, "Burst for the k8s API") f.IntVar(&operatorKubernetesOptions.burst, "kubernetes.burst", kclient.DefaultBurst, "Burst for the k8s API")
@ -530,6 +533,7 @@ func newOperatorConfigAndDeps(id, namespace, name string) (operator.Config, oper
ArangoImage: operatorOptions.arangoImage, ArangoImage: operatorOptions.arangoImage,
SingleMode: operatorOptions.singleMode, SingleMode: operatorOptions.singleMode,
Scope: scope, Scope: scope,
ReconciliationDelay: operatorOptions.reconciliationDelay,
ShutdownDelay: shutdownOptions.delay, ShutdownDelay: shutdownOptions.delay,
ShutdownTimeout: shutdownOptions.timeout, ShutdownTimeout: shutdownOptions.timeout,
} }

View file

@ -60,6 +60,7 @@ import (
"github.com/arangodb/kube-arangodb/pkg/util/k8sutil" "github.com/arangodb/kube-arangodb/pkg/util/k8sutil"
"github.com/arangodb/kube-arangodb/pkg/util/k8sutil/kerrors" "github.com/arangodb/kube-arangodb/pkg/util/k8sutil/kerrors"
"github.com/arangodb/kube-arangodb/pkg/util/kclient" "github.com/arangodb/kube-arangodb/pkg/util/kclient"
"github.com/arangodb/kube-arangodb/pkg/util/timer"
"github.com/arangodb/kube-arangodb/pkg/util/trigger" "github.com/arangodb/kube-arangodb/pkg/util/trigger"
) )
@ -70,6 +71,7 @@ type Config struct {
ScalingIntegrationEnabled bool ScalingIntegrationEnabled bool
OperatorImage string OperatorImage string
ArangoImage string ArangoImage string
ReconciliationDelay time.Duration
Scope scope.Scope Scope scope.Scope
} }
@ -107,6 +109,8 @@ type Deployment struct {
uid types.UID uid types.UID
namespace string namespace string
delayer timer.Delayer
currentObject *api.ArangoDeployment currentObject *api.ArangoDeployment
currentObjectStatus *api.DeploymentStatus currentObjectStatus *api.DeploymentStatus
currentObjectLock sync.RWMutex currentObjectLock sync.RWMutex
@ -256,6 +260,7 @@ func New(config Config, deps Dependencies, apiObject *api.ArangoDeployment) (*De
stopCh: make(chan struct{}), stopCh: make(chan struct{}),
agencyCache: agency.NewCache(apiObject.GetNamespace(), apiObject.GetName(), apiObject.GetAcceptedSpec().Mode), agencyCache: agency.NewCache(apiObject.GetNamespace(), apiObject.GetName(), apiObject.GetAcceptedSpec().Mode),
acs: acs.NewACS(apiObject.GetUID(), i), acs: acs.NewACS(apiObject.GetUID(), i),
delayer: timer.NewDelayer(),
} }
d.log = logger.WrapObj(d) d.log = logger.WrapObj(d)

View file

@ -24,6 +24,8 @@ import (
"context" "context"
"time" "time"
"github.com/rs/zerolog/log"
"github.com/arangodb/kube-arangodb/pkg/apis/deployment" "github.com/arangodb/kube-arangodb/pkg/apis/deployment"
api "github.com/arangodb/kube-arangodb/pkg/apis/deployment/v1" api "github.com/arangodb/kube-arangodb/pkg/apis/deployment/v1"
"github.com/arangodb/kube-arangodb/pkg/deployment/features" "github.com/arangodb/kube-arangodb/pkg/deployment/features"
@ -51,6 +53,11 @@ var (
func (d *Deployment) inspectDeployment(lastInterval util.Interval) util.Interval { func (d *Deployment) inspectDeployment(lastInterval util.Interval) util.Interval {
start := time.Now() start := time.Now()
if delay := d.delayer.Wait(); delay > 0 {
log.Info().Dur("delay", delay).Msgf("Reconciliation loop execution was delayed")
}
defer d.delayer.Delay(d.config.ReconciliationDelay)
ctxReconciliation, cancelReconciliation := globals.GetGlobalTimeouts().Reconciliation().WithTimeout(context.Background()) ctxReconciliation, cancelReconciliation := globals.GetGlobalTimeouts().Reconciliation().WithTimeout(context.Background())
defer cancelReconciliation() defer cancelReconciliation()
defer func() { defer func() {

View file

@ -106,6 +106,7 @@ type Config struct {
ScalingIntegrationEnabled bool ScalingIntegrationEnabled bool
SingleMode bool SingleMode bool
Scope scope.Scope Scope scope.Scope
ReconciliationDelay time.Duration
ShutdownDelay time.Duration ShutdownDelay time.Duration
ShutdownTimeout time.Duration ShutdownTimeout time.Duration
} }

View file

@ -201,6 +201,7 @@ func (o *Operator) makeDeploymentConfigAndDeps() (deployment.Config, deployment.
ArangoImage: o.ArangoImage, ArangoImage: o.ArangoImage,
AllowChaos: o.Config.AllowChaos, AllowChaos: o.Config.AllowChaos,
ScalingIntegrationEnabled: o.Config.ScalingIntegrationEnabled, ScalingIntegrationEnabled: o.Config.ScalingIntegrationEnabled,
ReconciliationDelay: o.Config.ReconciliationDelay,
Scope: o.Scope, Scope: o.Scope,
} }
deps := deployment.Dependencies{ deps := deployment.Dependencies{

View file

@ -1,7 +1,7 @@
// //
// DISCLAIMER // DISCLAIMER
// //
// Copyright 2016-2022 ArangoDB GmbH, Cologne, Germany // Copyright 2016-2023 ArangoDB GmbH, Cologne, Germany
// //
// Licensed under the Apache License, Version 2.0 (the "License"); // Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License. // you may not use this file except in compliance with the License.

77
pkg/util/timer/delayer.go Normal file
View file

@ -0,0 +1,77 @@
//
// DISCLAIMER
//
// Copyright 2023 ArangoDB GmbH, Cologne, Germany
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// Copyright holder is ArangoDB GmbH, Cologne, Germany
//
package timer
import (
"sync"
"time"
)
func NewDelayer() Delayer {
return &delayer{}
}
type Delayer interface {
Delay(delay time.Duration)
Wait() time.Duration
Copy() Delayer
}
type delayer struct {
lock sync.Mutex
last, next time.Time
}
func (d *delayer) Copy() Delayer {
d.lock.Lock()
defer d.lock.Unlock()
return &delayer{
last: d.last,
next: d.next,
}
}
func (d *delayer) Wait() time.Duration {
d.lock.Lock()
defer d.lock.Unlock()
since := time.Until(d.next)
if since <= time.Millisecond {
return 0
}
time.Sleep(since)
return since
}
func (d *delayer) Delay(delay time.Duration) {
d.lock.Lock()
defer d.lock.Unlock()
d.last = time.Now()
d.next = d.last.Add(delay)
}

View file

@ -0,0 +1,78 @@
//
// DISCLAIMER
//
// Copyright 2023 ArangoDB GmbH, Cologne, Germany
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// Copyright holder is ArangoDB GmbH, Cologne, Germany
//
package timer
import (
"testing"
"time"
"github.com/stretchr/testify/require"
)
func withTime(f func()) time.Duration {
now := time.Now()
f()
return time.Since(now)
}
func Test_Delayer(t *testing.T) {
d := NewDelayer()
t.Run("Ensure instant execution", func(t *testing.T) {
require.True(t, withTime(func() {
d.Wait()
}) < time.Millisecond)
require.True(t, withTime(func() {
d.Wait()
}) < time.Millisecond)
})
t.Run("Delay execution", func(t *testing.T) {
require.True(t, withTime(func() {
d.Delay(50 * time.Millisecond)
d.Wait()
}) >= 50*time.Millisecond)
})
t.Run("Delay execution, but allow multiple ones", func(t *testing.T) {
require.True(t, withTime(func() {
d.Delay(50 * time.Millisecond)
d.Wait()
d.Wait()
d.Wait()
d.Wait()
}) >= 50*time.Millisecond)
})
t.Run("Delay execution multiple times", func(t *testing.T) {
require.True(t, withTime(func() {
d.Delay(50 * time.Millisecond)
d.Wait()
d.Delay(50 * time.Millisecond)
d.Wait()
d.Delay(50 * time.Millisecond)
d.Wait()
d.Delay(50 * time.Millisecond)
d.Wait()
}) >= 200*time.Millisecond)
})
}