Skip to content

Commit

Permalink
feat: add WithOnCacheMiss option
Browse files Browse the repository at this point in the history
This is similar to WithOnCacheHit. It is also triggered on error (as
this is technically a cache miss). This is useful if you want to keep
metrics about hit and miss without having another middleware.
  • Loading branch information
vincentbernat committed Dec 21, 2022
1 parent 19318c7 commit 6f54afb
Show file tree
Hide file tree
Showing 4 changed files with 50 additions and 5 deletions.
1 change: 1 addition & 0 deletions cache.go
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ func cache(
if err != persist.ErrCacheMiss {
cfg.logger.Errorf("get cache error: %s, cache key: %s", err, cacheKey)
}
cfg.missCacheCallback(c)
}

// cache miss, then call the backend
Expand Down
23 changes: 22 additions & 1 deletion cache_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,18 @@ package cache

import (
"fmt"
"github.com/stretchr/testify/require"
"math/rand"
"net/http"
"net/http/httptest"
"sync"
"sync/atomic"
"testing"
"time"

"github.com/chenyahui/gin-cache/persist"
"github.com/gin-gonic/gin"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)

func init() {
Expand Down Expand Up @@ -53,6 +54,26 @@ func TestCacheByRequestPath(t *testing.T) {
assert.Equal(t, w1.Code, w2.Code)
}

func TestCacheHitMissCallback(t *testing.T) {
var cacheHitCount, cacheMissCount int32
memoryStore := persist.NewMemoryStore(1 * time.Minute)
cachePathMiddleware := CacheByRequestPath(memoryStore, 3*time.Second,
WithOnHitCache(func(c *gin.Context) {
atomic.AddInt32(&cacheHitCount, 1)
}),
WithOnMissCache(func(c *gin.Context) {
atomic.AddInt32(&cacheMissCount, 1)
}),
)

mockHttpRequest(cachePathMiddleware, "/cache?uid=u1", true)
mockHttpRequest(cachePathMiddleware, "/cache?uid=u2", true)
mockHttpRequest(cachePathMiddleware, "/cache?uid=u3", true)

assert.Equal(t, cacheHitCount, int32(2))
assert.Equal(t, cacheMissCount, int32(1))
}

func TestCacheDuration(t *testing.T) {
memoryStore := persist.NewMemoryStore(1 * time.Minute)
cacheURIMiddleware := CacheByRequestURI(memoryStore, 3*time.Second)
Expand Down
13 changes: 10 additions & 3 deletions examples/options/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,26 +2,30 @@ package main

import (
"fmt"
"sync/atomic"
"time"

cache "github.com/chenyahui/gin-cache"
"github.com/chenyahui/gin-cache/persist"
"github.com/gin-gonic/gin"
"sync/atomic"
"time"
)

func main() {
app := gin.New()

memoryStore := persist.NewMemoryStore(1 * time.Minute)

var cacheHitCount int32
var cacheHitCount, cacheMissCount int32
app.GET("/hello",
cache.CacheByRequestURI(
memoryStore,
2*time.Second,
cache.WithOnHitCache(func(c *gin.Context) {
atomic.AddInt32(&cacheHitCount, 1)
}),
cache.WithOnMissCache(func(c *gin.Context) {
atomic.AddInt32(&cacheMissCount, 1)
}),
),
func(c *gin.Context) {
c.String(200, "hello world")
Expand All @@ -31,6 +35,9 @@ func main() {
app.GET("/get_hit_count", func(c *gin.Context) {
c.String(200, fmt.Sprintf("total hit count: %d", cacheHitCount))
})
app.GET("/get_miss_count", func(c *gin.Context) {
c.String(200, fmt.Sprintf("total miss count: %d", cacheMissCount))
})

if err := app.Run(":8080"); err != nil {
panic(err)
Expand Down
18 changes: 17 additions & 1 deletion option.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@ type Config struct {

getCacheStrategyByRequest GetCacheStrategyByRequest

hitCacheCallback OnHitCacheCallback
hitCacheCallback OnHitCacheCallback
missCacheCallback OnMissCacheCallback

beforeReplyWithCacheCallback BeforeReplyWithCacheCallback

Expand All @@ -27,6 +28,7 @@ func newConfigByOpts(opts ...Option) *Config {
cfg := &Config{
logger: Discard{},
hitCacheCallback: defaultHitCacheCallback,
missCacheCallback: defaultMissCacheCallback,
beforeReplyWithCacheCallback: defaultBeforeReplyWithCacheCallback,
shareSingleFlightCallback: defaultShareSingleFlightCallback,
}
Expand Down Expand Up @@ -86,6 +88,20 @@ func WithOnHitCache(cb OnHitCacheCallback) Option {
}
}

// OnMissCacheCallback define the callback when use cache
type OnMissCacheCallback func(c *gin.Context)

var defaultMissCacheCallback = func(c *gin.Context) {}

// WithOnMissCache will be called when cache miss.
func WithOnMissCache(cb OnMissCacheCallback) Option {
return func(c *Config) {
if cb != nil {
c.missCacheCallback = cb
}
}
}

type BeforeReplyWithCacheCallback func(c *gin.Context, cache *ResponseCache)

var defaultBeforeReplyWithCacheCallback = func(c *gin.Context, cache *ResponseCache) {}
Expand Down

0 comments on commit 6f54afb

Please sign in to comment.