-
-
Notifications
You must be signed in to change notification settings - Fork 8
/
Copy pathmemoize.go
47 lines (40 loc) · 1.46 KB
/
memoize.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
package gogu
import (
"time"
"github.com/esimov/gogu/cache"
"golang.org/x/sync/singleflight"
)
// Memoizer is a two component struct type used to memoize the results of a function execution.
// It holds an exported Cache storage and a singleflight group which is used
// to guarantee that only one function execution is in flight for a given key.
type Memoizer[T ~string, V any] struct {
Cache *cache.Cache[T, V]
group *singleflight.Group
}
// NewMemoizer instantiates a new Memoizer.
func NewMemoizer[T ~string, V any](expiration, cleanup time.Duration) *Memoizer[T, V] {
return &Memoizer[T, V]{
Cache: cache.New[T, V](expiration, cleanup),
group: &singleflight.Group{},
}
}
// Memoize returns the item under a specific key instantly in case the key exists,
// otherwise returns the results of the given function, making sure that only one execution
// is in-flight for a given key at a time.
//
// This method is useful for caching the result of a time-consuming operation when is more important
// to return a slightly outdated result, than to wait for an operation to complete before serving it.
func (m Memoizer[T, V]) Memoize(key T, fn func() (*cache.Item[V], error)) (*cache.Item[V], error) {
item, _ := m.Cache.Get(key)
if item != nil {
return item, nil
}
data, err, _ := m.group.Do(string(key), func() (any, error) {
item, err := fn()
if err == nil {
m.Cache.SetDefault(key, item.Val())
}
return item, err
})
return data.(*cache.Item[V]), err
}