Skip to content

Commit ed3bf59

Browse files
gudvinrfguillot
authored andcommitted
refactor(reader): use time.Duration instead of minutes count
In general, duration is used as time unit representation. At some places when int is returned, there's no documentation which unit is used. So just convert to time.Duration ASAP.
1 parent 03021af commit ed3bf59

File tree

10 files changed

+144
-104
lines changed

10 files changed

+144
-104
lines changed

internal/config/config_test.go

Lines changed: 46 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,9 @@ import (
77
"bytes"
88
"os"
99
"reflect"
10+
"slices"
1011
"testing"
12+
"time"
1113
)
1214

1315
func TestLogFileDefaultValue(t *testing.T) {
@@ -887,12 +889,22 @@ func TestSchedulerEntryFrequencyMaxInterval(t *testing.T) {
887889
t.Fatalf(`Parsing failure: %v`, err)
888890
}
889891

890-
expected := 30
892+
expected := 30 * time.Minute
891893
result := opts.SchedulerEntryFrequencyMaxInterval()
892894

893895
if result != expected {
894896
t.Fatalf(`Unexpected SCHEDULER_ENTRY_FREQUENCY_MAX_INTERVAL value, got %v instead of %v`, result, expected)
895897
}
898+
899+
sorted := opts.SortedOptions(false)
900+
i := slices.IndexFunc(sorted, func(opt *option) bool {
901+
return opt.Key == "SCHEDULER_ENTRY_FREQUENCY_MAX_INTERVAL"
902+
})
903+
904+
expectedSerialized := 30
905+
if got := sorted[i].Value; got != expectedSerialized {
906+
t.Fatalf(`Unexpected value in option output, got %q instead of %q`, got, expectedSerialized)
907+
}
896908
}
897909

898910
func TestDefaultSchedulerEntryFrequencyMinIntervalValue(t *testing.T) {
@@ -922,12 +934,22 @@ func TestSchedulerEntryFrequencyMinInterval(t *testing.T) {
922934
t.Fatalf(`Parsing failure: %v`, err)
923935
}
924936

925-
expected := 30
937+
expected := 30 * time.Minute
926938
result := opts.SchedulerEntryFrequencyMinInterval()
927939

928940
if result != expected {
929941
t.Fatalf(`Unexpected SCHEDULER_ENTRY_FREQUENCY_MIN_INTERVAL value, got %v instead of %v`, result, expected)
930942
}
943+
944+
sorted := opts.SortedOptions(false)
945+
i := slices.IndexFunc(sorted, func(opt *option) bool {
946+
return opt.Key == "SCHEDULER_ENTRY_FREQUENCY_MIN_INTERVAL"
947+
})
948+
949+
expectedSerialized := 30
950+
if got := sorted[i].Value; got != expectedSerialized {
951+
t.Fatalf(`Unexpected value in option output, got %q instead of %q`, got, expectedSerialized)
952+
}
931953
}
932954

933955
func TestDefaultSchedulerEntryFrequencyFactorValue(t *testing.T) {
@@ -992,12 +1014,22 @@ func TestSchedulerRoundRobin(t *testing.T) {
9921014
t.Fatalf(`Parsing failure: %v`, err)
9931015
}
9941016

995-
expected := 15
1017+
expected := 15 * time.Minute
9961018
result := opts.SchedulerRoundRobinMinInterval()
9971019

9981020
if result != expected {
9991021
t.Fatalf(`Unexpected SCHEDULER_ROUND_ROBIN_MIN_INTERVAL value, got %v instead of %v`, result, expected)
10001022
}
1023+
1024+
sorted := opts.SortedOptions(false)
1025+
i := slices.IndexFunc(sorted, func(opt *option) bool {
1026+
return opt.Key == "SCHEDULER_ROUND_ROBIN_MIN_INTERVAL"
1027+
})
1028+
1029+
expectedSerialized := 15
1030+
if got := sorted[i].Value; got != expectedSerialized {
1031+
t.Fatalf(`Unexpected value in option output, got %q instead of %q`, got, expectedSerialized)
1032+
}
10011033
}
10021034

