Skip to content

Remove dependency on external cache package #823

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 2 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ docker-dev:

docker-test:
docker compose -f docker-compose.yml -f docker-compose.dev.yml run --rm -p 2416:2416 challenge-bypass bash -c \
"(aws dynamodb delete-table \
"export AWS_PAGER='' && (aws dynamodb delete-table \
--table-name redemptions --endpoint-url http://dynamodb:8000 --region us-west-2 || \
aws dynamodb create-table \
--attribute-definitions AttributeName=id,AttributeType=S \
Expand Down
1 change: 0 additions & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ require (
github.com/google/uuid v1.6.0
github.com/jmoiron/sqlx v1.3.5
github.com/lib/pq v1.10.9
github.com/patrickmn/go-cache v2.1.0+incompatible
github.com/prometheus/client_golang v1.14.0
github.com/robfig/cron/v3 v3.0.1
github.com/satori/go.uuid v1.2.0
Expand Down
2 changes: 0 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -206,8 +206,6 @@ github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8
github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM=
github.com/opencontainers/image-spec v1.1.0 h1:8SG7/vwALn54lVB/0yZ/MMwhFrPYtpEHQb2IpWsCzug=
github.com/opencontainers/image-spec v1.1.0/go.mod h1:W4s4sFTMaBeK1BQLXbG4AdM2szdn85PY75RI83NrTrM=
github.com/patrickmn/go-cache v2.1.0+incompatible h1:HRMgzkcYKYpi3C8ajMPV8OFXaaRUnok+kx1WdO15EQc=
github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ=
github.com/pierrec/lz4/v4 v4.1.15/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4=
github.com/pierrec/lz4/v4 v4.1.17 h1:kV4Ip+/hUBC+8T6+2EgburRtkE9ef4nbY3f4dFhGjMc=
github.com/pierrec/lz4/v4 v4.1.17/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4=
Expand Down
140 changes: 140 additions & 0 deletions server/cache.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
package server

import (
"sync"
"time"
)

// CachingConfig is how long data is cached
type CachingConfig struct {
Enabled bool `json:"enabled"`
ExpirationSec int `json:"expirationSec"`
}

// CacheInterface cache functions
type CacheInterface interface {
Get(k string) (interface{}, bool)
Delete(k string)
SetDefault(k string, x interface{})
}

// SimpleCache implements CacheInterface using standard library
type SimpleCache struct {
items sync.Map
defaultExpiration time.Duration
cleanupInterval time.Duration
stopCleanup chan bool
}

type cacheItem struct {
value interface{}
expiration int64 // Unix timestamp for expiration
}

// NewSimpleCache creates a new cache with the given default expiration and cleanup interval
func NewSimpleCache(defaultExpiration, cleanupInterval time.Duration) *SimpleCache {
cache := &SimpleCache{
defaultExpiration: defaultExpiration,
cleanupInterval: cleanupInterval,
stopCleanup: make(chan bool),
}

// Start cleanup routine if cleanup interval > 0
if cleanupInterval > 0 {
go cache.startCleanupTimer()
}

return cache
}

// startCleanupTimer starts a timer that periodically cleans up expired items
func (c *SimpleCache) startCleanupTimer() {
ticker := time.NewTicker(c.cleanupInterval)
defer ticker.Stop()

for {
select {
case <-ticker.C:
c.deleteExpired()
case <-c.stopCleanup:
return
}
}
}

// deleteExpired deletes expired items from the cache
func (c *SimpleCache) deleteExpired() {
now := time.Now().UnixNano()
c.items.Range(func(key, value interface{}) bool {
item, ok := value.(cacheItem)
if ok && item.expiration > 0 && item.expiration < now {
c.items.Delete(key)
}
return true
})
}

// Get retrieves an item from the cache
func (c *SimpleCache) Get(k string) (interface{}, bool) {
value, found := c.items.Load(k)
if !found {
return nil, false
}

item, ok := value.(cacheItem)
if !ok {
return nil, false
}

// Check if item has expired
if item.expiration > 0 && item.expiration < time.Now().UnixNano() {
c.items.Delete(k)
return nil, false
}

return item.value, true
}

// Delete removes an item from the cache
func (c *SimpleCache) Delete(k string) {
c.items.Delete(k)
}

// SetDefault adds an item to the cache with the default expiration time
func (c *SimpleCache) SetDefault(k string, x interface{}) {
var expiration int64 = 0
if c.defaultExpiration > 0 {
expiration = time.Now().Add(c.defaultExpiration).UnixNano()
}

c.items.Store(k, cacheItem{
value: x,
expiration: expiration,
})
}

func retrieveFromCache(
caches map[string]CacheInterface,
cacheName string,
key string,
) interface{} {
if caches != nil {
if cached, found := caches[cacheName].Get(key); found {
return cached
}
}
return nil
}

func bootstrapCache(cfg DBConfig) map[string]CacheInterface {
caches := make(map[string]CacheInterface)
defaultDuration := time.Duration(cfg.CachingConfig.ExpirationSec) * time.Second
cleanupInterval := defaultDuration * 2

caches["issuers"] = NewSimpleCache(defaultDuration, cleanupInterval)
caches["issuer"] = NewSimpleCache(defaultDuration, cleanupInterval)
caches["redemptions"] = NewSimpleCache(defaultDuration, cleanupInterval)
caches["issuercohort"] = NewSimpleCache(defaultDuration, cleanupInterval)

return caches
}
37 changes: 0 additions & 37 deletions server/db.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,16 +22,9 @@ import (
_ "github.com/golang-migrate/migrate/v4/source/file" // Why?
"github.com/jmoiron/sqlx"
"github.com/lib/pq"
cache "github.com/patrickmn/go-cache"
"github.com/prometheus/client_golang/prometheus"
)

// CachingConfig is how long data is cached
type CachingConfig struct {
Enabled bool `json:"enabled"`
ExpirationSec int `json:"expirationSec"`
}

// DBConfig defines app configurations
type DBConfig struct {
ConnectionURI string `json:"connectionURI"`
Expand Down Expand Up @@ -61,13 +54,6 @@ type RedemptionV2 struct {
Offset int64 `json:"offset"`
}

// CacheInterface cache functions
type CacheInterface interface {
Get(k string) (interface{}, bool)
Delete(k string)
SetDefault(k string, x interface{})
}

var (
errIssuerNotFound = errors.New("issuer with the given name does not exist")
errIssuerCohortNotFound = errors.New("issuer with the given name and cohort does not exist")
Expand Down Expand Up @@ -843,26 +829,3 @@ func isPostgresNotFoundError(err error) bool {
}
return false
}

func retrieveFromCache(
caches map[string]CacheInterface,
cacheName string,
key string,
) interface{} {
if caches != nil {
if cached, found := caches[cacheName].Get(key); found {
return cached
}
}
return nil
}

func bootstrapCache(cfg DBConfig) map[string]CacheInterface {
caches := make(map[string]CacheInterface)
defaultDuration := time.Duration(cfg.CachingConfig.ExpirationSec) * time.Second
caches["issuers"] = cache.New(defaultDuration, 2*defaultDuration)
caches["issuer"] = cache.New(defaultDuration, 2*defaultDuration)
caches["redemptions"] = cache.New(defaultDuration, 2*defaultDuration)
caches["issuercohort"] = cache.New(defaultDuration, 2*defaultDuration)
return caches
}
Loading