Skip to content

Commit 5537a8f

Browse files
committed
make it generic
1 parent 80e14fe commit 5537a8f

File tree

2 files changed

+38
-39
lines changed

2 files changed

+38
-39
lines changed

logp/ratelimited.go renamed to periodic/ratelimited.go

+28-29
Original file line numberDiff line numberDiff line change
@@ -15,31 +15,31 @@
1515
// specific language governing permissions and limitations
1616
// under the License.
1717

18-
package logp
18+
package periodic
1919

2020
import (
2121
"sync"
2222
"sync/atomic"
2323
"time"
2424
)
2525

26-
// RateLimitedLogger is a logger that limits log messages to at most once within
27-
// a specified period.
28-
// It is intended for logging events that occur frequently, providing a summary
29-
// with the number of occurrences within the given period.
26+
// Doer limits an action to be executed at most once within a specified period.
27+
// It is intended for managing events that occur frequently, but instead of an
28+
// action being taken for every event, the action should be executed at most
29+
// once within a given period of time.
3030
//
31-
// RateLimitedLogger takes a logger function, logFn, which is called every time
32-
// the specified period has elapsed to log the summary.
33-
type RateLimitedLogger struct {
31+
// Doer takes a function to execute, doFn, which is called every time
32+
// the specified period has elapsed with the number of events and the period.
33+
type Doer struct {
3434
count atomic.Uint64
3535

3636
period time.Duration
3737

38-
// logFn is called for logging, which receives the count of events and the
39-
// duration since the last call.
40-
logFn func(count uint64, d time.Duration)
41-
lastLog time.Time
42-
done chan struct{}
38+
// doFn is called for executing the action every period if at least one
39+
// event happened. It receives the count of events and the period.
40+
doFn func(count uint64, d time.Duration)
41+
lastDone time.Time
42+
done chan struct{}
4343

4444
// nowFn is used to acquire the current time instead of time.Now so it can
4545
// be mocked for tests.
@@ -53,35 +53,34 @@ type RateLimitedLogger struct {
5353
ticker *time.Ticker
5454
}
5555

56-
// NewRateLimited returns a new RateLimitedLogger. It takes a logFn, which is
57-
// called with the count of events and the period between each call,
58-
// and a period determining how often the log function should be called.
59-
func NewRateLimited(period time.Duration, logFn func(count uint64, d time.Duration)) *RateLimitedLogger {
60-
return &RateLimitedLogger{
56+
// NewDoer returns a new Doer. It takes a doFn, which is
57+
// called with the current count of events and the period.
58+
func NewDoer(period time.Duration, doFn func(count uint64, d time.Duration)) *Doer {
59+
return &Doer{
6160
period: period,
62-
logFn: logFn,
61+
doFn: doFn,
6362

6463
nowFn: time.Now,
6564
newTickerFn: time.NewTicker,
6665
}
6766
}
6867

69-
func (r *RateLimitedLogger) Add() {
68+
func (r *Doer) Add() {
7069
r.count.Add(1)
7170
}
7271

73-
func (r *RateLimitedLogger) AddN(n uint64) {
72+
func (r *Doer) AddN(n uint64) {
7473
r.count.Add(n)
7574
}
7675

77-
func (r *RateLimitedLogger) Start() {
76+
func (r *Doer) Start() {
7877
if r.started.Load() {
7978
return
8079
}
8180

8281
r.done = make(chan struct{})
8382
r.started.Store(true)
84-
r.lastLog = r.nowFn()
83+
r.lastDone = r.nowFn()
8584
r.ticker = r.newTickerFn(r.period)
8685

8786
r.wg.Add(1)
@@ -93,16 +92,16 @@ func (r *RateLimitedLogger) Start() {
9392
for {
9493
select {
9594
case <-r.ticker.C:
96-
r.log()
95+
r.do()
9796
case <-r.done:
98-
r.log()
97+
r.do()
9998
return
10099
}
101100
}
102101
}()
103102
}
104103

105-
func (r *RateLimitedLogger) Stop() {
104+
func (r *Doer) Stop() {
106105
if !r.started.Load() {
107106
return
108107
}
@@ -112,10 +111,10 @@ func (r *RateLimitedLogger) Stop() {
112111
r.started.Store(false)
113112
}
114113

115-
func (r *RateLimitedLogger) log() {
114+
func (r *Doer) do() {
116115
count := r.count.Swap(0)
117116
if count > 0 {
118-
r.lastLog = r.nowFn()
119-
r.logFn(count, r.period)
117+
r.lastDone = r.nowFn()
118+
r.doFn(count, r.period)
120119
}
121120
}

logp/ratelimited_test.go renamed to periodic/ratelimited_test.go

+10-10
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
// specific language governing permissions and limitations
1616
// under the License.
1717

18-
package logp
18+
package periodic
1919

2020
import (
2121
"bytes"
@@ -65,19 +65,19 @@ func TestRateLimitedLogger(t *testing.T) {
6565
now := time.Now()
6666

6767
t.Run("Start", func(t *testing.T) {
68-
r := NewRateLimited(math.MaxInt64, func(count uint64, d time.Duration) {})
68+
r := NewDoer(math.MaxInt64, func(count uint64, d time.Duration) {})
6969
defer r.Stop()
7070
r.nowFn = func() time.Time { return now }
7171

7272
r.Start()
7373

7474
assert.True(t, r.started.Load(),
7575
"Start() was called, thus 'started' should be true")
76-
assert.NotEmpty(t, r.lastLog, "lastLog should have been set")
76+
assert.NotEmpty(t, r.lastDone, "lastDone should have been set")
7777
})
7878

7979
t.Run("Start twice", func(t *testing.T) {
80-
r := NewRateLimited(math.MaxInt64, func(count uint64, d time.Duration) {})
80+
r := NewDoer(math.MaxInt64, func(count uint64, d time.Duration) {})
8181
defer r.Stop()
8282

8383
r.nowFn = func() time.Time { return now }
@@ -86,7 +86,7 @@ func TestRateLimitedLogger(t *testing.T) {
8686
r.nowFn = func() time.Time { return now.Add(time.Minute) }
8787
r.Start()
8888

89-
assert.Equal(t, now, r.lastLog, "lastLog should have been set a second time")
89+
assert.Equal(t, now, r.lastDone, "lastDone should have been set a second time")
9090
})
9191

9292
t.Run("Stop", func(t *testing.T) {
@@ -101,7 +101,7 @@ func TestRateLimitedLogger(t *testing.T) {
101101
for _, tc := range tcs {
102102
t.Run(tc.name, func(t *testing.T) {
103103
buff, logFn := newLogger()
104-
r := NewRateLimited(42*time.Second, logFn)
104+
r := NewDoer(42*time.Second, logFn)
105105
r.nowFn = func() time.Time { return now }
106106

107107
tch := make(chan time.Time)
@@ -134,7 +134,7 @@ func TestRateLimitedLogger(t *testing.T) {
134134

135135
t.Run("Add", func(t *testing.T) {
136136
buff, logFn := newLogger()
137-
r := NewRateLimited(42*time.Second, logFn)
137+
r := NewDoer(42*time.Second, logFn)
138138
defer r.Stop()
139139

140140
r.nowFn = func() time.Time { return now }
@@ -157,14 +157,14 @@ func TestRateLimitedLogger(t *testing.T) {
157157
logs = strings.TrimSpace(string(bs))
158158

159159
return len(strings.Split(logs, "\n")) == 1
160-
}, time.Second, 100*time.Millisecond, "should have found 1 log")
160+
}, time.Second, 100*time.Millisecond, "should have found 1 do")
161161

162162
assert.Contains(t, logs, fmt.Sprintf(pattern, 1, 42*time.Second))
163163
})
164164

165165
t.Run("AddN", func(t *testing.T) {
166166
buff, logFn := newLogger()
167-
r := NewRateLimited(42*time.Second, logFn)
167+
r := NewDoer(42*time.Second, logFn)
168168
defer r.Stop()
169169

170170
r.nowFn = func() time.Time { return now }
@@ -187,7 +187,7 @@ func TestRateLimitedLogger(t *testing.T) {
187187
logs = strings.TrimSpace(string(bs))
188188

189189
return len(strings.Split(logs, "\n")) == 1
190-
}, time.Second, 100*time.Millisecond, "should have found 1 log")
190+
}, time.Second, 100*time.Millisecond, "should have found 1 do")
191191

192192
assert.Contains(t, logs, fmt.Sprintf(pattern, 42, 42*time.Second))
193193
})

0 commit comments

Comments
 (0)