Repository: spidernet-io/spiderpool
Pull request #1427 (2023-03-13 08:16:33)

Add retry util for conflict retry
Signed-off-by: iiiceoo <ziqian.xue@daocloud.io>


Patch:
diff --git a/cmd/spiderpool-agent/cmd/config.go b/cmd/spiderpool-agent/cmd/config.go
index 4c7d5e0d2..cbf3c1dc2 100644
--- a/cmd/spiderpool-agent/cmd/config.go
+++ b/cmd/spiderpool-agent/cmd/config.go
@@ -60,8 +60,6 @@ var envInfo = []envConf{
 	{"SPIDERPOOL_GOPS_LISTEN_PORT", "5712", false, &agentContext.Cfg.GopsListenPort, nil, nil},
 	{"SPIDERPOOL_PYROSCOPE_PUSH_SERVER_ADDRESS", "", false, &agentContext.Cfg.PyroscopeAddress, nil, nil},
 
-	{"SPIDERPOOL_UPDATE_CR_MAX_RETRIES", "3", false, nil, nil, &agentContext.Cfg.UpdateCRMaxRetries},
-	{"SPIDERPOOL_UPDATE_CR_RETRY_UNIT_TIME", "50", false, nil, nil, &agentContext.Cfg.UpdateCRRetryUnitTime},
 	{"SPIDERPOOL_IPPOOL_MAX_ALLOCATED_IPS", "5000", true, nil, nil, &agentContext.Cfg.IPPoolMaxAllocatedIPs},
 	{"SPIDERPOOL_WAIT_SUBNET_POOL_TIME_IN_SECOND", "1", false, nil, nil, &agentContext.Cfg.WaitSubnetPoolTime},
 	{"SPIDERPOOL_WAIT_SUBNET_POOL_MAX_RETRIES", "50", false, nil, nil, &agentContext.Cfg.WaitSubnetPoolMaxRetries},
@@ -85,8 +83,6 @@ type Config struct {
 	GopsListenPort   string
 	PyroscopeAddress string
 
-	UpdateCRMaxRetries       int
-	UpdateCRRetryUnitTime    int
 	IPPoolMaxAllocatedIPs    int
 	WaitSubnetPoolTime       int
 	WaitSubnetPoolMaxRetries int
diff --git a/cmd/spiderpool-agent/cmd/daemon.go b/cmd/spiderpool-agent/cmd/daemon.go
index c255c952f..b8cd1bf78 100644
--- a/cmd/spiderpool-agent/cmd/daemon.go
+++ b/cmd/spiderpool-agent/cmd/daemon.go
@@ -286,10 +286,6 @@ func initAgentServiceManagers(ctx context.Context) {
 
 	logger.Debug("Begin to initialize Endpoint manager")
 	endpointManager, err := workloadendpointmanager.NewWorkloadEndpointManager(
-		workloadendpointmanager.EndpointManagerConfig{
-			MaxConflictRetries:    agentContext.Cfg.UpdateCRMaxRetries,
-			ConflictRetryUnitTime: time.Duration(agentContext.Cfg.UpdateCRRetryUnitTime) * time.Millisecond,
-		},
 		agentContext.CRDManager.GetClient(),
 		agentContext.CRDManager.GetAPIReader(),
 	)
@@ -311,9 +307,7 @@ func initAgentServiceManagers(ctx context.Context) {
 	logger.Debug("Begin to initialize IPPool manager")
 	ipPoolManager, err := ippoolmanager.NewIPPoolManager(
 		ippoolmanager.IPPoolManagerConfig{
-			MaxConflictRetries:    agentContext.Cfg.UpdateCRMaxRetries,
-			ConflictRetryUnitTime: time.Duration(agentContext.Cfg.UpdateCRRetryUnitTime) * time.Millisecond,
-			MaxAllocatedIPs:       &agentContext.Cfg.IPPoolMaxAllocatedIPs,
+			MaxAllocatedIPs: &agentContext.Cfg.IPPoolMaxAllocatedIPs,
 		},
 		agentContext.CRDManager.GetClient(),
 		agentContext.CRDManager.GetAPIReader(),
@@ -327,10 +321,6 @@ func initAgentServiceManagers(ctx context.Context) {
 	if agentContext.Cfg.EnableSpiderSubnet {
 		logger.Debug("Begin to initialize Subnet manager")
 		subnetManager, err := subnetmanager.NewSubnetManager(
-			subnetmanager.SubnetManagerConfig{
-				MaxConflictRetries:    agentContext.Cfg.UpdateCRMaxRetries,
-				ConflictRetryUnitTime: time.Duration(agentContext.Cfg.UpdateCRRetryUnitTime) * time.Millisecond,
-			},
 			agentContext.CRDManager.GetClient(),
 			agentContext.CRDManager.GetAPIReader(),
 			agentContext.IPPoolManager,
diff --git a/cmd/spiderpool-controller/cmd/config.go b/cmd/spiderpool-controller/cmd/config.go
index 8b585b852..5771922e9 100644
--- a/cmd/spiderpool-controller/cmd/config.go
+++ b/cmd/spiderpool-controller/cmd/config.go
@@ -76,8 +76,6 @@ var envInfo = []envConf{
 	{"SPIDERPOOL_GC_LEADER_RETRY_PERIOD", "2", true, nil, nil, &controllerContext.Cfg.LeaseRetryPeriod},
 	{"SPIDERPOOL_GC_LEADER_RETRY_GAP", "1", true, nil, nil, &controllerContext.Cfg.LeaseRetryGap},
 
-	{"SPIDERPOOL_UPDATE_CR_MAX_RETRIES", "3", false, nil, nil, &controllerContext.Cfg.UpdateCRMaxRetries},
-	{"SPIDERPOOL_UPDATE_CR_RETRY_UNIT_TIME", "50", false, nil, nil, &controllerContext.Cfg.UpdateCRRetryUnitTime},
 	{"SPIDERPOOL_IPPOOL_MAX_ALLOCATED_IPS", "5000", false, nil, nil, &controllerContext.Cfg.IPPoolMaxAllocatedIPs},
 
 	{"SPIDERPOOL_SUBNET_RESYNC_PERIOD", "300", false, nil, nil, &controllerContext.Cfg.SubnetResyncPeriod},
@@ -120,8 +118,6 @@ type Config struct {
 	LeaseRetryPeriod       int
 	LeaseRetryGap          int
 
-	UpdateCRMaxRetries    int
-	UpdateCRRetryUnitTime int
 	IPPoolMaxAllocatedIPs int
 
 	SubnetResyncPeriod               int
diff --git a/cmd/spiderpool-controller/cmd/daemon.go b/cmd/spiderpool-controller/cmd/daemon.go
index 094bb045d..83d40bd22 100644
--- a/cmd/spiderpool-controller/cmd/daemon.go
+++ b/cmd/spiderpool-controller/cmd/daemon.go
@@ -247,10 +247,6 @@ func initControllerServiceManagers(ctx context.Context) {
 
 	logger.Debug("Begin to initialize Endpoint manager")
 	endpointManager, err := workloadendpointmanager.NewWorkloadEndpointManager(
-		workloadendpointmanager.EndpointManagerConfig{
-			MaxConflictRetries:    controllerContext.Cfg.UpdateCRMaxRetries,
-			ConflictRetryUnitTime: time.Duration(controllerContext.Cfg.UpdateCRRetryUnitTime) * time.Millisecond,
-		},
 		controllerContext.CRDManager.GetClient(),
 		controllerContext.CRDManager.GetAPIReader(),
 	)
@@ -280,9 +276,7 @@ func initControllerServiceManagers(ctx context.Context) {
 	logger.Debug("Begin to initialize IPPool manager")
 	ipPoolManager, err := ippoolmanager.NewIPPoolManager(
 		ippoolmanager.IPPoolManagerConfig{
-			MaxConflictRetries:    controllerContext.Cfg.UpdateCRMaxRetries,
-			ConflictRetryUnitTime: time.Duration(controllerContext.Cfg.UpdateCRRetryUnitTime) * time.Millisecond,
-			MaxAllocatedIPs:       &controllerContext.Cfg.IPPoolMaxAllocatedIPs,
+			MaxAllocatedIPs: &controllerContext.Cfg.IPPoolMaxAllocatedIPs,
 		},
 		controllerContext.CRDManager.GetClient(),
 		controllerContext.CRDManager.GetAPIReader(),
@@ -307,10 +301,6 @@ func initControllerServiceManagers(ctx context.Context) {
 	if controllerContext.Cfg.EnableSpiderSubnet {
 		logger.Debug("Begin to initialize Subnet manager")
 		subnetManager, err := subnetmanager.NewSubnetManager(
-			subnetmanager.SubnetManagerConfig{
-				MaxConflictRetries:    controllerContext.Cfg.UpdateCRMaxRetries,
-				ConflictRetryUnitTime: time.Duration(controllerContext.Cfg.UpdateCRRetryUnitTime) * time.Millisecond,
-			},
 			controllerContext.CRDManager.GetClient(),
 			controllerContext.CRDManager.GetAPIReader(),
 			controllerContext.IPPoolManager,
diff --git a/pkg/ippoolmanager/config.go b/pkg/ippoolmanager/config.go
index 16dd1ba54..2df574469 100644
--- a/pkg/ippoolmanager/config.go
+++ b/pkg/ippoolmanager/config.go
@@ -3,16 +3,12 @@
 
 package ippoolmanager
 
-import "time"
-
 const (
 	defaultMaxAllocatedIPs = 5000
 )
 
 type IPPoolManagerConfig struct {
-	MaxConflictRetries    int
-	ConflictRetryUnitTime time.Duration
-	MaxAllocatedIPs       *int
+	MaxAllocatedIPs *int
 }
 
 func setDefaultsForIPPoolManagerConfig(config IPPoolManagerConfig) IPPoolManagerConfig {
diff --git a/pkg/ippoolmanager/ippool_manager.go b/pkg/ippoolmanager/ippool_manager.go
index c494ba359..f68c070f5 100644
--- a/pkg/ippoolmanager/ippool_manager.go
+++ b/pkg/ippoolmanager/ippool_manager.go
@@ -6,14 +6,13 @@ package ippoolmanager
 import (
 	"context"
 	"fmt"
-	"math/rand"
 	"net"
-	"time"
 
 	"go.uber.org/zap"
 	corev1 "k8s.io/api/core/v1"
 	apierrors "k8s.io/apimachinery/pkg/api/errors"
 	apitypes "k8s.io/apimachinery/pkg/types"
+	"k8s.io/apimachinery/pkg/util/wait"
 	"sigs.k8s.io/controller-runtime/pkg/client"
 
 	"github.com/spidernet-io/spiderpool/api/v1/agent/models"
@@ -25,6 +24,7 @@ import (
 	"github.com/spidernet-io/spiderpool/pkg/reservedipmanager"
 	"github.com/spidernet-io/spiderpool/pkg/types"
 	"github.com/spidernet-io/spiderpool/pkg/utils/convert"
+	"github.com/spidernet-io/spiderpool/pkg/utils/retry"
 )
 
 type IPPoolManager interface {
@@ -93,41 +93,43 @@ func (im *ipPoolManager) ListIPPools(ctx context.Context, cached bool, opts ...c
 func (im *ipPoolManager) AllocateIP(ctx context.Context, poolName, nic string, pod *corev1.Pod) (*models.IPConfig, error) {
 	logger := logutils.FromContext(ctx)
 
+	backoff := retry.DefaultRetry
+	steps := backoff.Steps
 	var ipConfig *models.IPConfig
-	r := rand.New(rand.NewSource(time.Now().UnixNano()))
-	for i := 0; i <= im.config.MaxConflictRetries; i++ {
-		logger := logger.With(zap.Int("times", i+1))
-		logger.Sugar().Debugf("Re-get IPPool %s for IP allocation", poolName)
+	err := retry.RetryOnConflictWithContext(ctx, backoff, func(ctx context.Context) error {
+		logger := logger.With(
+			zap.String("IPPoolName", poolName),
+			zap.Int("Times", steps-backoff.Steps+1),
+		)
+		logger.Debug("Re-get IPPool for IP allocation")
 		ipPool, err := im.GetIPPoolByName(ctx, poolName, constant.IgnoreCache)
 		if err != nil {
-			return nil, err
+			return err
 		}
 
 		logger.Debug("Generate a random IP address")
 		allocatedIP, err := im.genRandomIP(ctx, nic, ipPool, pod)
 		if err != nil {
-			return nil, err
+			return err
 		}
 
-		logger.Sugar().Debugf("Try to update the allocation status of IPPool %s with random IP %s", ipPool.Name, allocatedIP)
+		logger.Sugar().Debugf("Try to update the allocation status of IPPool using random IP %s", allocatedIP)
 		if err := im.client.Status().Update(ctx, ipPool); err != nil {
-			if !apierrors.IsConflict(err) {
-				return nil, err
-			}
-
-			metric.IpamAllocationUpdateIPPoolConflictCounts.Add(ctx, 1)
-			if i == im.config.MaxConflictRetries {
-				return nil, fmt.Errorf("%w (%d times), failed to allocate IP from IPPool %s", constant.ErrRetriesExhausted, im.config.MaxConflictRetries, ipPool.Name)
+			if apierrors.IsConflict(err) {
+				metric.IpamAllocationUpdateIPPoolConflictCounts.Add(ctx, 1)
+				logger.Debug("An conflict occurred when updating the status of IPPool")
 			}
-
-			interval := time.Duration(r.Intn(1<<(i+1))) * im.config.ConflictRetryUnitTime
-			logger.Sugar().Debugf("An conflict occurred when updating the status of the IPPool %s, it will be retried in %s", ipPool.Name, interval)
-			time.Sleep(interval)
-			continue
+			return err
 		}
-
 		ipConfig = convert.GenIPConfigResult(allocatedIP, nic, ipPool)
-		break
+
+		return nil
+	})
+	if err != nil {
+		if err == wait.ErrWaitTimeout {
+			err = fmt.Errorf("%w (%d times), failed to allocate IP from IPPool %s", constant.ErrRetriesExhausted, steps, poolName)
+		}
+		return nil, err
 	}
 
 	return ipConfig, nil
@@ -192,10 +194,14 @@ func (im *ipPoolManager) genRandomIP(ctx context.Context, nic string, ipPool *sp
 func (im *ipPoolManager) ReleaseIP(ctx context.Context, poolName string, ipAndUIDs []types.IPAndUID) error {
 	logger := logutils.FromContext(ctx)
 
-	r := rand.New(rand.NewSource(time.Now().UnixNano()))
-	for i := 0; i <= im.config.MaxConflictRetries; i++ {
-		logger := logger.With(zap.Int("times", i+1))
-		logger.Sugar().Debugf("Re-get IPPool %s for IP release", poolName)
+	backoff := retry.DefaultRetry
+	steps := backoff.Steps
+	err := retry.RetryOnConflictWithContext(ctx, backoff, func(ctx context.Context) error {
+		logger := logger.With(
+			zap.String("IPPoolName", poolName),
+			zap.Int("Times", steps-backoff.Steps+1),
+		)
+		logger.Debug("Re-get IPPool for IP release")
 		ipPool, err := im.GetIPPoolByName(ctx, poolName, constant.IgnoreCache)
 		if err != nil {
 			return err
@@ -231,32 +237,31 @@ func (im *ipPoolManager) ReleaseIP(ctx context.Context, poolName string, ipAndUI
 		}
 		ipPool.Status.AllocatedIPs = data
 
-		logger.Sugar().Debugf("Try to clean the allocation records of IPPool %s with IP addresses %+v", ipPool.Name, ipAndUIDs)
+		logger.Sugar().Debugf("Try to clean the IP allocation records of IPPool with IP addresses %+v", ipAndUIDs)
 		if err := im.client.Status().Update(ctx, ipPool); err != nil {
-			if !apierrors.IsConflict(err) {
-				return err
+			if apierrors.IsConflict(err) {
+				metric.IpamReleaseUpdateIPPoolConflictCounts.Add(ctx, 1)
+				logger.Debug("An conflict occurred when cleaning the IP allocation records of IPPool")
 			}
+			return err
+		}
 
-			metric.IpamReleaseUpdateIPPoolConflictCounts.Add(ctx, 1)
-			if i == im.config.MaxConflictRetries {
-				return fmt.Errorf("%w (%d times), failed to release IP addresses %+v from IPPool %s", constant.ErrRetriesExhausted, im.config.MaxConflictRetries, ipAndUIDs, poolName)
-			}
-
-			interval := time.Duration(r.Intn(1<<(i+1))) * im.config.ConflictRetryUnitTime
-			logger.Sugar().Debugf("An conflict occurred when releasing form the IPPool %s, it will be retried in %s", ipPool.Name, interval)
-
-			time.Sleep(interval)
-			continue
+		return nil
+	})
+	if err != nil {
+		if err == wait.ErrWaitTimeout {
+			err = fmt.Errorf("%w (%d times), failed to release IP addresses %+v from IPPool %s", constant.ErrRetriesExhausted, steps, ipAndUIDs, poolName)
 		}
-		break
+		return err
 	}
 
 	return nil
 }
 
 func (im *ipPoolManager) UpdateAllocatedIPs(ctx context.Context, poolName string, ipAndUIDs []types.IPAndUID) error {
-	r := rand.New(rand.NewSource(time.Now().UnixNano()))
-	for i := 0; i <= im.config.MaxConflictRetries; i++ {
+	backoff := retry.DefaultRetry
+	steps := backoff.Steps
+	err := retry.RetryOnConflictWithContext(ctx, backoff, func(ctx context.Context) error {
 		ipPool, err := im.GetIPPoolByName(ctx, poolName, constant.IgnoreCache)
 		if err != nil {
 			return err
@@ -288,19 +293,19 @@ func (im *ipPoolManager) UpdateAllocatedIPs(ctx context.Context, poolName string
 		ipPool.Status.AllocatedIPs = data
 
 		if err := im.client.Status().Update(ctx, ipPool); err != nil {
-			if !apierrors.IsConflict(err) {
-				return err
-			}
-
-			metric.IpamAllocationUpdateIPPoolConflictCounts.Add(ctx, 1)
-			if i == im.config.MaxConflictRetries {
-				return fmt.Errorf("%w (%d times), failed to re-allocate the IP addresses %+v from IPPool %s", constant.ErrRetriesExhausted, im.config.MaxConflictRetries, ipAndUIDs, poolName)
+			if apierrors.IsConflict(err) {
+				metric.IpamAllocationUpdateIPPoolConflictCounts.Add(ctx, 1)
 			}
+			return err
+		}
 
-			time.Sleep(time.Duration(r.Intn(1<<(i+1))) * im.config.ConflictRetryUnitTime)
-			continue
+		return nil
+	})
+	if err != nil {
+		if err == wait.ErrWaitTimeout {
+			err = fmt.Errorf("%w (%d times), failed to re-allocate the IP addresses %+v from IPPool %s", constant.ErrRetriesExhausted, steps, ipAndUIDs, poolName)
 		}
-		break
+		return err
 	}
 
 	return nil
diff --git a/pkg/subnetmanager/config.go b/pkg/subnetmanager/config.go
deleted file mode 100644
index 6263cbcdf..000000000
--- a/pkg/subnetmanager/config.go
+++ /dev/null
@@ -1,17 +0,0 @@
-// Copyright 2022 Authors of spidernet-io
-// SPDX-License-Identifier: Apache-2.0
-
-package subnetmanager
-
-import (
-	"time"
-)
-
-type SubnetManagerConfig struct {
-	MaxConflictRetries    int
-	ConflictRetryUnitTime time.Duration
-}
-
-func setDefaultsForSubnetManagerConfig(config SubnetManagerConfig) SubnetManagerConfig {
-	return config
-}
diff --git a/pkg/subnetmanager/subnet_manager.go b/pkg/subnetmanager/subnet_manager.go
index 5a4e0fb87..d240282b0 100644
--- a/pkg/subnetmanager/subnet_manager.go
+++ b/pkg/subnetmanager/subnet_manager.go
@@ -31,14 +31,13 @@ type SubnetManager interface {
 }
 
 type subnetManager struct {
-	config    SubnetManagerConfig
 	client    client.Client
 	apiReader client.Reader
 
 	ipPoolManager ippoolmanager.IPPoolManager
 }
 
-func NewSubnetManager(config SubnetManagerConfig, client client.Client, apiReader client.Reader, ipPoolManager ippoolmanager.IPPoolManager) (SubnetManager, error) {
+func NewSubnetManager(client client.Client, apiReader client.Reader, ipPoolManager ippoolmanager.IPPoolManager) (SubnetManager, error) {
 	if client == nil {
 		return nil, fmt.Errorf("k8s client %w", constant.ErrMissingRequiredParam)
 	}
@@ -50,7 +49,6 @@ func NewSubnetManager(config SubnetManagerConfig, client client.Client, apiReade
 	}
 
 	return &subnetManager{
-		config:        setDefaultsForSubnetManagerConfig(config),
 		client:        client,
 		apiReader:     apiReader,
 		ipPoolManager: ipPoolManager,
diff --git a/pkg/utils/retry/retry.go b/pkg/utils/retry/retry.go
new file mode 100644
index 000000000..99d40dead
--- /dev/null
+++ b/pkg/utils/retry/retry.go
@@ -0,0 +1,45 @@
+// Copyright 2022 Authors of spidernet-io
+// SPDX-License-Identifier: Apache-2.0
+
+package retry
+
+import (
+	"context"
+	"time"
+
+	apierrors "k8s.io/apimachinery/pkg/api/errors"
+	"k8s.io/apimachinery/pkg/util/wait"
+)
+
+var DefaultRetry = wait.Backoff{
+	Steps:    5,
+	Duration: 10 * time.Millisecond,
+	Factor:   1.5,
+	Jitter:   0.1,
+}
+
+var DefaultBackoff = wait.Backoff{
+	Steps:    4,
+	Duration: 10 * time.Millisecond,
+	Factor:   5.0,
+	Jitter:   0.1,
+}
+
+func OnErrorWithContext(ctx context.Context, backoff wait.Backoff, retriable func(error) bool, f func(context.Context) error) error {
+	err := wait.ExponentialBackoffWithContext(ctx, backoff, func() (bool, error) {
+		err := f(ctx)
+		switch {
+		case err == nil:
+			return true, nil
+		case retriable(err):
+			return false, nil
+		default:
+			return false, err
+		}
+	})
+	return err
+}
+
+func RetryOnConflictWithContext(ctx context.Context, backoff wait.Backoff, f func(context.Context) error) error {
+	return OnErrorWithContext(ctx, backoff, apierrors.IsConflict, f)
+}
diff --git a/pkg/workloadendpointmanager/config.go b/pkg/workloadendpointmanager/config.go
deleted file mode 100644
index e1f6336cf..000000000
--- a/pkg/workloadendpointmanager/config.go
+++ /dev/null
@@ -1,17 +0,0 @@
-// Copyright 2022 Authors of spidernet-io
-// SPDX-License-Identifier: Apache-2.0
-
-package workloadendpointmanager
-
-import (
-	"time"
-)
-
-type EndpointManagerConfig struct {
-	MaxConflictRetries    int
-	ConflictRetryUnitTime time.Duration
-}
-
-func setDefaultsForEndpointManagerConfig(config EndpointManagerConfig) EndpointManagerConfig {
-	return config
-}
diff --git a/pkg/workloadendpointmanager/workloadendpoint_manager.go b/pkg/workloadendpointmanager/workloadendpoint_manager.go
index a398d5fd6..eedcad0f5 100644
--- a/pkg/workloadendpointmanager/workloadendpoint_manager.go
+++ b/pkg/workloadendpointmanager/workloadendpoint_manager.go
@@ -6,13 +6,12 @@ package workloadendpointmanager
 import (
 	"context"
 	"fmt"
-	"math/rand"
 	"time"
 
 	corev1 "k8s.io/api/core/v1"
-	apierrors "k8s.io/apimachinery/pkg/api/errors"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	apitypes "k8s.io/apimachinery/pkg/types"
+	"k8s.io/apimachinery/pkg/util/wait"
 	"sigs.k8s.io/controller-runtime/pkg/client"
 	"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
 
@@ -20,6 +19,7 @@ import (
 	spiderpoolv1 "github.com/spidernet-io/spiderpool/pkg/k8s/apis/spiderpool.spidernet.io/v1"
 	"github.com/spidernet-io/spiderpool/pkg/types"
 	"github.com/spidernet-io/spiderpool/pkg/utils/convert"
+	"github.com/spidernet-io/spiderpool/pkg/utils/retry"
 )
 
 type WorkloadEndpointManager interface {
@@ -32,12 +32,11 @@ type WorkloadEndpointManager interface {
 }
 
 type workloadEndpointManager struct {
-	config    EndpointManagerConfig
 	client    client.Client
 	apiReader client.Reader
 }
 
-func NewWorkloadEndpointManager(config EndpointManagerConfig, client client.Client, apiReader client.Reader) (WorkloadEndpointManager, error) {
+func NewWorkloadEndpointManager(client client.Client, apiReader client.Reader) (WorkloadEndpointManager, error) {
 	if client == nil {
 		return nil, fmt.Errorf("k8s client %w", constant.ErrMissingRequiredParam)
 	}
@@ -46,7 +45,6 @@ func NewWorkloadEndpointManager(config EndpointManagerConfig, client client.Clie
 	}
 
 	return &workloadEndpointManager{
-		config:    setDefaultsForEndpointManagerConfig(config),
 		client:    client,
 		apiReader: apiReader,
 	}, nil
@@ -89,8 +87,9 @@ func (em *workloadEndpointManager) DeleteEndpoint(ctx context.Context, endpoint
 }
 
 func (em *workloadEndpointManager) RemoveFinalizer(ctx context.Context, namespace, podName string) error {
-	r := rand.New(rand.NewSource(time.Now().UnixNano()))
-	for i := 0; i <= em.config.MaxConflictRetries; i++ {
+	backoff := retry.DefaultRetry
+	steps := backoff.Steps
+	err := retry.RetryOnConflictWithContext(ctx, backoff, func(ctx context.Context) error {
 		endpoint, err := em.GetEndpointByName(ctx, namespace, podName, constant.IgnoreCache)
 		if err != nil {
 			return client.IgnoreNotFound(err)
@@ -101,17 +100,13 @@ func (em *workloadEndpointManager) RemoveFinalizer(ctx context.Context, namespac
 		}
 
 		controllerutil.RemoveFinalizer(endpoint, constant.SpiderFinalizer)
-		if err := em.client.Update(ctx, endpoint); err != nil {
-			if !apierrors.IsConflict(err) {
-				return err
-			}
-			if i == em.config.MaxConflictRetries {
-				return fmt.Errorf("%w (%d times), failed to remove finalizer %s from Endpoint %s/%s", constant.ErrRetriesExhausted, em.config.MaxConflictRetries, constant.SpiderFinalizer, namespace, podName)
-			}
-			time.Sleep(time.Duration(r.Intn(1<<(i+1))) * em.config.ConflictRetryUnitTime)
-			continue
+		return em.client.Update(ctx, endpoint)
+	})
+	if err != nil {
+		if err == wait.ErrWaitTimeout {
+			err = fmt.Errorf("%w (%d times), failed to remove finalizer %s from Endpoint %s/%s", constant.ErrRetriesExhausted, steps, constant.SpiderFinalizer, namespace, podName)
 		}
-		break
+		return err
 	}
 
 	return nil


Test patch:
diff --git a/pkg/workloadendpointmanager/workloadendpoint_manager_suite_test.go b/pkg/workloadendpointmanager/workloadendpoint_manager_suite_test.go
index 404756951..18cfa858c 100644
--- a/pkg/workloadendpointmanager/workloadendpoint_manager_suite_test.go
+++ b/pkg/workloadendpointmanager/workloadendpoint_manager_suite_test.go
@@ -49,9 +49,6 @@ var _ = BeforeSuite(func() {
 		Build()
 
 	endpointManager, err = workloadendpointmanager.NewWorkloadEndpointManager(
-		workloadendpointmanager.EndpointManagerConfig{
-			MaxConflictRetries: 1,
-		},
 		fakeClient,
 		fakeAPIReader,
 	)
diff --git a/pkg/workloadendpointmanager/workloadendpoint_manager_test.go b/pkg/workloadendpointmanager/workloadendpoint_manager_test.go
index 275d83482..c9c17ea84 100644
--- a/pkg/workloadendpointmanager/workloadendpoint_manager_test.go
+++ b/pkg/workloadendpointmanager/workloadendpoint_manager_test.go
@@ -30,19 +30,8 @@ import (
 
 var _ = Describe("WorkloadEndpointManager", Label("workloadendpoint_manager_test"), func() {
 	Describe("New WorkloadEndpointManager", func() {
-		It("sets default config", func() {
-			manager, err := workloadendpointmanager.NewWorkloadEndpointManager(
-				workloadendpointmanager.EndpointManagerConfig{},
-				fakeClient,
-				fakeAPIReader,
-			)
-			Expect(err).NotTo(HaveOccurred())
-			Expect(manager).NotTo(BeNil())
-		})
-
 		It("inputs nil client", func() {
 			manager, err := workloadendpointmanager.NewWorkloadEndpointManager(
-				workloadendpointmanager.EndpointManagerConfig{},
 				nil,
 				fakeAPIReader,
 			)
@@ -52,7 +41,6 @@ var _ = Describe("WorkloadEndpointManager", Label("workloadendpoint_manager_test
 
 		It("inputs nil API reader", func() {
 			manager, err := workloadendpointmanager.NewWorkloadEndpointManager(
-				workloadendpointmanager.EndpointManagerConfig{},
 				fakeClient,
 				nil,
 			)