lookup_cache.go 1.2 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152
  1. package util
  2. import (
  3. "sync"
  4. "time"
  5. )
  6. // LookupCache is a single-value cache with a time-to-live (TTL). The cache has a lookup function
  7. // to retrieve the value and stores it until TTL is reached.
  8. //
  9. // Example:
  10. //
  11. // lookup := func() (string, error) {
  12. // r, _ := http.Get("...")
  13. // s, _ := io.ReadAll(r.Body)
  14. // return string(s), nil
  15. // }
  16. // c := NewLookupCache[string](lookup, time.Hour)
  17. // fmt.Println(c.Get()) // Fetches the string via HTTP
  18. // fmt.Println(c.Get()) // Uses cached value
  19. type LookupCache[T any] struct {
  20. value *T
  21. lookup func() (T, error)
  22. ttl time.Duration
  23. updated time.Time
  24. mu sync.Mutex
  25. }
  26. // NewLookupCache creates a new LookupCache with a given time-to-live (TTL)
  27. func NewLookupCache[T any](lookup func() (T, error), ttl time.Duration) *LookupCache[T] {
  28. return &LookupCache[T]{
  29. value: nil,
  30. lookup: lookup,
  31. ttl: ttl,
  32. }
  33. }
  34. // Value returns the cached value, or retrieves it via the lookup function
  35. func (c *LookupCache[T]) Value() (T, error) {
  36. c.mu.Lock()
  37. defer c.mu.Unlock()
  38. if c.value == nil || (c.ttl > 0 && time.Since(c.updated) > c.ttl) {
  39. value, err := c.lookup()
  40. if err != nil {
  41. var t T
  42. return t, err
  43. }
  44. c.value = &value
  45. c.updated = time.Now()
  46. }
  47. return *c.value, nil
  48. }