10031035
func TestDefaultSchedulerRoundRobinMaxIntervalValue(t *testing.T) {
@@ -1027,12 +1059,22 @@ func TestSchedulerRoundRobinMaxInterval(t *testing.T) {
10271059
t.Fatalf(`Parsing failure: %v`, err)
10281060
}
10291061

1030-
expected := 150
1062+
expected := 150 * time.Minute
10311063
result := opts.SchedulerRoundRobinMaxInterval()
10321064

10331065
if result != expected {
10341066
t.Fatalf(`Unexpected SCHEDULER_ROUND_ROBIN_MAX_INTERVAL value, got %v instead of %v`, result, expected)
10351067
}
1068+
1069+
sorted := opts.SortedOptions(false)
1070+
i := slices.IndexFunc(sorted, func(opt *option) bool {
1071+
return opt.Key == "SCHEDULER_ROUND_ROBIN_MAX_INTERVAL"
1072+
})
1073+
1074+
expectedSerialized := 150
1075+
if got := sorted[i].Value; got != expectedSerialized {
1076+
t.Fatalf(`Unexpected value in option output, got %q instead of %q`, got, expectedSerialized)
1077+
}
10361078
}
10371079

10381080
func TestPollingParsingErrorLimit(t *testing.T) {

internal/config/options.go

Lines changed: 18 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -32,11 +32,11 @@ const (
3232
defaultForceRefreshInterval = 30
3333
defaultBatchSize = 100
3434
defaultPollingScheduler = "round_robin"
35-
defaultSchedulerEntryFrequencyMinInterval = 5
36-
defaultSchedulerEntryFrequencyMaxInterval = 24 * 60
35+
defaultSchedulerEntryFrequencyMinInterval = 5 * time.Minute
36+
defaultSchedulerEntryFrequencyMaxInterval = 24 * time.Hour
3737
defaultSchedulerEntryFrequencyFactor = 1
38-
defaultSchedulerRoundRobinMinInterval = 60
39-
defaultSchedulerRoundRobinMaxInterval = 1440
38+
defaultSchedulerRoundRobinMinInterval = 1 * time.Hour
39+
defaultSchedulerRoundRobinMaxInterval = 24 * time.Hour
4040
defaultPollingParsingErrorLimit = 3
4141
defaultRunMigrations = false
4242
defaultDatabaseURL = "user=postgres password=postgres dbname=miniflux2 sslmode=disable"
@@ -132,11 +132,11 @@ type options struct {
132132
cleanupRemoveSessionsDays int
133133
forceRefreshInterval int
134134
batchSize int
135-
schedulerEntryFrequencyMinInterval int
136-
schedulerEntryFrequencyMaxInterval int
135+
schedulerEntryFrequencyMinInterval time.Duration
136+
schedulerEntryFrequencyMaxInterval time.Duration
137137
schedulerEntryFrequencyFactor int
138-
schedulerRoundRobinMinInterval int
139-
schedulerRoundRobinMaxInterval int
138+
schedulerRoundRobinMinInterval time.Duration
139+
schedulerRoundRobinMaxInterval time.Duration
140140
pollingFrequency int
141141
pollingLimitPerHost int
142142
pollingParsingErrorLimit int
@@ -422,13 +422,13 @@ func (o *options) PollingScheduler() string {
422422
return o.pollingScheduler
423423
}
424424

425-
// SchedulerEntryFrequencyMaxInterval returns the maximum interval in minutes for the entry frequency scheduler.
426-
func (o *options) SchedulerEntryFrequencyMaxInterval() int {
425+
// SchedulerEntryFrequencyMaxInterval returns the maximum interval for the entry frequency scheduler.
426+
func (o *options) SchedulerEntryFrequencyMaxInterval() time.Duration {
427427
return o.schedulerEntryFrequencyMaxInterval
428428
}
429429

430-
// SchedulerEntryFrequencyMinInterval returns the minimum interval in minutes for the entry frequency scheduler.
431-
func (o *options) SchedulerEntryFrequencyMinInterval() int {
430+
// SchedulerEntryFrequencyMinInterval returns the minimum interval for the entry frequency scheduler.
431+
func (o *options) SchedulerEntryFrequencyMinInterval() time.Duration {
432432
return o.schedulerEntryFrequencyMinInterval
433433
}
434434

@@ -437,11 +437,11 @@ func (o *options) SchedulerEntryFrequencyFactor() int {
437437
return o.schedulerEntryFrequencyFactor
438438
}
439439

440-
func (o *options) SchedulerRoundRobinMinInterval() int {
440+
func (o *options) SchedulerRoundRobinMinInterval() time.Duration {
441441
return o.schedulerRoundRobinMinInterval
442442
}
443443

444-
func (o *options) SchedulerRoundRobinMaxInterval() int {
444+
func (o *options) SchedulerRoundRobinMaxInterval() time.Duration {
445445
return o.schedulerRoundRobinMaxInterval
446446
}
447447

@@ -781,11 +781,11 @@ func (o *options) SortedOptions(redactSecret bool) []*option {
781781
"MEDIA_PROXY_CUSTOM_URL": o.mediaProxyCustomURL,
782782
"ROOT_URL": o.rootURL,
783783
"RUN_MIGRATIONS": o.runMigrations,
784-
"SCHEDULER_ENTRY_FREQUENCY_MAX_INTERVAL": o.schedulerEntryFrequencyMaxInterval,
785-
"SCHEDULER_ENTRY_FREQUENCY_MIN_INTERVAL": o.schedulerEntryFrequencyMinInterval,
784+
"SCHEDULER_ENTRY_FREQUENCY_MAX_INTERVAL": int(o.schedulerEntryFrequencyMaxInterval.Minutes()),
785+
"SCHEDULER_ENTRY_FREQUENCY_MIN_INTERVAL": int(o.schedulerEntryFrequencyMinInterval.Minutes()),
786786
"SCHEDULER_ENTRY_FREQUENCY_FACTOR": o.schedulerEntryFrequencyFactor,
787-
"SCHEDULER_ROUND_ROBIN_MIN_INTERVAL": o.schedulerRoundRobinMinInterval,
788-
"SCHEDULER_ROUND_ROBIN_MAX_INTERVAL": o.schedulerRoundRobinMaxInterval,
787+
"SCHEDULER_ROUND_ROBIN_MIN_INTERVAL": int(o.schedulerRoundRobinMinInterval.Minutes()),
788+
"SCHEDULER_ROUND_ROBIN_MAX_INTERVAL": int(o.schedulerRoundRobinMaxInterval.Minutes()),
789789
"SCHEDULER_SERVICE": o.schedulerService,
790790
"WATCHDOG": o.watchdog,
791791
"WORKER_POOL_SIZE": o.workerPoolSize,

internal/config/parser.go

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import (
1414
"os"
1515
"strconv"
1616
"strings"
17+
"time"
1718
)
1819

1920
// parser handles configuration parsing.
@@ -150,15 +151,15 @@ func (p *parser) parseLines(lines []string) (err error) {
150151
case "POLLING_SCHEDULER":
151152
p.opts.pollingScheduler = strings.ToLower(parseString(value, defaultPollingScheduler))
152153
case "SCHEDULER_ENTRY_FREQUENCY_MAX_INTERVAL":
153-
p.opts.schedulerEntryFrequencyMaxInterval = parseInt(value, defaultSchedulerEntryFrequencyMaxInterval)
154+
p.opts.schedulerEntryFrequencyMaxInterval = parseInterval(value, time.Minute, defaultSchedulerEntryFrequencyMaxInterval)
154155
case "SCHEDULER_ENTRY_FREQUENCY_MIN_INTERVAL":
155-
p.opts.schedulerEntryFrequencyMinInterval = parseInt(value, defaultSchedulerEntryFrequencyMinInterval)
156+
p.opts.schedulerEntryFrequencyMinInterval = parseInterval(value, time.Minute, defaultSchedulerEntryFrequencyMinInterval)
156157
case "SCHEDULER_ENTRY_FREQUENCY_FACTOR":
157158
p.opts.schedulerEntryFrequencyFactor = parseInt(value, defaultSchedulerEntryFrequencyFactor)
158159
case "SCHEDULER_ROUND_ROBIN_MIN_INTERVAL":
159-
p.opts.schedulerRoundRobinMinInterval = parseInt(value, defaultSchedulerRoundRobinMinInterval)
160+
p.opts.schedulerRoundRobinMinInterval = parseInterval(value, time.Minute, defaultSchedulerRoundRobinMinInterval)
160161
case "SCHEDULER_ROUND_ROBIN_MAX_INTERVAL":
161-
p.opts.schedulerRoundRobinMaxInterval = parseInt(value, defaultSchedulerRoundRobinMaxInterval)
162+
p.opts.schedulerRoundRobinMaxInterval = parseInterval(value, time.Minute, defaultSchedulerRoundRobinMaxInterval)
162163
case "MEDIA_PROXY_HTTP_CLIENT_TIMEOUT":
163164
p.opts.mediaProxyHTTPClientTimeout = parseInt(value, defaultMediaProxyHTTPClientTimeout)
164165
case "MEDIA_PROXY_MODE":

internal/model/feed.go

Lines changed: 16 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ package model // import "miniflux.app/v2/internal/model"
66
import (
77
"fmt"
88
"io"
9-
"math"
109
"time"
1110

1211
"miniflux.app/v2/internal/config"
@@ -69,11 +68,11 @@ type Feed struct {
6968
Entries Entries `json:"entries,omitempty"`
7069

7170
// Internal attributes (not exposed in the API and not persisted in the database)
72-
TTL int `json:"-"`
73-
IconURL string `json:"-"`
74-
UnreadCount int `json:"-"`
75-
ReadCount int `json:"-"`
76-
NumberOfVisibleEntries int `json:"-"`
71+
TTL time.Duration `json:"-"`
72+
IconURL string `json:"-"`
73+
UnreadCount int `json:"-"`
74+
ReadCount int `json:"-"`
75+
NumberOfVisibleEntries int `json:"-"`
7776
}
7877

7978
type FeedCounters struct {
@@ -119,35 +118,33 @@ func (f *Feed) CheckedNow() {
119118
}
120119

121120
// ScheduleNextCheck set "next_check_at" of a feed based on the scheduler selected from the configuration.
122-
func (f *Feed) ScheduleNextCheck(weeklyCount int, refreshDelayInMinutes int) int {
121+
func (f *Feed) ScheduleNextCheck(weeklyCount int, refreshDelay time.Duration) time.Duration {
123122
// Default to the global config Polling Frequency.
124-
intervalMinutes := config.Opts.SchedulerRoundRobinMinInterval()
123+
interval := config.Opts.SchedulerRoundRobinMinInterval()
125124

126125
if config.Opts.PollingScheduler() == SchedulerEntryFrequency {
127126
if weeklyCount <= 0 {
128-
intervalMinutes = config.Opts.SchedulerEntryFrequencyMaxInterval()
127+
interval = config.Opts.SchedulerEntryFrequencyMaxInterval()
129128
} else {
130-
intervalMinutes = int(math.Round(float64(7*24*60) / float64(weeklyCount*config.Opts.SchedulerEntryFrequencyFactor())))
131-
intervalMinutes = min(intervalMinutes, config.Opts.SchedulerEntryFrequencyMaxInterval())
132-
intervalMinutes = max(intervalMinutes, config.Opts.SchedulerEntryFrequencyMinInterval())
129+
interval = (7 * 24 * time.Hour) / time.Duration(weeklyCount*config.Opts.SchedulerEntryFrequencyFactor())
130+
interval = min(interval, config.Opts.SchedulerEntryFrequencyMaxInterval())
131+
interval = max(interval, config.Opts.SchedulerEntryFrequencyMinInterval())
133132
}
134133
}
135134

136135
// Use the RSS TTL field, Retry-After, Cache-Control or Expires HTTP headers if defined.
137-
if refreshDelayInMinutes > 0 && refreshDelayInMinutes > intervalMinutes {
138-
intervalMinutes = refreshDelayInMinutes
139-
}
136+
interval = max(interval, refreshDelay)
140137

141138
// Limit the max interval value for misconfigured feeds.
142139
switch config.Opts.PollingScheduler() {
143140
case SchedulerRoundRobin:
144-
intervalMinutes = min(intervalMinutes, config.Opts.SchedulerRoundRobinMaxInterval())
141+
interval = min(interval, config.Opts.SchedulerRoundRobinMaxInterval())
145142
case SchedulerEntryFrequency:
146-
intervalMinutes = min(intervalMinutes, config.Opts.SchedulerEntryFrequencyMaxInterval())
143+
interval = min(interval, config.Opts.SchedulerEntryFrequencyMaxInterval())
147144
}
148145

149-
f.NextCheckAt = time.Now().Add(time.Minute * time.Duration(intervalMinutes))
150-
return intervalMinutes
146+
f.NextCheckAt = time.Now().Add(interval)
147+
return interval
151148
}
152149

153150
// FeedCreationRequest represents the request to create a feed.

internal/model/feed_test.go

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -67,11 +67,11 @@ func TestFeedCheckedNow(t *testing.T) {
6767
}
6868
}
6969

70-
func checkTargetInterval(t *testing.T, feed *Feed, targetInterval int, timeBefore time.Time, message string) {
71-
if feed.NextCheckAt.Before(timeBefore.Add(time.Minute * time.Duration(targetInterval))) {
70+
func checkTargetInterval(t *testing.T, feed *Feed, targetInterval time.Duration, timeBefore time.Time, message string) {
71+
if feed.NextCheckAt.Before(timeBefore.Add(targetInterval)) {
7272
t.Errorf(`The next_check_at should be after timeBefore + %s`, message)
7373
}
74-
if feed.NextCheckAt.After(time.Now().Add(time.Minute * time.Duration(targetInterval))) {
74+
if feed.NextCheckAt.After(time.Now().Add(targetInterval)) {
7575
t.Errorf(`The next_check_at should be before now + %s`, message)
7676
}
7777
}
@@ -188,7 +188,7 @@ func TestFeedScheduleNextCheckRoundRobinMinInterval(t *testing.T) {
188188
t.Error(`The next_check_at must be set`)
189189
}
190190

191-
expectedInterval := minInterval
191+
expectedInterval := time.Duration(minInterval) * time.Minute
192192
checkTargetInterval(t, feed, expectedInterval, timeBefore, "TestFeedScheduleNextCheckRoundRobinMinInterval")
193193
}
194194

@@ -217,7 +217,7 @@ func TestFeedScheduleNextCheckEntryFrequencyMaxInterval(t *testing.T) {
217217
t.Error(`The next_check_at must be set`)
218218
}
219219

220-
targetInterval := maxInterval
220+
targetInterval := time.Duration(maxInterval) * time.Minute
221221
checkTargetInterval(t, feed, targetInterval, timeBefore, "entry frequency max interval")
222222
}
223223

@@ -246,7 +246,7 @@ func TestFeedScheduleNextCheckEntryFrequencyMaxIntervalZeroWeeklyCount(t *testin
246246
t.Error(`The next_check_at must be set`)
247247
}
248248

249-
targetInterval := maxInterval
249+
targetInterval := time.Duration(maxInterval) * time.Minute
250250
checkTargetInterval(t, feed, targetInterval, timeBefore, "entry frequency max interval")
251251
}
252252

@@ -275,7 +275,7 @@ func TestFeedScheduleNextCheckEntryFrequencyMinInterval(t *testing.T) {
275275
t.Error(`The next_check_at must be set`)
276276
}
277277

278-
targetInterval := minInterval
278+
targetInterval := time.Duration(minInterval) * time.Minute
279279
checkTargetInterval(t, feed, targetInterval, timeBefore, "entry frequency min interval")
280280
}
281281

@@ -301,7 +301,7 @@ func TestFeedScheduleNextCheckEntryFrequencyFactor(t *testing.T) {
301301
t.Error(`The next_check_at must be set`)
302302
}
303303

304-
targetInterval := config.Opts.SchedulerEntryFrequencyMaxInterval() / factor
304+
targetInterval := config.Opts.SchedulerEntryFrequencyMaxInterval() / time.Duration(factor)
305305
checkTargetInterval(t, feed, targetInterval, timeBefore, "factor * count")
306306
}
307307

@@ -326,17 +326,17 @@ func TestFeedScheduleNextCheckEntryFrequencySmallNewTTL(t *testing.T) {
326326
// Use a very large weekly count to trigger the min interval
327327
weeklyCount := largeWeeklyCount
328328
// TTL is smaller than minInterval.
329-
newTTL := minInterval / 2
329+
newTTL := time.Duration(minInterval) * time.Minute / 2
330330
feed.ScheduleNextCheck(weeklyCount, newTTL)
331331

332332
if feed.NextCheckAt.IsZero() {
333333
t.Error(`The next_check_at must be set`)
334334
}
335335

336-
targetInterval := minInterval
336+
targetInterval := time.Duration(minInterval) * time.Minute
337337
checkTargetInterval(t, feed, targetInterval, timeBefore, "entry frequency min interval")
338338

339-
if feed.NextCheckAt.Before(timeBefore.Add(time.Minute * time.Duration(newTTL))) {
339+
if feed.NextCheckAt.Before(timeBefore.Add(newTTL)) {
340340
t.Error(`The next_check_at should be after timeBefore + TTL`)
341341
}
342342
}
@@ -362,7 +362,7 @@ func TestFeedScheduleNextCheckEntryFrequencyLargeNewTTL(t *testing.T) {
362362
// Use a very large weekly count to trigger the min interval
363363
weeklyCount := largeWeeklyCount
364364
// TTL is larger than minInterval.
365-
newTTL := minInterval * 2
365+
newTTL := time.Duration(minInterval) * time.Minute * 2
366366
feed.ScheduleNextCheck(weeklyCount, newTTL)
367367

368368
if feed.NextCheckAt.IsZero() {

0 commit comments

Comments
 (0)