github.com/m3db/m3@v1.5.0/src/aggregator/integration/options.go (about)

     1  // Copyright (c) 2016 Uber Technologies, Inc.
     2  //
     3  // Permission is hereby granted, free of charge, to any person obtaining a copy
     4  // of this software and associated documentation files (the "Software"), to deal
     5  // in the Software without restriction, including without limitation the rights
     6  // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
     7  // copies of the Software, and to permit persons to whom the Software is
     8  // furnished to do so, subject to the following conditions:
     9  //
    10  // The above copyright notice and this permission notice shall be included in
    11  // all copies or substantial portions of the Software.
    12  //
    13  // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    14  // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    15  // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
    16  // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    17  // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
    18  // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
    19  // THE SOFTWARE.
    20  
    21  package integration
    22  
    23  import (
    24  	"testing"
    25  	"time"
    26  
    27  	"github.com/stretchr/testify/require"
    28  
    29  	"github.com/m3db/m3/src/aggregator/aggregator"
    30  	aggclient "github.com/m3db/m3/src/aggregator/client"
    31  	"github.com/m3db/m3/src/aggregator/sharding"
    32  	cluster "github.com/m3db/m3/src/cluster/client"
    33  	"github.com/m3db/m3/src/cluster/kv"
    34  	memcluster "github.com/m3db/m3/src/cluster/mem"
    35  	"github.com/m3db/m3/src/metrics/aggregation"
    36  	"github.com/m3db/m3/src/msg/topic"
    37  	"github.com/m3db/m3/src/x/clock"
    38  	"github.com/m3db/m3/src/x/instrument"
    39  )
    40  
    41  const (
    42  	defaultRawTCPAddr                 = "localhost:6000"
    43  	defaultHTTPAddr                   = "localhost:6001"
    44  	defaultM3MsgAddr                  = "localhost:6002"
    45  	defaultServerStateChangeTimeout   = 5 * time.Second
    46  	defaultClientBatchSize            = 1440
    47  	defaultWorkerPoolSize             = 4
    48  	defaultServiceName                = "m3aggregator"
    49  	defaultInstanceID                 = "localhost"
    50  	defaultPlacementKVKey             = "/placement"
    51  	defaultElectionKeyFmt             = "/shardset/%d/lock"
    52  	defaultFlushTimesKeyFmt           = "/shardset/%d/flush"
    53  	defaultTopicName                  = "aggregator_ingest"
    54  	defaultShardSetID                 = 0
    55  	defaultElectionStateChangeTimeout = 10 * time.Second
    56  	defaultEntryCheckInterval         = time.Second
    57  	defaultJitterEnabled              = true
    58  	defaultDiscardNaNAggregatedValues = true
    59  	defaultEntryTTL                   = time.Hour
    60  )
    61  
    62  type testServerOptions interface {
    63  	// SetClockOptions sets the clock options.
    64  	SetClockOptions(value clock.Options) testServerOptions
    65  
    66  	// ClockOptions returns the clock options.
    67  	ClockOptions() clock.Options
    68  
    69  	// SetInstrumentOptions sets the instrument options.
    70  	SetInstrumentOptions(value instrument.Options) testServerOptions
    71  
    72  	// InstrumentOptions returns the instrument options.
    73  	InstrumentOptions() instrument.Options
    74  
    75  	// SetAggregationTypesOptions sets the aggregation types options.
    76  	SetAggregationTypesOptions(value aggregation.TypesOptions) testServerOptions
    77  
    78  	// AggregationTypesOptions returns the aggregation types options.
    79  	AggregationTypesOptions() aggregation.TypesOptions
    80  
    81  	// SetRawTCPAddr sets the raw TCP server address.
    82  	SetRawTCPAddr(value string) testServerOptions
    83  
    84  	// RawTCPAddr returns the raw TCP server address.
    85  	RawTCPAddr() string
    86  
    87  	// SetHTTPAddr sets the http server address.
    88  	SetHTTPAddr(value string) testServerOptions
    89  
    90  	// HTTPAddr returns the http server address.
    91  	HTTPAddr() string
    92  
    93  	// SetM3MsgAddr sets the M3msg server address.
    94  	SetM3MsgAddr(value string) testServerOptions
    95  
    96  	// M3MsgAddr returns the M3msg server address.
    97  	M3MsgAddr() string
    98  
    99  	// SetInstanceID sets the instance id.
   100  	SetInstanceID(value string) testServerOptions
   101  
   102  	// InstanceID returns the instance id.
   103  	InstanceID() string
   104  
   105  	// SetElectionKeyFmt sets the election key format.
   106  	SetElectionKeyFmt(value string) testServerOptions
   107  
   108  	// ElectionKeyFmt returns the election key format.
   109  	ElectionKeyFmt() string
   110  
   111  	// SetElectionCluster sets the test KV cluster for election.
   112  	SetElectionCluster(value *testCluster) testServerOptions
   113  
   114  	// ElectionCluster returns the test KV cluster for election.
   115  	ElectionCluster() *testCluster
   116  
   117  	// SetShardSetID sets the shard set id.
   118  	SetShardSetID(value uint32) testServerOptions
   119  
   120  	// ShardSetID returns the shard set id.
   121  	ShardSetID() uint32
   122  
   123  	// SetShardFn sets the sharding function.
   124  	SetShardFn(value sharding.ShardFn) testServerOptions
   125  
   126  	// ShardFn returns the sharding function.
   127  	ShardFn() sharding.ShardFn
   128  
   129  	// SetPlacementKVKey sets the placement kv key.
   130  	SetPlacementKVKey(value string) testServerOptions
   131  
   132  	// PlacementKVKey returns the placement kv key.
   133  	PlacementKVKey() string
   134  
   135  	// SetFlushTimesKeyFmt sets the flush times key format.
   136  	SetFlushTimesKeyFmt(value string) testServerOptions
   137  
   138  	// FlushTimesKeyFmt returns the flush times key format.
   139  	FlushTimesKeyFmt() string
   140  
   141  	// SetClusterClient sets the cluster client.
   142  	SetClusterClient(value cluster.Client) testServerOptions
   143  
   144  	// ClusterClient returns the cluster client.
   145  	ClusterClient() cluster.Client
   146  
   147  	// SetTopicService sets the topic service.
   148  	SetTopicService(value topic.Service) testServerOptions
   149  
   150  	// TopicService returns the topic service.
   151  	TopicService() topic.Service
   152  
   153  	// SetTopicName sets the topic name.
   154  	SetTopicName(value string) testServerOptions
   155  
   156  	// TopicName return the topic name.
   157  	TopicName() string
   158  
   159  	// SetAggregatorClientType sets the aggregator client type.
   160  	SetAggregatorClientType(value aggclient.AggregatorClientType) testServerOptions
   161  
   162  	// AggregatorClientType returns the agggregator client type.
   163  	AggregatorClientType() aggclient.AggregatorClientType
   164  
   165  	// SetClientBatchSize sets the client-side batch size.
   166  	SetClientBatchSize(value int) testServerOptions
   167  
   168  	// ClientBatchSize returns the client-side batch size.
   169  	ClientBatchSize() int
   170  
   171  	// SetClientConnectionOptions sets the client-side connection options.
   172  	SetClientConnectionOptions(value aggclient.ConnectionOptions) testServerOptions
   173  
   174  	// ClientConnectionOptions returns the client-side connection options.
   175  	ClientConnectionOptions() aggclient.ConnectionOptions
   176  
   177  	// SetServerStateChangeTimeout sets the client connect timeout.
   178  	SetServerStateChangeTimeout(value time.Duration) testServerOptions
   179  
   180  	// ServerStateChangeTimeout returns the client connect timeout.
   181  	ServerStateChangeTimeout() time.Duration
   182  
   183  	// SetElectionStateChangeTimeout sets the election state change timeout.
   184  	SetElectionStateChangeTimeout(value time.Duration) testServerOptions
   185  
   186  	// ElectionStateChangeTimeout returns the election state change timeout.
   187  	ElectionStateChangeTimeout() time.Duration
   188  
   189  	// SetWorkerPoolSize sets the number of workers in the worker pool.
   190  	SetWorkerPoolSize(value int) testServerOptions
   191  
   192  	// WorkerPoolSize returns the number of workers in the worker pool.
   193  	WorkerPoolSize() int
   194  
   195  	// SetEntryCheckInterval sets the entry check interval.
   196  	SetEntryCheckInterval(value time.Duration) testServerOptions
   197  
   198  	// EntryCheckInterval returns the entry check interval.
   199  	EntryCheckInterval() time.Duration
   200  
   201  	// SetJitterEnabled sets whether jittering is enabled.
   202  	SetJitterEnabled(value bool) testServerOptions
   203  
   204  	// JitterEnabled returns whether jittering is enabled.
   205  	JitterEnabled() bool
   206  
   207  	// SetMaxJitterFn sets the max flush jittering function.
   208  	SetMaxJitterFn(value aggregator.FlushJitterFn) testServerOptions
   209  
   210  	// MaxJitterFn returns the max flush jittering function.
   211  	MaxJitterFn() aggregator.FlushJitterFn
   212  
   213  	// SetMaxAllowedForwardingDelayFn sets the maximum allowed forwarding delay function.
   214  	SetMaxAllowedForwardingDelayFn(value aggregator.MaxAllowedForwardingDelayFn) testServerOptions
   215  
   216  	// MaxAllowedForwardingDelayFn returns the maximum allowed forwarding delay function.
   217  	MaxAllowedForwardingDelayFn() aggregator.MaxAllowedForwardingDelayFn
   218  
   219  	// SetDiscardNaNAggregatedValues determines whether NaN aggregated values are discarded.
   220  	SetDiscardNaNAggregatedValues(value bool) testServerOptions
   221  
   222  	// DiscardNaNAggregatedValues determines whether NaN aggregated values are discarded.
   223  	DiscardNaNAggregatedValues() bool
   224  
   225  	// SetBufferForPastTimedMetric sets the BufferForPastTimedMetric.
   226  	SetBufferForPastTimedMetric(value time.Duration) testServerOptions
   227  
   228  	// BufferForPastTimedMetric is how long to wait for timed metrics to arrive.
   229  	BufferForPastTimedMetric() time.Duration
   230  
   231  	// SetEntryTTL sets the EntryTTL.
   232  	SetEntryTTL(value time.Duration) testServerOptions
   233  
   234  	// EntryTTL is how long to wait before expiring the aggregation when it's inactive.
   235  	EntryTTL() time.Duration
   236  }
   237  
   238  type serverOptions struct {
   239  	clockOpts                     clock.Options
   240  	instrumentOpts                instrument.Options
   241  	aggTypesOpts                  aggregation.TypesOptions
   242  	rawTCPAddr                    string
   243  	httpAddr                      string
   244  	m3MsgAddr                     string
   245  	instanceID                    string
   246  	electionKeyFmt                string
   247  	electionCluster               *testCluster
   248  	shardSetID                    uint32
   249  	shardFn                       sharding.ShardFn
   250  	placementKVKey                string
   251  	flushTimesKeyFmt              string
   252  	clusterClient                 cluster.Client
   253  	topicService                  topic.Service
   254  	topicName                     string
   255  	serverStateChangeTimeout      time.Duration
   256  	workerPoolSize                int
   257  	clientType                    aggclient.AggregatorClientType
   258  	clientBatchSize               int
   259  	clientConnectionOpts          aggclient.ConnectionOptions
   260  	electionStateChangeTimeout    time.Duration
   261  	entryCheckInterval            time.Duration
   262  	jitterEnabled                 bool
   263  	maxJitterFn                   aggregator.FlushJitterFn
   264  	maxAllowedForwardingDelayFn   aggregator.MaxAllowedForwardingDelayFn
   265  	discardNaNAggregatedValues    bool
   266  	resendBufferForPastTimeMetric time.Duration
   267  	entryTTL                      time.Duration
   268  }
   269  
   270  func newTestServerOptions(t *testing.T) testServerOptions {
   271  	clientType, err := getAggregatorClientTypeFromEnv()
   272  	require.NoError(t, err)
   273  	instanceID := defaultRawTCPAddr
   274  	if clientType == aggclient.M3MsgAggregatorClient {
   275  		instanceID = defaultM3MsgAddr
   276  	}
   277  
   278  	aggTypesOpts := aggregation.NewTypesOptions().
   279  		SetCounterTypeStringTransformFn(aggregation.EmptyTransform).
   280  		SetTimerTypeStringTransformFn(aggregation.SuffixTransform).
   281  		SetGaugeTypeStringTransformFn(aggregation.EmptyTransform)
   282  	connOpts := aggclient.NewConnectionOptions().SetWriteTimeout(time.Second)
   283  	return &serverOptions{
   284  		rawTCPAddr:                  defaultRawTCPAddr,
   285  		httpAddr:                    defaultHTTPAddr,
   286  		m3MsgAddr:                   defaultM3MsgAddr,
   287  		clockOpts:                   clock.NewOptions(),
   288  		instrumentOpts:              instrument.NewOptions(),
   289  		aggTypesOpts:                aggTypesOpts,
   290  		instanceID:                  instanceID,
   291  		electionKeyFmt:              defaultElectionKeyFmt,
   292  		shardSetID:                  defaultShardSetID,
   293  		shardFn:                     sharding.Murmur32Hash.MustShardFn(),
   294  		placementKVKey:              defaultPlacementKVKey,
   295  		flushTimesKeyFmt:            defaultFlushTimesKeyFmt,
   296  		clusterClient:               memcluster.New(kv.NewOverrideOptions()),
   297  		topicService:                nil,
   298  		topicName:                   defaultTopicName,
   299  		serverStateChangeTimeout:    defaultServerStateChangeTimeout,
   300  		workerPoolSize:              defaultWorkerPoolSize,
   301  		clientType:                  clientType,
   302  		clientBatchSize:             defaultClientBatchSize,
   303  		clientConnectionOpts:        connOpts,
   304  		electionStateChangeTimeout:  defaultElectionStateChangeTimeout,
   305  		jitterEnabled:               defaultJitterEnabled,
   306  		entryCheckInterval:          defaultEntryCheckInterval,
   307  		maxJitterFn:                 defaultMaxJitterFn,
   308  		maxAllowedForwardingDelayFn: defaultMaxAllowedForwardingDelayFn,
   309  		discardNaNAggregatedValues:  defaultDiscardNaNAggregatedValues,
   310  		entryTTL:                    defaultEntryTTL,
   311  	}
   312  }
   313  
   314  func (o *serverOptions) SetClockOptions(value clock.Options) testServerOptions {
   315  	opts := *o
   316  	opts.clockOpts = value
   317  	return &opts
   318  }
   319  
   320  func (o *serverOptions) ClockOptions() clock.Options {
   321  	return o.clockOpts
   322  }
   323  
   324  func (o *serverOptions) SetInstrumentOptions(value instrument.Options) testServerOptions {
   325  	opts := *o
   326  	opts.instrumentOpts = value
   327  	return &opts
   328  }
   329  
   330  func (o *serverOptions) InstrumentOptions() instrument.Options {
   331  	return o.instrumentOpts
   332  }
   333  
   334  func (o *serverOptions) SetAggregationTypesOptions(value aggregation.TypesOptions) testServerOptions {
   335  	opts := *o
   336  	opts.aggTypesOpts = value
   337  	return &opts
   338  }
   339  
   340  func (o *serverOptions) AggregationTypesOptions() aggregation.TypesOptions {
   341  	return o.aggTypesOpts
   342  }
   343  
   344  func (o *serverOptions) SetRawTCPAddr(value string) testServerOptions {
   345  	opts := *o
   346  	opts.rawTCPAddr = value
   347  	return &opts
   348  }
   349  
   350  func (o *serverOptions) RawTCPAddr() string {
   351  	return o.rawTCPAddr
   352  }
   353  
   354  func (o *serverOptions) SetHTTPAddr(value string) testServerOptions {
   355  	opts := *o
   356  	opts.httpAddr = value
   357  	return &opts
   358  }
   359  
   360  func (o *serverOptions) M3MsgAddr() string {
   361  	return o.m3MsgAddr
   362  }
   363  
   364  func (o *serverOptions) SetM3MsgAddr(value string) testServerOptions {
   365  	opts := *o
   366  	opts.m3MsgAddr = value
   367  	return &opts
   368  }
   369  
   370  func (o *serverOptions) HTTPAddr() string {
   371  	return o.httpAddr
   372  }
   373  
   374  func (o *serverOptions) SetInstanceID(value string) testServerOptions {
   375  	opts := *o
   376  	opts.instanceID = value
   377  	return &opts
   378  }
   379  
   380  func (o *serverOptions) InstanceID() string {
   381  	return o.instanceID
   382  }
   383  
   384  func (o *serverOptions) SetElectionKeyFmt(value string) testServerOptions {
   385  	opts := *o
   386  	opts.electionKeyFmt = value
   387  	return &opts
   388  }
   389  
   390  func (o *serverOptions) ElectionKeyFmt() string {
   391  	return o.electionKeyFmt
   392  }
   393  
   394  func (o *serverOptions) SetElectionCluster(value *testCluster) testServerOptions {
   395  	opts := *o
   396  	opts.electionCluster = value
   397  	return &opts
   398  }
   399  
   400  func (o *serverOptions) ElectionCluster() *testCluster {
   401  	return o.electionCluster
   402  }
   403  
   404  func (o *serverOptions) SetShardSetID(value uint32) testServerOptions {
   405  	opts := *o
   406  	opts.shardSetID = value
   407  	return &opts
   408  }
   409  
   410  func (o *serverOptions) ShardSetID() uint32 {
   411  	return o.shardSetID
   412  }
   413  
   414  func (o *serverOptions) SetShardFn(value sharding.ShardFn) testServerOptions {
   415  	opts := *o
   416  	opts.shardFn = value
   417  	return &opts
   418  }
   419  
   420  func (o *serverOptions) ShardFn() sharding.ShardFn {
   421  	return o.shardFn
   422  }
   423  
   424  func (o *serverOptions) SetPlacementKVKey(value string) testServerOptions {
   425  	opts := *o
   426  	opts.placementKVKey = value
   427  	return &opts
   428  }
   429  
   430  func (o *serverOptions) PlacementKVKey() string {
   431  	return o.placementKVKey
   432  }
   433  
   434  func (o *serverOptions) SetFlushTimesKeyFmt(value string) testServerOptions {
   435  	opts := *o
   436  	opts.flushTimesKeyFmt = value
   437  	return &opts
   438  }
   439  
   440  func (o *serverOptions) FlushTimesKeyFmt() string {
   441  	return o.flushTimesKeyFmt
   442  }
   443  
   444  func (o *serverOptions) SetClusterClient(value cluster.Client) testServerOptions {
   445  	opts := *o
   446  	opts.clusterClient = value
   447  	return &opts
   448  }
   449  
   450  func (o *serverOptions) ClusterClient() cluster.Client {
   451  	return o.clusterClient
   452  }
   453  
   454  func (o *serverOptions) SetTopicService(value topic.Service) testServerOptions {
   455  	opts := *o
   456  	opts.topicService = value
   457  	return &opts
   458  }
   459  
   460  func (o *serverOptions) TopicService() topic.Service {
   461  	return o.topicService
   462  }
   463  
   464  func (o *serverOptions) SetTopicName(value string) testServerOptions {
   465  	opts := *o
   466  	opts.topicName = value
   467  	return &opts
   468  }
   469  
   470  func (o *serverOptions) TopicName() string {
   471  	return o.topicName
   472  }
   473  
   474  func (o *serverOptions) SetAggregatorClientType(value aggclient.AggregatorClientType) testServerOptions {
   475  	opts := *o
   476  	opts.clientType = value
   477  	return &opts
   478  }
   479  
   480  func (o *serverOptions) AggregatorClientType() aggclient.AggregatorClientType {
   481  	return o.clientType
   482  }
   483  
   484  func (o *serverOptions) SetClientBatchSize(value int) testServerOptions {
   485  	opts := *o
   486  	opts.clientBatchSize = value
   487  	return &opts
   488  }
   489  
   490  func (o *serverOptions) ClientBatchSize() int {
   491  	return o.clientBatchSize
   492  }
   493  
   494  func (o *serverOptions) SetClientConnectionOptions(value aggclient.ConnectionOptions) testServerOptions {
   495  	opts := *o
   496  	opts.clientConnectionOpts = value
   497  	return &opts
   498  }
   499  
   500  func (o *serverOptions) ClientConnectionOptions() aggclient.ConnectionOptions {
   501  	return o.clientConnectionOpts
   502  }
   503  
   504  func (o *serverOptions) SetServerStateChangeTimeout(value time.Duration) testServerOptions {
   505  	opts := *o
   506  	opts.serverStateChangeTimeout = value
   507  	return &opts
   508  }
   509  
   510  func (o *serverOptions) ServerStateChangeTimeout() time.Duration {
   511  	return o.serverStateChangeTimeout
   512  }
   513  
   514  func (o *serverOptions) SetElectionStateChangeTimeout(value time.Duration) testServerOptions {
   515  	opts := *o
   516  	opts.electionStateChangeTimeout = value
   517  	return &opts
   518  }
   519  
   520  func (o *serverOptions) ElectionStateChangeTimeout() time.Duration {
   521  	return o.electionStateChangeTimeout
   522  }
   523  
   524  func (o *serverOptions) SetWorkerPoolSize(value int) testServerOptions {
   525  	opts := *o
   526  	opts.workerPoolSize = value
   527  	return &opts
   528  }
   529  
   530  func (o *serverOptions) WorkerPoolSize() int {
   531  	return o.workerPoolSize
   532  }
   533  
   534  func (o *serverOptions) SetEntryCheckInterval(value time.Duration) testServerOptions {
   535  	opts := *o
   536  	opts.entryCheckInterval = value
   537  	return &opts
   538  }
   539  
   540  func (o *serverOptions) EntryCheckInterval() time.Duration {
   541  	return o.entryCheckInterval
   542  }
   543  
   544  func (o *serverOptions) SetJitterEnabled(value bool) testServerOptions {
   545  	opts := *o
   546  	opts.jitterEnabled = value
   547  	return &opts
   548  }
   549  
   550  func (o *serverOptions) JitterEnabled() bool {
   551  	return o.jitterEnabled
   552  }
   553  
   554  func (o *serverOptions) SetMaxJitterFn(value aggregator.FlushJitterFn) testServerOptions {
   555  	opts := *o
   556  	opts.maxJitterFn = value
   557  	return &opts
   558  }
   559  
   560  func (o *serverOptions) MaxJitterFn() aggregator.FlushJitterFn {
   561  	return o.maxJitterFn
   562  }
   563  
   564  func (o *serverOptions) SetMaxAllowedForwardingDelayFn(value aggregator.MaxAllowedForwardingDelayFn) testServerOptions {
   565  	opts := *o
   566  	opts.maxAllowedForwardingDelayFn = value
   567  	return &opts
   568  }
   569  
   570  func (o *serverOptions) MaxAllowedForwardingDelayFn() aggregator.MaxAllowedForwardingDelayFn {
   571  	return o.maxAllowedForwardingDelayFn
   572  }
   573  
   574  func (o *serverOptions) SetBufferForPastTimedMetric(value time.Duration) testServerOptions {
   575  	opts := *o
   576  	opts.resendBufferForPastTimeMetric = value
   577  	return &opts
   578  }
   579  
   580  func (o *serverOptions) BufferForPastTimedMetric() time.Duration {
   581  	return o.resendBufferForPastTimeMetric
   582  }
   583  
   584  func (o *serverOptions) SetDiscardNaNAggregatedValues(value bool) testServerOptions {
   585  	opts := *o
   586  	opts.discardNaNAggregatedValues = value
   587  	return &opts
   588  }
   589  
   590  func (o *serverOptions) DiscardNaNAggregatedValues() bool {
   591  	return o.discardNaNAggregatedValues
   592  }
   593  
   594  func (o *serverOptions) SetEntryTTL(value time.Duration) testServerOptions {
   595  	opts := *o
   596  	opts.entryTTL = value
   597  	return &opts
   598  }
   599  
   600  func (o *serverOptions) EntryTTL() time.Duration {
   601  	return o.entryTTL
   602  }
   603  
   604  func defaultMaxJitterFn(interval time.Duration) time.Duration {
   605  	return time.Duration(0.75 * float64(interval))
   606  }
   607  
   608  func defaultMaxAllowedForwardingDelayFn(
   609  	resolution time.Duration,
   610  	numForwardedTimes int,
   611  ) time.Duration {
   612  	return resolution + time.Second*time.Duration(numForwardedTimes)
   613  }