forked from dexidp/dex
-
Notifications
You must be signed in to change notification settings - Fork 0
/
gc.go
107 lines (91 loc) · 1.87 KB
/
gc.go
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
package db
import (
"time"
"github.com/go-gorp/gorp"
"github.com/jonboulle/clockwork"
"github.com/coreos/dex/pkg/log"
ptime "github.com/coreos/dex/pkg/time"
)
type purger interface {
purge() error
}
type namedPurger struct {
name string
purger
}
func NewGarbageCollector(dbm *gorp.DbMap, ival time.Duration) *GarbageCollector {
sRepo := NewSessionRepo(dbm)
skRepo := NewSessionKeyRepo(dbm)
purgers := []namedPurger{
namedPurger{
name: "session",
purger: sRepo,
},
namedPurger{
name: "session_key",
purger: skRepo,
},
}
gc := GarbageCollector{
purgers: purgers,
interval: ival,
clock: clockwork.NewRealClock(),
}
return &gc
}
type GarbageCollector struct {
purgers []namedPurger
interval time.Duration
clock clockwork.Clock
}
func (gc *GarbageCollector) Run() chan struct{} {
stop := make(chan struct{})
go func() {
var failing bool
next := gc.interval
for {
select {
case <-gc.clock.After(next):
if anyPurgeErrors(purgeAll(gc.purgers)) {
if !failing {
failing = true
next = time.Second
} else {
next = ptime.ExpBackoff(next, time.Minute)
}
log.Errorf("Failed garbage collection, retrying in %v", next)
break
}
failing = false
next = gc.interval
log.Infof("Garbage collection complete, running again in %v", next)
case <-stop:
return
}
}
}()
return stop
}
type purgeError struct {
name string
err error
}
func anyPurgeErrors(errchan <-chan purgeError) (found bool) {
for perr := range errchan {
found = true
log.Errorf("Failed purging %s: %v", perr.name, perr.err)
}
return
}
func purgeAll(purgers []namedPurger) <-chan purgeError {
errchan := make(chan purgeError)
go func() {
for _, p := range purgers {
if err := p.purge(); err != nil {
errchan <- purgeError{name: p.name, err: err}
}
}
close(errchan)
}()
return errchan
}