-
Notifications
You must be signed in to change notification settings - Fork 8
/
remember.go
125 lines (109 loc) · 2.96 KB
/
remember.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
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
// Copyright 2018-21 PJ Engineering and Business Solutions Pty. Ltd. All rights reserved.
package remember
import (
"context"
"encoding/gob"
"fmt"
"log"
"time"
)
// Cache is used to return a cached value. If it's not available, fn will be called to obtain a value.
// Subsequently, fn's value will be saved into the cache.
func Cache(ctx context.Context, c Conner, key string, expiration time.Duration, fn SlowRetrieve, options ...Options) (_ interface{}, found bool, _ error) {
var (
disableCache bool
fresh bool
logger Logger
gobRegister bool
onlyLogErrors bool
)
if options != nil {
disableCache = options[0].DisableCacheUsage
fresh = options[0].UseFreshData
logger = options[0].Logger
gobRegister = options[0].GobRegister
onlyLogErrors = options[0].OnlyLogErrors
}
// Check if cache has been disabled
if disableCache {
if logger != nil && !onlyLogErrors {
logger.Log(logPatternBlue, "[cache disabled] Grabbing from SlowRetrieve key: "+key)
}
out, err := fn(ctx)
if err != nil {
if logger != nil && !onlyLogErrors {
logger.Log(logPatternBlue, "[cache disabled] Grabbing (cache disabled) from SlowRetrieve key: "+key+" error: "+err.Error())
}
return nil, false, err
}
return out, false, nil
}
// Obtain cache connection
cache, err := c.Conn(ctx)
if err != nil {
if logger != nil {
logger.Log(logPatternRed, "could not obtain connection for cache")
}
return nil, false, err
}
defer cache.Close()
var item interface{}
if fresh {
if logger != nil && !onlyLogErrors {
logger.Log(logPatternBlue, "Grabbing (fresh) from SlowRetrieve key: "+key)
}
goto fresh
}
// Check if item exists
item, found, err = cache.Get(key)
if err != nil {
// Error when attempting to fetch from cache
if logger != nil {
logger.Log(logPatternRed, "could not fetch from cache key: "+key+" error: "+err.Error())
}
}
if found && err == nil {
// Item exists in cache
if logger != nil && !onlyLogErrors {
logger.Log(logPatternBlue, "Found in Cache key: "+key)
}
return item, true, nil
}
if logger != nil && !onlyLogErrors {
logger.Log(logPatternBlue, "Grabbing from SlowRetrieve key: "+key)
}
fresh:
// Item does not exist in cache so grab it from the fn
itemToStore, err := fn(ctx)
if err != nil {
return nil, false, err
}
if gobRegister {
func() {
defer func() {
if err := recover(); err != nil {
msg := fmt.Sprintf("gob register: %v", err)
if logger != nil {
logger.Log(logPatternRed, msg)
} else {
log.Printf(logPatternRed, msg)
}
}
}()
gob.Register(itemToStore)
}()
}
// Store item in Cache
if cache.StorePointer() {
err = cache.Set(key, expiration, &itemToStore)
} else {
err = cache.Set(key, expiration, itemToStore)
}
if err != nil {
// Storage failed
if logger != nil {
logger.Log(logPatternRed, "Could not store item to key: "+key+" "+err.Error()+" "+fmt.Sprintf("%+v", itemToStore))
}
}
return itemToStore, false, nil
}