Skip to content

Commit

Permalink
Refactor to use decorator for the cache
Browse files Browse the repository at this point in the history
  • Loading branch information
miguelreiswildlife committed Sep 25, 2023
1 parent 6bca41d commit 32fdd1d
Show file tree
Hide file tree
Showing 12 changed files with 305 additions and 250 deletions.
17 changes: 14 additions & 3 deletions api/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import (
"context"
"fmt"
"github.com/go-redis/redis/v8"
enrichercache "github.com/topfreegames/podium/leaderboard/v2/enriching/cache"
"net"
"net/http"
"os"
Expand Down Expand Up @@ -231,16 +232,26 @@ func (app *App) configureEnrichment() {
Password: app.ParsedConfig.Enrichment.Cache.Password,
})

enrichCache := enriching.NewEnricherCache(app.Logger, redisClient)
enrichCache := enrichercache.NewEnricherCache(redisClient)
enricher := enriching.NewEnricher(
enrichCache,
enriching.WithLogger(app.Logger),
enriching.WithWebhookUrls(app.ParsedConfig.Enrichment.WebhookUrls),
enriching.WithWebhookTimeout(app.ParsedConfig.Enrichment.WebhookTimeout),
enriching.WithCloudSaveUrl(app.ParsedConfig.Enrichment.CloudSave.Url),
enriching.WithCloudSaveDisabled(app.ParsedConfig.Enrichment.CloudSave.Disabled),
)
app.Enricher = enriching.NewInstrumentedEnricher(enricher, app.DDStatsD)
wrapped := enriching.NewInstrumentedEnricher(enricher, app.DDStatsD)

if !app.ParsedConfig.Enrichment.Cache.Disabled {
wrapped = enrichercache.NewCachedEnricher(
enrichCache,
enricher,
enrichercache.WithLogger(app.Logger),
enrichercache.WithTTL(app.ParsedConfig.Enrichment.Cache.TTL),
)
}

app.Enricher = wrapped
}

// OnErrorHandler handles panics
Expand Down
1 change: 1 addition & 0 deletions config/default.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ extensions:
enrichment:
webhook_urls:
cache:
disabled: false
ttl: 24h
addrs: "localhost:6739"
username: ""
Expand Down
1 change: 1 addition & 0 deletions config/local.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ enrichment:
dummy_tenant_id: "localhost:8080/"
webhook_timeout: 500ms
cache:
disabled: false
ttl: 24h
addrs: "localhost:6739"
username: ""
Expand Down
Original file line number Diff line number Diff line change
@@ -1,32 +1,29 @@
package enriching
package cache

import (
"context"
"encoding/json"
"fmt"
"github.com/go-redis/redis/v8"
"github.com/topfreegames/podium/leaderboard/v2/enriching"
"github.com/topfreegames/podium/leaderboard/v2/model"
"go.uber.org/zap"
"time"
)

// cacheKeyFormat is {tenantID}:{leaderboardID}:{memberID}
const cacheKeyFormat = "leaderboards-enrich-caching:%s:%s:%s"

type enricherCache struct {
redis *redis.Client
logger *zap.Logger
redis *redis.Client
}

var _ EnricherCache = &enricherCache{}
var _ enriching.EnricherCache = &enricherCache{}

func NewEnricherCache(
logger *zap.Logger,
redis *redis.Client,
) EnricherCache {
) enriching.EnricherCache {
return &enricherCache{
redis: redis,
logger: logger.With(zap.String("source", "enricherCache")),
redis: redis,
}
}

