github.com/cilium/statedb@v0.3.2/reconciler/config.go (about)

     1  package reconciler
     2  
     3  import (
     4  	"fmt"
     5  	"time"
     6  
     7  	"github.com/cilium/statedb"
     8  	"golang.org/x/time/rate"
     9  )
    10  
    11  func defaultOptions() options {
    12  	return options{
    13  		Metrics: nil, // use DefaultMetrics
    14  
    15  		// Refresh objects every 30 minutes at a rate of 100 per second.
    16  		RefreshInterval:    30 * time.Minute,
    17  		RefreshRateLimiter: rate.NewLimiter(100.0, 1),
    18  
    19  		// Prune when initialized and then once an hour.
    20  		PruneInterval: time.Hour,
    21  
    22  		// Retry failed operations with exponential backoff from 100ms to 1min.
    23  		RetryBackoffMinDuration: 100 * time.Millisecond,
    24  		RetryBackoffMaxDuration: time.Minute,
    25  
    26  		// Reconcile 100 rounds per second * 1000 yielding maximum rate of
    27  		// 100k objects per second.
    28  		IncrementalRoundSize: 1000,
    29  		RateLimiter:          rate.NewLimiter(1000.0, 1),
    30  	}
    31  }
    32  
    33  type options struct {
    34  	// Metrics to use with this reconciler. The metrics capture the duration
    35  	// of operations during incremental and full reconcilation and the errors
    36  	// that occur during either.
    37  	//
    38  	// If nil, then the default metrics are used via Params.
    39  	// A simple implementation of metrics based on the expvar package come
    40  	// with the reconciler and a custom one can be used by implementing the
    41  	// Metrics interface.
    42  	Metrics Metrics
    43  
    44  	// RefreshInterval is the interval at which the objects are refreshed,
    45  	// e.g. how often Update() should be called to refresh an object even
    46  	// when it has not changed. This is implemented by periodically setting
    47  	// all objects that have not been updated for [RefreshInterval] or longer
    48  	// as pending.
    49  	// If set to 0 refreshing is disabled.
    50  	RefreshInterval time.Duration
    51  
    52  	// RefreshRateLimiter is optional and if set is used to limit the rate at
    53  	// which objects are marked for refresh. If not provided a default rate
    54  	// limiter is used.
    55  	RefreshRateLimiter *rate.Limiter
    56  
    57  	// PruneInterval is the interval at which Prune() is called to prune
    58  	// unexpected objects in the target system. If set to 0 pruning is disabled.
    59  	// Prune() will not be called before the table has been fully initialized
    60  	// (Initialized() returns true).
    61  	// A single Prune() can be forced via the [Reconciler.Prune] method regardless
    62  	// of this value (0 or not).
    63  	PruneInterval time.Duration
    64  
    65  	// RetryBackoffMinDuration is the minimum amount of time to wait before
    66  	// retrying a failed Update() or Delete() operation on an object.
    67  	// The retry wait time for an object will increase exponentially on
    68  	// subsequent failures until RetryBackoffMaxDuration is reached.
    69  	RetryBackoffMinDuration time.Duration
    70  
    71  	// RetryBackoffMaxDuration is the maximum amount of time to wait before
    72  	// retrying.
    73  	RetryBackoffMaxDuration time.Duration
    74  
    75  	// IncrementalRoundSize is the maximum number objects to reconcile during
    76  	// incremental reconciliation before updating status and refreshing the
    77  	// statedb snapshot. This should be tuned based on the cost of each operation
    78  	// and the rate of expected changes so that health and per-object status
    79  	// updates are not delayed too much. If in doubt, use a value between 100-1000.
    80  	IncrementalRoundSize int
    81  
    82  	// RateLimiter is optional and if set will use the limiter to wait between
    83  	// reconciliation rounds. This allows trading latency with throughput by
    84  	// waiting longer to collect a batch of objects to reconcile.
    85  	RateLimiter *rate.Limiter
    86  }
    87  
    88  type config[Obj any] struct {
    89  	// Table to reconcile. Mandatory.
    90  	Table statedb.RWTable[Obj]
    91  
    92  	// GetObjectStatus returns the reconciliation status for the object.
    93  	// Mandatory.
    94  	GetObjectStatus func(Obj) Status
    95  
    96  	// SetObjectStatus sets the reconciliation status for the object.
    97  	// This is called with a copy of the object returned by CloneObject.
    98  	// Mandatory.
    99  	SetObjectStatus func(Obj, Status) Obj
   100  
   101  	// CloneObject returns a shallow copy of the object. This is used to
   102  	// make it possible for the reconciliation operations to mutate
   103  	// the object (to for example provide additional information that the
   104  	// reconciliation produces) and to be able to set the reconciliation
   105  	// status after the reconciliation.
   106  	// Mandatory.
   107  	CloneObject func(Obj) Obj
   108  
   109  	// Operations defines how an object is reconciled. Mandatory.
   110  	Operations Operations[Obj]
   111  
   112  	// BatchOperations is optional and if provided these are used instead of
   113  	// the single-object operations.
   114  	BatchOperations BatchOperations[Obj]
   115  
   116  	options
   117  }
   118  
   119  func (cfg config[Obj]) validate() error {
   120  	if cfg.Table == nil {
   121  		return fmt.Errorf("%T.Table cannot be nil", cfg)
   122  	}
   123  	if cfg.GetObjectStatus == nil {
   124  		return fmt.Errorf("%T.GetObjectStatus cannot be nil", cfg)
   125  	}
   126  	if cfg.SetObjectStatus == nil {
   127  		return fmt.Errorf("%T.SetObjectStatus cannot be nil", cfg)
   128  	}
   129  	if cfg.CloneObject == nil {
   130  		return fmt.Errorf("%T.CloneObject cannot be nil", cfg)
   131  	}
   132  	if cfg.IncrementalRoundSize <= 0 {
   133  		return fmt.Errorf("%T.IncrementalBatchSize needs to be >0", cfg)
   134  	}
   135  	if cfg.RefreshInterval < 0 {
   136  		return fmt.Errorf("%T.RefreshInterval must be >=0", cfg)
   137  	}
   138  	if cfg.PruneInterval < 0 {
   139  		return fmt.Errorf("%T.PruneInterval must be >=0", cfg)
   140  	}
   141  	if cfg.RetryBackoffMaxDuration <= 0 {
   142  		return fmt.Errorf("%T.RetryBackoffMaxDuration must be >0", cfg)
   143  	}
   144  	if cfg.RetryBackoffMinDuration <= 0 {
   145  		return fmt.Errorf("%T.RetryBackoffMinDuration must be >0", cfg)
   146  	}
   147  	if cfg.Operations == nil {
   148  		return fmt.Errorf("%T.Operations must be defined", cfg)
   149  	}
   150  	return nil
   151  }