@@ -10,24 +10,48 @@ import (
10
10
11
11
"cdr.dev/slog"
12
12
"github.com/coder/coder/coderd/database"
13
+ "github.com/coder/coder/coderd/database/dbauthz"
14
+ "github.com/coder/coder/cryptorand"
13
15
)
14
16
17
+ const (
18
+ jitter = 2 * time .Hour
19
+ delay = 23 * time .Hour
20
+ )
21
+
22
+ func nextTick () (time.Duration , error ) {
23
+ f , err := cryptorand .Float64 ()
24
+ if err != nil {
25
+ return 0 , err
26
+ }
27
+
28
+ return delay + time .Duration (float64 (jitter )* f ), nil
29
+ }
30
+
15
31
// New creates a new periodically purging database instance.
16
32
// It is the caller's responsibility to call Close on the returned instance.
17
33
//
18
34
// This is for cleaning up old, unused resources from the database that take up space.
19
35
func New (ctx context.Context , logger slog.Logger , db database.Store ) io.Closer {
20
36
closed := make (chan struct {})
21
37
ctx , cancelFunc := context .WithCancel (ctx )
38
+ //nolint:gocritic // The system purges old db records without user input.
39
+ ctx = dbauthz .AsSystemRestricted (ctx )
22
40
go func () {
23
41
defer close (closed )
24
- ticker := time .NewTicker (24 * time .Hour )
25
- defer ticker .Stop ()
42
+ wait , err := nextTick ()
43
+ if err != nil {
44
+ logger .Error (ctx , "failed to generate random delay; exiting" , slog .Error (err ))
45
+ return
46
+ }
47
+
48
+ timer := time .NewTimer (wait )
49
+ defer timer .Stop ()
26
50
for {
27
51
select {
28
52
case <- ctx .Done ():
29
53
return
30
- case <- ticker .C :
54
+ case <- timer .C :
31
55
}
32
56
33
57
var eg errgroup.Group
@@ -44,6 +68,13 @@ func New(ctx context.Context, logger slog.Logger, db database.Store) io.Closer {
44
68
}
45
69
logger .Error (ctx , "failed to purge old database entries" , slog .Error (err ))
46
70
}
71
+
72
+ wait , err := nextTick ()
73
+ if err != nil {
74
+ logger .Error (ctx , "failed to generate random delay; exiting" , slog .Error (err ))
75
+ return
76
+ }
77
+ timer .Reset (wait )
47
78
}
48
79
}()
49
80
return & instance {
0 commit comments