Expand All @@ -36,17 +33,10 @@ func (e *enricherCache) Get(
leaderboardID string,
members []*model.Member,
) (map[string]map[string]string, bool, error) {
l := e.logger.With(
zap.String("method", "Get"),
zap.String("tenantID", tenantID),
zap.String("leaderboardID", leaderboardID),
)

keys := getKeysFromMemberArray(tenantID, leaderboardID, members)
dataArray, err := e.redis.MGet(ctx, keys...).Result()
if err != nil {
l.With(zap.Error(err)).Error("failed to get members from cache")
return nil, false, fmt.Errorf("failed to get data from cache: %w", err)
return nil, false, fmt.Errorf("failed to get data from cacheConfig: %w", err)
}

dataMap := make(map[string]map[string]string)
Expand All @@ -58,7 +48,6 @@ func (e *enricherCache) Get(
unmarshaled := map[string]string{}
err := json.Unmarshal([]byte(data.(string)), &unmarshaled)
if err != nil {
l.With(zap.Error(err)).Error("failed to unmarshal data")
return nil, false, fmt.Errorf("failed to unmarshal data: %w", err)
}

Expand All @@ -76,27 +65,21 @@ func (e *enricherCache) Set(
members []*model.Member,
ttl time.Duration,
) error {
l := e.logger.With(
zap.String("method", "Set"),
zap.String("tenantID", tenantID),
zap.String("leaderboardID", leaderboardID),
)

keys := getKeysFromMemberArray(tenantID, leaderboardID, members)
pipe := e.redis.TxPipeline()
for i, member := range members {
marshaled, err := json.Marshal(member.Metadata)
if err != nil {
l.With(zap.Error(err)).Error("failed to marshal metadata")
return fmt.Errorf("failed to marshal metadata: %w", err)
if member.Metadata != nil {
marshaled, err := json.Marshal(member.Metadata)
if err != nil {
return fmt.Errorf("failed to marshal metadata: %w", err)
}
pipe.Set(ctx, keys[i], marshaled, ttl)
}
pipe.Set(ctx, keys[i], marshaled, ttl)
}

_, err := pipe.Exec(ctx)
if err != nil {
l.With(zap.Error(err)).Error("failed to set members in cache")
return fmt.Errorf("failed to set members in cache: %w", err)
return fmt.Errorf("failed to set members in cacheConfig: %w", err)
}

return nil
Expand Down
12 changes: 12 additions & 0 deletions leaderboard/enriching/cache/cache_suite_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package cache

import (
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
"testing"
)

func TestEnrichingCache(t *testing.T) {
RegisterFailHandler(Fail)
RunSpecs(t, "Enriching Cache Suite")
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package enriching
package cache

import (
"context"
Expand All @@ -9,7 +9,6 @@ import (
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
"github.com/topfreegames/podium/leaderboard/v2/model"
"go.uber.org/zap"
)

var _ = Describe("Members array to keys array test", func() {
Expand All @@ -34,7 +33,7 @@ var _ = Describe("Members array to keys array test", func() {
})
})

var _ = Describe("Enricher cache Get tests", func() {
var _ = Describe("Enricher cacheConfig Get tests", func() {
tenantID := "tenantID"
leaderboardID := "leaderboardID"

Expand All @@ -51,7 +50,7 @@ var _ = Describe("Enricher cache Get tests", func() {
getKeysFromMemberArray(tenantID, leaderboardID, members)...,
).SetErr(errors.New("some error"))

cache := NewEnricherCache(zap.NewNop(), redis)
cache := NewEnricherCache(redis)
res, hit, err := cache.Get(context.Background(), tenantID, leaderboardID, members)

Expect(res).To(BeNil())
Expand All @@ -76,7 +75,7 @@ var _ = Describe("Enricher cache Get tests", func() {
getKeysFromMemberArray(tenantID, leaderboardID, members)...,
).SetVal([]interface{}{nil, nil})

cache := NewEnricherCache(zap.NewNop(), redis)
cache := NewEnricherCache(redis)
res, hit, err := cache.Get(context.Background(), tenantID, leaderboardID, members)

Expect(res).To(BeNil())
Expand Down Expand Up @@ -105,7 +104,7 @@ var _ = Describe("Enricher cache Get tests", func() {
getKeysFromMemberArray(tenantID, leaderboardID, members)...,
).SetVal(mgetExpectedResult)

cache := NewEnricherCache(zap.NewNop(), redis)
cache := NewEnricherCache(redis)
res, hit, err := cache.Get(context.Background(), tenantID, leaderboardID, members)

Expect(res).To(BeNil())
Expand Down Expand Up @@ -134,7 +133,7 @@ var _ = Describe("Enricher cache Get tests", func() {
getKeysFromMemberArray(tenantID, leaderboardID, members)...,
).SetVal(mgetExpectedResult)

cache := NewEnricherCache(zap.NewNop(), redis)
cache := NewEnricherCache(redis)
res, hit, err := cache.Get(context.Background(), tenantID, leaderboardID, members)

expectedResult := map[string]map[string]string{
Expand All @@ -152,14 +151,14 @@ var _ = Describe("Enricher cache Get tests", func() {
})
})

var _ = Describe("Ericher cache Set tests", func() {
var _ = Describe("Ericher cacheConfig Set tests", func() {
tenantID := "tenantID"
leaderboardID := "leaderboardID"

It("should set the data in redis", func() {
redis := redis.NewClient(&redis.Options{Addr: "localhost:6379"})

cache := NewEnricherCache(zap.NewNop(), redis)
cache := NewEnricherCache(redis)
members := []*model.Member{
{
PublicID: "member1",
Expand Down
81 changes: 81 additions & 0 deletions leaderboard/enriching/cache/cached_enricher.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
package cache

import (
"context"
"github.com/topfreegames/podium/leaderboard/v2/enriching"
"github.com/topfreegames/podium/leaderboard/v2/model"
"go.uber.org/zap"
)

type cachedEnricher struct {
cache enriching.EnricherCache
config cacheConfig
impl enriching.Enricher
logger *zap.Logger
}

func NewCachedEnricher(
cache enriching.EnricherCache,
enricher enriching.Enricher,
options ...CachedEnricherOptions,
) enriching.Enricher {
e := &cachedEnricher{
cache: cache,
impl: enricher,
config: newDefaultCacheConfig(),
logger: zap.NewNop(),
}

for _, opt := range options {
opt(e)
}

return e
}

var _ enriching.Enricher = &cachedEnricher{}

func (e *cachedEnricher) Enrich(
ctx context.Context,
tenantID,
leaderboardID string,
members []*model.Member,
) ([]*model.Member, error) {
if len(members) == 0 {
return members, nil
}

l := e.logger.With(
zap.String("tenantID", tenantID),
zap.String("leaderboardID", leaderboardID),
)

cached, hit, err := e.cache.Get(ctx, tenantID, leaderboardID, members)
if err != nil {
l.Error("could not get cached enrichment data", zap.Error(err))
}

if hit {
l.Debug("returning cached enrich data")
for _, m := range members {
if metadata, exists := cached[m.PublicID]; exists {
m.Metadata = metadata
}
}

return members, nil
}

members, err = e.impl.Enrich(ctx, tenantID, leaderboardID, members)

if err != nil {
return nil, err
}

err = e.cache.Set(ctx, tenantID, leaderboardID, members, e.config.ttl)
if err != nil {
l.Error("could not set cached enrichment data", zap.Error(err))
}

return members, nil
}
Loading

0 comments on commit 32fdd1d

Please sign in to comment.