mirror of https://github.com/jlelse/GoBlog
Add garbage collection to cache and cache redirects
This commit is contained in:
parent
a3c6ba832e
commit
77f6a53a7e
51
cache.go
51
cache.go
|
@ -9,10 +9,27 @@ import (
|
||||||
"golang.org/x/sync/singleflight"
|
"golang.org/x/sync/singleflight"
|
||||||
)
|
)
|
||||||
|
|
||||||
var cacheMap = map[string]*cacheItem{}
|
var (
|
||||||
var cacheMutex = &sync.RWMutex{}
|
cacheGroup singleflight.Group
|
||||||
|
cacheMap = map[string]*cacheItem{}
|
||||||
|
cacheMutex = &sync.RWMutex{}
|
||||||
|
)
|
||||||
|
|
||||||
var requestGroup singleflight.Group
|
func initCache() {
|
||||||
|
go func() {
|
||||||
|
for {
|
||||||
|
// GC the entries every 60 seconds
|
||||||
|
time.Sleep(60 * time.Second)
|
||||||
|
cacheMutex.Lock()
|
||||||
|
for key, item := range cacheMap {
|
||||||
|
if item.expired() {
|
||||||
|
delete(cacheMap, key)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
cacheMutex.Unlock()
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
|
||||||
func cacheMiddleware(next http.Handler) http.Handler {
|
func cacheMiddleware(next http.Handler) http.Handler {
|
||||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
@ -21,11 +38,10 @@ func cacheMiddleware(next http.Handler) http.Handler {
|
||||||
!(r.URL.Query().Get("cache") == "0") &&
|
!(r.URL.Query().Get("cache") == "0") &&
|
||||||
// check method
|
// check method
|
||||||
(r.Method == http.MethodGet || r.Method == http.MethodHead) {
|
(r.Method == http.MethodGet || r.Method == http.MethodHead) {
|
||||||
// Fix path
|
key := cacheKey(r)
|
||||||
path := slashTrimmedPath(r)
|
|
||||||
// Get cache or render it
|
// Get cache or render it
|
||||||
cacheInterface, _, _ := requestGroup.Do(path, func() (interface{}, error) {
|
cacheInterface, _, _ := cacheGroup.Do(key, func() (interface{}, error) {
|
||||||
return getCache(path, next, r), nil
|
return getCache(key, next, r), nil
|
||||||
})
|
})
|
||||||
cache := cacheInterface.(*cacheItem)
|
cache := cacheInterface.(*cacheItem)
|
||||||
// log.Println(string(cache.body))
|
// log.Println(string(cache.body))
|
||||||
|
@ -55,6 +71,10 @@ func cacheMiddleware(next http.Handler) http.Handler {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func cacheKey(r *http.Request) string {
|
||||||
|
return slashTrimmedPath(r)
|
||||||
|
}
|
||||||
|
|
||||||
func setCacheHeaders(w http.ResponseWriter, cacheTimeString string, expiresTimeString string) {
|
func setCacheHeaders(w http.ResponseWriter, cacheTimeString string, expiresTimeString string) {
|
||||||
w.Header().Set("Cache-Control", "public")
|
w.Header().Set("Cache-Control", "public")
|
||||||
w.Header().Set("Last-Modified", cacheTimeString)
|
w.Header().Set("Last-Modified", cacheTimeString)
|
||||||
|
@ -68,16 +88,21 @@ type cacheItem struct {
|
||||||
body []byte
|
body []byte
|
||||||
}
|
}
|
||||||
|
|
||||||
func getCache(path string, next http.Handler, r *http.Request) *cacheItem {
|
func (c *cacheItem) expired() bool {
|
||||||
|
return c.creationTime < time.Now().Unix()-appConfig.Cache.Expiration
|
||||||
|
}
|
||||||
|
|
||||||
|
func getCache(key string, next http.Handler, r *http.Request) *cacheItem {
|
||||||
cacheMutex.RLock()
|
cacheMutex.RLock()
|
||||||
item, ok := cacheMap[path]
|
item, ok := cacheMap[key]
|
||||||
cacheMutex.RUnlock()
|
cacheMutex.RUnlock()
|
||||||
if !ok || item.creationTime < time.Now().Unix()-appConfig.Cache.Expiration {
|
if !ok || item.expired() {
|
||||||
item = &cacheItem{}
|
|
||||||
// No cache available
|
// No cache available
|
||||||
|
item = &cacheItem{}
|
||||||
|
// Record request
|
||||||
recorder := httptest.NewRecorder()
|
recorder := httptest.NewRecorder()
|
||||||
next.ServeHTTP(recorder, r)
|
next.ServeHTTP(recorder, r)
|
||||||
// copy values from recorder
|
// Cache values from recorder
|
||||||
now := time.Now()
|
now := time.Now()
|
||||||
item.creationTime = now.Unix()
|
item.creationTime = now.Unix()
|
||||||
item.code = recorder.Code
|
item.code = recorder.Code
|
||||||
|
@ -85,7 +110,7 @@ func getCache(path string, next http.Handler, r *http.Request) *cacheItem {
|
||||||
item.body = recorder.Body.Bytes()
|
item.body = recorder.Body.Bytes()
|
||||||
// Save cache
|
// Save cache
|
||||||
cacheMutex.Lock()
|
cacheMutex.Lock()
|
||||||
cacheMap[path] = item
|
cacheMap[key] = item
|
||||||
cacheMutex.Unlock()
|
cacheMutex.Unlock()
|
||||||
}
|
}
|
||||||
return item
|
return item
|
||||||
|
|
2
http.go
2
http.go
|
@ -137,7 +137,7 @@ func buildHandler() (http.Handler, error) {
|
||||||
}
|
}
|
||||||
for _, path := range allRedirectPaths {
|
for _, path := range allRedirectPaths {
|
||||||
if path != "" {
|
if path != "" {
|
||||||
r.With(minifier.Middleware).Get(path, serveRedirect)
|
r.With(cacheMiddleware, minifier.Middleware).Get(path, serveRedirect)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue