Skip to content

Commit

Permalink
Add background refresh functionality
Browse files Browse the repository at this point in the history
  • Loading branch information
Nithin Benny committed Sep 26, 2024
1 parent ffa3c85 commit 5fcff7f
Show file tree
Hide file tree
Showing 2 changed files with 57 additions and 3 deletions.
26 changes: 23 additions & 3 deletions cache.go
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,12 @@ type Config struct {
OnEviction func(key, value interface{})
// Optional callback invoked when an item expired
OnExpiration func(key, value interface{})
// Optional refresh interval after which all items in the cache expires.
// If zero, refreshing cache is disabled.
RefreshInterval time.Duration
// Optional on refresh callback invoked when the cache is refreshed
// Both RefreshInterval and OnRefresh must be provided to enable background cache refresh
OnRefresh func() map[interface{}]interface{}
}

// Entry pointed to by each list.Element
Expand Down Expand Up @@ -133,6 +139,10 @@ func New(config Config) *Cache {
panic("config.MinAge must be less than or equal to config.MaxAge")
}

if config.RefreshInterval < 0 {
panic("Must supply a zero or positive config.RefreshInterval")
}

minAge := config.MinAge
if minAge == 0 {
minAge = config.MaxAge
Expand Down Expand Up @@ -166,6 +176,18 @@ func New(config Config) *Cache {
}()
}

if config.RefreshInterval > 0 && config.OnRefresh != nil {
cache.RefreshCache(config.OnRefresh())
go func() {
t := time.NewTicker(config.RefreshInterval)
defer t.Stop()
for {
<-t.C
cache.RefreshCache(config.OnRefresh())
}
}()
}

return cache
}

Expand Down Expand Up @@ -232,9 +254,7 @@ func (cache *Cache) RefreshCache(items map[interface{}]interface{}) {
cache.mutex.Lock()
defer cache.mutex.Unlock()

for _, val := range cache.items {
cache.deleteElement(val)
}
cache.items = make(map[interface{}]*list.Element)
cache.evictionList.Init()

for key, value := range items {
Expand Down
34 changes: 34 additions & 0 deletions cache_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,12 @@ func TestInvalidMinAge(t *testing.T) {
})
}

func TestInvalidRefreshInterval(t *testing.T) {
assert.Panics(t, func() {
New(Config{Capacity: 1, RefreshInterval: -1 * time.Hour})
})
}

func TestBasicSetGet(t *testing.T) {
cache := New(Config{Capacity: 2})
cache.Set("foo", 1)
Expand Down Expand Up @@ -109,6 +115,34 @@ func TestExpiration(t *testing.T) {
assert.False(t, eviction)
}

func TestCacheBackgroundRefresh(t *testing.T) {
count := 0
cache := New(Config{
Capacity: 1,
RefreshInterval: 3 * time.Second,
OnRefresh: func() map[interface{}]interface{} {
count++
return map[interface{}]interface{}{"key": count}
},
})

value, ok := cache.Get("key")
assert.Equal(t, true, ok)
assert.Equal(t, 1, value)

time.Sleep(4 * time.Second) // wait for the refresh loop to run

value, ok = cache.Get("key")
assert.Equal(t, true, ok)
assert.Equal(t, 2, value)

time.Sleep(4 * time.Second)
value, ok = cache.Get("key")
assert.Equal(t, true, ok)
assert.Equal(t, 3, value)

}

type MockRandGenerator struct {
startAt int64
incr int64
Expand Down

0 comments on commit 5fcff7f

Please sign in to comment.