Fix a bunch of FIXMEs

This commit is contained in:
binwiederhier 2023-01-18 15:50:06 -05:00
parent f945fb4cdd
commit 3bd6518309
15 changed files with 269 additions and 182 deletions

52
util/lookup_cache.go Normal file
View file

@ -0,0 +1,52 @@
package util
import (
"sync"
"time"
)
// LookupCache is a single-value cache with a time-to-live (TTL). The cache has a lookup function
// to retrieve the value and stores it until TTL is reached.
//
// Example:
//
// lookup := func() (string, error) {
// r, _ := http.Get("...")
// s, _ := io.ReadAll(r.Body)
// return string(s), nil
// }
// c := NewLookupCache[string](lookup, time.Hour)
// fmt.Println(c.Get()) // Fetches the string via HTTP
// fmt.Println(c.Get()) // Uses cached value
type LookupCache[T any] struct {
value *T
lookup func() (T, error)
ttl time.Duration
updated time.Time
mu sync.Mutex
}
// NewLookupCache creates a new LookupCache with a given time-to-live (TTL)
func NewLookupCache[T any](lookup func() (T, error), ttl time.Duration) *LookupCache[T] {
return &LookupCache[T]{
value: nil,
lookup: lookup,
ttl: ttl,
}
}
// Value returns the cached value, or retrieves it via the lookup function
func (c *LookupCache[T]) Value() (T, error) {
c.mu.Lock()
defer c.mu.Unlock()
if c.value == nil || (c.ttl > 0 && time.Since(c.updated) > c.ttl) {
value, err := c.lookup()
if err != nil {
var t T
return t, err
}
c.value = &value
c.updated = time.Now()
}
return *c.value, nil
}

63
util/lookup_cache_test.go Normal file
View file

@ -0,0 +1,63 @@
package util
import (
"errors"
"github.com/stretchr/testify/require"
"testing"
"time"
)
func TestLookupCache_Success(t *testing.T) {
values, i := []string{"first", "second"}, 0
c := NewLookupCache[string](func() (string, error) {
time.Sleep(300 * time.Millisecond)
v := values[i]
i++
return v, nil
}, 500*time.Millisecond)
start := time.Now()
v, err := c.Value()
require.Nil(t, err)
require.Equal(t, values[0], v)
require.True(t, time.Since(start) >= 300*time.Millisecond)
start = time.Now()
v, err = c.Value()
require.Nil(t, err)
require.Equal(t, values[0], v)
require.True(t, time.Since(start) < 200*time.Millisecond)
time.Sleep(550 * time.Millisecond)
start = time.Now()
v, err = c.Value()
require.Nil(t, err)
require.Equal(t, values[1], v)
require.True(t, time.Since(start) >= 300*time.Millisecond)
start = time.Now()
v, err = c.Value()
require.Nil(t, err)
require.Equal(t, values[1], v)
require.True(t, time.Since(start) < 200*time.Millisecond)
}
func TestLookupCache_Error(t *testing.T) {
c := NewLookupCache[string](func() (string, error) {
time.Sleep(200 * time.Millisecond)
return "", errors.New("some error")
}, 500*time.Millisecond)
start := time.Now()
v, err := c.Value()
require.NotNil(t, err)
require.Equal(t, "", v)
require.True(t, time.Since(start) >= 200*time.Millisecond)
start = time.Now()
v, err = c.Value()
require.NotNil(t, err)
require.Equal(t, "", v)
require.True(t, time.Since(start) >= 200*time.Millisecond)
}