Skip to content

Commit

Permalink
feat(cache): added options
Browse files Browse the repository at this point in the history
  • Loading branch information
eko committed Oct 13, 2019
1 parent 52a29a1 commit 23439ea
Show file tree
Hide file tree
Showing 5 changed files with 115 additions and 36 deletions.
51 changes: 39 additions & 12 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@ Here is what it brings in detail:

## Built-in stores

* [Memory](https://github.com/dgraph-io/ristretto) (dgraph-io/ristretto)
* [Memory (bigcache)](https://github.com/allegro/bigcache) (allegro/bigcache)
* [Memory (ristretto)](https://github.com/dgraph-io/ristretto) (dgraph-io/ristretto)
* [Memcache](https://github.com/bradfitz/gomemcache) (bradfitz/memcache)
* [Redis](https://github.com/go-redis/redis/v7) (go-redis/redis)
* More to come soon
Expand Down Expand Up @@ -48,6 +49,23 @@ if err != nil {
value := cacheManager.Get("my-key")
```
#### Memory (using Bigcache)
```go
bigcacheClient, _ := bigcache.NewBigCache(bigcache.DefaultConfig(5 * time.Minute))
bigcacheStore := store.NewBigcache(
bigcacheClient,
)
cacheManager := cache.New(bigcacheStore, nil)
err := cacheManager.Set("my-key", "my-value")
if err != nil {
panic(err)
}
value := cacheManager.Get("my-key")
```
#### Memory (using Ristretto)
```go
Expand All @@ -57,8 +75,8 @@ if err != nil {
}
ristrettoStore := store.NewRistretto(ristrettoCache)
cacheManager := cache.New(ristrettoStore, 1*time.Second)
err := cacheManager.Set("my-key", "my-value)
cacheManager := cache.New(ristrettoStore, nil)
err := cacheManager.Set("my-key", "my-value")
if err != nil {
panic(err)
}
Expand All @@ -71,8 +89,8 @@ value := cacheManager.Get("my-key")
```go
redisStore := store.NewRedis(redis.NewClient(&redis.Options{Addr: "127.0.0.1:6379"}))
cacheManager := cache.New(redisStore, 15*time.Second)
err := cacheManager.Set("my-key", "my-value)
cacheManager := cache.New(redisStore, &cache.Options{Expiration: 15*time.Second})
err := cacheManager.Set("my-key", "my-value")
if err != nil {
panic(err)
}
Expand All @@ -99,8 +117,8 @@ redisStore := store.NewRedis(redisClient)
// Initialize chained cache
cacheManager := cache.NewChain(
cache.New(ristrettoStore, 5*time.Second),
cache.New(redisStore, 15*time.Second),
cache.New(ristrettoStore, nil),
cache.New(redisStore, &cache.Options{Expiration: 15*time.Second}),
)
// ... Then, do what you want with your cache
Expand All @@ -124,7 +142,10 @@ loadFunction := func(key interface{}) (interface{}, error) {
}
// Initialize loadable cache
cacheManager := cache.NewLoadable(loadFunction, cache.New(redisStore, 15*time.Second))
cacheManager := cache.NewLoadable(
loadFunction,
cache.New(redisStore, &cache.Options{Expiration: 15*time.Second}),
)
// ... Then, you can get your data and your function will automatically put them in cache(s)
```
Expand All @@ -142,7 +163,10 @@ redisStore := store.NewRedis(redisClient)
promMetrics := metrics.NewPrometheus("my-test-app")
// Initialize metric cache
cacheManager := cache.NewMetric(promMetrics, cache.New(redisStore, 15*time.Second))
cacheManager := cache.NewMetric(
promMetrics,
cache.New(redisStore, &cache.Options{Expiration: 15*time.Second}),
)
// ... Then, you can get your data and metrics will be observed by Prometheus
```
Expand All @@ -159,7 +183,10 @@ redisClient := redis.NewClient(&redis.Options{Addr: "127.0.0.1:6379"})
redisStore := store.NewRedis(redisClient)
// Initialize chained cache
cacheManager := cache.NewMetric(promMetrics, cache.New(redisStore, 15*time.Second))
cacheManager := cache.NewMetric(
promMetrics,
cache.New(redisStore, &cache.Options{Expiration: 15*time.Second}),
)
// Initializes marshaler
marshaller := marshaler.New(cacheManager)
Expand Down Expand Up @@ -231,8 +258,8 @@ func main() {
// and a load function that will put data back into caches if none has the value
cacheManager := cache.NewMetric(promMetrics, cache.NewLoadable(loadFunction,
cache.NewChain(
cache.New(ristrettoStore, 5*time.Second),
cache.New(redisStore, 15*time.Second),
cache.New(ristrettoStore, nil),
cache.New(redisStore, &cache.Options{Expiration: 15*time.Second}),
),
))
Expand Down
17 changes: 10 additions & 7 deletions cache/cache.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package cache

import (
"strings"
"time"

"github.com/eko/gache/codec"
"github.com/eko/gache/store"
Expand All @@ -14,15 +13,19 @@ const (

// Cache represents the configuration needed by a cache
type Cache struct {
codec codec.CodecInterface
expiration time.Duration
codec codec.CodecInterface
options *Options
}

// New instanciates a new cache entry
func New(store store.StoreInterface, expiration time.Duration) *Cache {
func New(store store.StoreInterface, options *Options) *Cache {
if options == nil {
options = &Options{}
}

return &Cache{
codec: codec.New(store),
expiration: expiration,
codec: codec.New(store),
options: options,
}
}

Expand All @@ -35,7 +38,7 @@ func (c *Cache) Get(key interface{}) (interface{}, error) {
// Set populates the cache item using the given key
func (c *Cache) Set(key, object interface{}) error {
cacheKey := c.getCacheKey(key)
return c.codec.Set(cacheKey, object, c.expiration)
return c.codec.Set(cacheKey, object, c.options.ExpirationValue())
}

// GetCodec returns the current codec
Expand Down
50 changes: 33 additions & 17 deletions cache/cache_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,22 +14,26 @@ import (
func TestNew(t *testing.T) {
// Given
store := &mocksStore.StoreInterface{}
expiration := 5 * time.Second
options := &Options{
Expiration: 5 * time.Second,
}

// When
cache := New(store, expiration)
cache := New(store, options)

// Then
assert.IsType(t, new(Cache), cache)
assert.IsType(t, new(codec.Codec), cache.codec)

assert.Equal(t, store, cache.codec.GetStore())
assert.Equal(t, expiration, cache.expiration)
assert.Equal(t, options, cache.options)
}

func TestCacheSet(t *testing.T) {
// Given
expiration := 5 * time.Second
options := &Options{
Expiration: 5 * time.Second,
}

value := &struct {
Hello string
Expand All @@ -38,9 +42,10 @@ func TestCacheSet(t *testing.T) {
}

store := &mocksStore.StoreInterface{}
store.On("Set", "9b1ac8a6e8ca8ca9477c0a252eb37756", value, expiration).Return(nil)
store.On("Set", "9b1ac8a6e8ca8ca9477c0a252eb37756", value, options.ExpirationValue()).
Return(nil)

cache := New(store, expiration)
cache := New(store, options)

// When
err := cache.Set("my-key", value)
Expand All @@ -49,7 +54,9 @@ func TestCacheSet(t *testing.T) {

func TestCacheSetWhenErrorOccurs(t *testing.T) {
// Given
expiration := 5 * time.Second
options := &Options{
Expiration: 5 * time.Second,
}

value := &struct {
Hello string
Expand All @@ -60,9 +67,10 @@ func TestCacheSetWhenErrorOccurs(t *testing.T) {
storeErr := errors.New("An error has occured while inserting data into store")

store := &mocksStore.StoreInterface{}
store.On("Set", "9b1ac8a6e8ca8ca9477c0a252eb37756", value, expiration).Return(storeErr)
store.On("Set", "9b1ac8a6e8ca8ca9477c0a252eb37756", value, options.ExpirationValue()).
Return(storeErr)

cache := New(store, expiration)
cache := New(store, options)

// When
err := cache.Set("my-key", value)
Expand All @@ -71,7 +79,9 @@ func TestCacheSetWhenErrorOccurs(t *testing.T) {

func TestCacheGet(t *testing.T) {
// Given
expiration := 5 * time.Second
options := &Options{
Expiration: 5 * time.Second,
}

cacheValue := &struct {
Hello string
Expand All @@ -82,7 +92,7 @@ func TestCacheGet(t *testing.T) {
store := &mocksStore.StoreInterface{}
store.On("Get", "9b1ac8a6e8ca8ca9477c0a252eb37756").Return(cacheValue, nil)

cache := New(store, expiration)
cache := New(store, options)

// When
value, err := cache.Get("my-key")
Expand All @@ -94,14 +104,16 @@ func TestCacheGet(t *testing.T) {

func TestCacheGetWhenNotFound(t *testing.T) {
// Given
expiration := 5 * time.Second
options := &Options{
Expiration: 5 * time.Second,
}

returnedErr := errors.New("Unable to find item in store")

store := &mocksStore.StoreInterface{}
store.On("Get", "9b1ac8a6e8ca8ca9477c0a252eb37756").Return(nil, returnedErr)

cache := New(store, expiration)
cache := New(store, options)

// When
value, err := cache.Get("my-key")
Expand All @@ -114,9 +126,11 @@ func TestCacheGetWhenNotFound(t *testing.T) {
func TestCacheGetCodec(t *testing.T) {
// Given
store := &mocksStore.StoreInterface{}
expiration := 5 * time.Second
options := &Options{
Expiration: 5 * time.Second,
}

cache := New(store, expiration)
cache := New(store, options)

// When
value := cache.GetCodec()
Expand All @@ -129,9 +143,11 @@ func TestCacheGetCodec(t *testing.T) {
func TestCacheGetType(t *testing.T) {
// Given
store := &mocksStore.StoreInterface{}
expiration := 5 * time.Second
options := &Options{
Expiration: 5 * time.Second,
}

cache := New(store, expiration)
cache := New(store, options)

// When - Then
assert.Equal(t, CacheType, cache.GetType())
Expand Down
15 changes: 15 additions & 0 deletions cache/options.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package cache

import (
"time"
)

// Options represents the cache available options
type Options struct {
Expiration time.Duration
}

// ExpirationValue returns the expiration option value
func (o Options) ExpirationValue() time.Duration {
return o.Expiration
}
18 changes: 18 additions & 0 deletions cache/options_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package cache

import (
"testing"
"time"

"github.com/stretchr/testify/assert"
)

func TestOptionsExpirationValue(t *testing.T) {
// Given
options := Options{
Expiration: 25 * time.Second,
}

// When - Then
assert.Equal(t, 25*time.Second, options.ExpirationValue())
}

0 comments on commit 23439ea

Please sign in to comment.