File: timer.go

package info (click to toggle)
golang-github-juju-utils 0.0~git20171220.f38c0b0-5
  • links: PTS, VCS
  • area: main
  • in suites: buster
  • size: 1,748 kB
  • sloc: makefile: 20
file content (124 lines) | stat: -rw-r--r-- 3,632 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
// Copyright 2015 Canonical Ltd.
// Copyright 2015 Cloudbase Solutions SRL
// Licensed under the LGPLv3, see LICENCE file for details.

package utils

import (
	"math/rand"
	"time"

	"github.com/juju/utils/clock"
)

// Countdown implements a timer that will call a provided function.
// after a internally stored duration. The steps as well as min and max
// durations are declared upon initialization and depend on
// the particular implementation.
//
// TODO(katco): 2016-08-09: This type is deprecated: lp:1611427
type Countdown interface {
	// Reset stops the timer and resets its duration to the minimum one.
	// Start must be called to start the timer again.
	Reset()

	// Start starts the internal timer.
	// At the end of the timer, if Reset hasn't been called in the mean time
	// Func will be called and the duration is increased for the next call.
	Start()
}

// NewBackoffTimer creates and initializes a new BackoffTimer
// A backoff timer starts at min and gets multiplied by factor
// until it reaches max. Jitter determines whether a small
// randomization is added to the duration.
//
// TODO(katco): 2016-08-09: This type is deprecated: lp:1611427
func NewBackoffTimer(config BackoffTimerConfig) *BackoffTimer {
	return &BackoffTimer{
		config:          config,
		currentDuration: config.Min,
	}
}

// BackoffTimer implements Countdown.
// A backoff timer starts at min and gets multiplied by factor
// until it reaches max. Jitter determines whether a small
// randomization is added to the duration.
//
// TODO(katco): 2016-08-09: This type is deprecated: lp:1611427
type BackoffTimer struct {
	config BackoffTimerConfig

	timer           clock.Timer
	currentDuration time.Duration
}

// BackoffTimerConfig is a helper struct for backoff timer
// that encapsulates config information.
//
// TODO(katco): 2016-08-09: This type is deprecated: lp:1611427
type BackoffTimerConfig struct {
	// The minimum duration after which Func is called.
	Min time.Duration

	// The maximum duration after which Func is called.
	Max time.Duration

	// Determines whether a small randomization is applied to
	// the duration.
	Jitter bool

	// The factor by which you want the duration to increase
	// every time.
	Factor int64

	// Func is the function that will be called when the countdown reaches 0.
	Func func()

	// Clock provides the AfterFunc function used to call func.
	// It is exposed here so it's easier to mock it in tests.
	Clock clock.Clock
}

// Start implements the Timer interface.
// Any existing timer execution is stopped before
// a new one is created.
func (t *BackoffTimer) Start() {
	if t.timer != nil {
		t.timer.Stop()
	}
	t.timer = t.config.Clock.AfterFunc(t.currentDuration, t.config.Func)

	// Since it's a backoff timer we will increase
	// the duration after each signal.
	t.increaseDuration()
}

// Reset implements the Timer interface.
func (t *BackoffTimer) Reset() {
	if t.timer != nil {
		t.timer.Stop()
	}
	if t.currentDuration > t.config.Min {
		t.currentDuration = t.config.Min
	}
}

// increaseDuration will increase the duration based on
// the current value and the factor. If jitter is true
// it will add a 0.3% jitter to the final value.
func (t *BackoffTimer) increaseDuration() {
	current := int64(t.currentDuration)
	nextDuration := time.Duration(current * t.config.Factor)
	if t.config.Jitter {
		// Get a factor in [-1; 1].
		randFactor := (rand.Float64() * 2) - 1
		jitter := float64(nextDuration) * randFactor * 0.03
		nextDuration = nextDuration + time.Duration(jitter)
	}
	if nextDuration > t.config.Max {
		nextDuration = t.config.Max
	}
	t.currentDuration = nextDuration
}