1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556 |
- 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
- }
- // LookupFunc is a function that is called by the LookupCache if the underlying
- // value is out-of-date. It returns the new value, or an error.
- type LookupFunc[T any] func() (T, error)
- // NewLookupCache creates a new LookupCache with a given time-to-live (TTL)
- func NewLookupCache[T any](lookup LookupFunc[T], 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
- }
|