Skip to content

Commit 266bb5c

Browse files
committed
pkg/services/orgresolver: add cached OrgResolver
1 parent 218fe4a commit 266bb5c

File tree

1 file changed

+99
-0
lines changed

1 file changed

+99
-0
lines changed

pkg/services/orgresolver/cache.go

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
package orgresolver
2+
3+
import (
4+
"context"
5+
"sync"
6+
"time"
7+
)
8+
9+
const (
10+
cacheDurationOrg = 24 * time.Hour
11+
cacheDurationError = time.Minute
12+
)
13+
14+
type entry struct {
15+
orgID string
16+
err error
17+
expiration time.Time
18+
}
19+
20+
var _ OrgResolver = (*cached)(nil)
21+
22+
type cached struct {
23+
OrgResolver
24+
mu sync.RWMutex
25+
m map[string]entry
26+
stop, done chan struct{}
27+
}
28+
29+
func NewCache(orgResolver OrgResolver) OrgResolver {
30+
return &cached{OrgResolver: orgResolver, m: make(map[string]entry)}
31+
}
32+
33+
func (c *cached) Start(ctx context.Context) error {
34+
err := c.OrgResolver.Start(ctx)
35+
if err == nil {
36+
go c.reaper()
37+
}
38+
return err
39+
}
40+
41+
func (c *cached) Close() error {
42+
close(c.stop)
43+
return c.OrgResolver.Close()
44+
}
45+
46+
func (c *cached) reaper() {
47+
defer close(c.done)
48+
t := time.NewTicker(time.Hour)
49+
defer t.Stop()
50+
for {
51+
select {
52+
case <-c.stop:
53+
return
54+
case <-t.C:
55+
c.reap()
56+
}
57+
}
58+
}
59+
func (c *cached) reap() {
60+
for owner, e := range c.m {
61+
if e.expiration.Before(time.Now()) {
62+
delete(c.m, owner)
63+
}
64+
}
65+
}
66+
67+
func (c *cached) Get(ctx context.Context, owner string) (string, error) {
68+
// fast path
69+
c.mu.RLock()
70+
e, ok := c.m[owner]
71+
if ok && e.expiration.After(time.Now()) {
72+
c.mu.RUnlock()
73+
return e.orgID, e.err
74+
}
75+
c.mu.RUnlock()
76+
77+
// maybe update
78+
c.mu.Lock()
79+
defer c.mu.Unlock()
80+
if ok && e.expiration.After(time.Now()) {
81+
return e.orgID, e.err // already updated
82+
}
83+
84+
// update
85+
orgID, err := c.OrgResolver.Get(ctx, owner)
86+
if err != nil {
87+
c.m[owner] = entry{
88+
err: err,
89+
expiration: time.Now().Add(cacheDurationError),
90+
}
91+
} else {
92+
c.m[owner] = entry{
93+
orgID: orgID,
94+
expiration: time.Now().Add(cacheDurationOrg),
95+
}
96+
}
97+
98+
return orgID, err
99+
}

0 commit comments

Comments
 (0)