Skip to content

Commit

Permalink
Offers Cache
Browse files Browse the repository at this point in the history
  • Loading branch information
henrod committed Mar 22, 2017
1 parent f969dc2 commit eed36ab
Show file tree
Hide file tree
Showing 20 changed files with 266 additions and 127 deletions.
4 changes: 2 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ start-deps:
stop-deps:
@env MY_IP=${MY_IP} docker-compose --project-name offers down

test: deps unit integration acceptance test-coverage-func
test: deps unit integration test-coverage-func #acceptance test-coverage-func

clear-coverage-profiles:
@find . -name '*.coverprofile' -delete
Expand Down Expand Up @@ -152,7 +152,7 @@ run-perf:

run-test-offers: build kill-test-offers
@rm -rf /tmp/offers-bench.log
@./bin/offers start -p 8888 -q -c ./config/perf.yaml 2>&1 > /tmp/offers-bench.log &
@./bin/offers start -p 8889 -q -c ./config/perf.yaml 2>&1 > /tmp/offers-bench.log &

kill-test-offers:
@-ps aux | egrep './bin/offers.+perf.yaml' | egrep -v grep | awk ' { print $$2 } ' | xargs kill -9
1 change: 1 addition & 0 deletions api/api_suite_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ var _ = AfterEach(func() {
app.Clock = oTesting.MockClock{
CurrentTime: 1486678000,
}
app.Cache.Flush()
})

var _ = AfterSuite(func() {
Expand Down
34 changes: 23 additions & 11 deletions api/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,13 @@ import (
"io"
"net"
"net/http"
"time"

"github.com/Sirupsen/logrus"
"github.com/asaskevich/govalidator"
"github.com/gorilla/mux"
newrelic "github.com/newrelic/go-agent"
"github.com/pmylund/go-cache"
"github.com/spf13/viper"
"github.com/topfreegames/offers/errors"
"github.com/topfreegames/offers/metadata"
Expand All @@ -27,17 +29,19 @@ import (

//App is our API application
type App struct {
Address string
Clock models.Clock
Config *viper.Viper
DB runner.Connection
Debug bool
Logger logrus.FieldLogger
MaxAge int64
NewRelic newrelic.Application
RedisClient *util.RedisClient
Router *mux.Router
Server *http.Server
Address string
Clock models.Clock
Config *viper.Viper
DB runner.Connection
Debug bool
Logger logrus.FieldLogger
MaxAge int64
NewRelic newrelic.Application
RedisClient *util.RedisClient
Router *mux.Router
Server *http.Server
Cache *cache.Cache
OffersCacheMaxAge time.Duration
}

//NewApp ctor
Expand Down Expand Up @@ -187,9 +191,17 @@ func (a *App) configureApp() error {

a.MaxAge = a.Config.GetInt64("cache.maxAgeSeconds")
a.configureServer()
a.configureCache()
return nil
}

func (a *App) configureCache() {
maxAge := time.Duration(a.Config.GetInt64("offersCache.maxAgeSeconds")) * time.Second
cleanupInterval := time.Duration(a.Config.GetInt64("offersCache.cleanupInterval")) * time.Second
a.Cache = cache.New(maxAge, cleanupInterval)
a.OffersCacheMaxAge = maxAge
}

func (a *App) configureRedisClient() error {
redisHost := a.Config.GetString("redis.host")
redisPort := a.Config.GetInt("redis.port")
Expand Down
2 changes: 1 addition & 1 deletion api/offer_request.go
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ func (h *OfferRequestHandler) getOffers(w http.ResponseWriter, r *http.Request)
var err error
var offers map[string][]*models.OfferToReturn
err = mr.WithSegment(models.SegmentModel, func() error {
offers, err = models.GetAvailableOffers(h.App.DB, h.App.RedisClient, gameID, playerID, currentTime, mr)
offers, err = models.GetAvailableOffers(h.App.DB, h.App.RedisClient, h.App.Cache, gameID, playerID, currentTime, h.App.OffersCacheMaxAge, mr)
return err
})

Expand Down
18 changes: 18 additions & 0 deletions api/offer_request_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -529,6 +529,24 @@ var _ = Describe("Offer Handler", func() {
}
Expect(offersToReturn["store"]).NotTo(ContainElement(offer))
})

It("should return available offers from cache on second request", func() {
playerID := "player-1"
gameID := "offers-game"
url := fmt.Sprintf("/available-offers?player-id=%s&game-id=%s", playerID, gameID)
request, _ := http.NewRequest("GET", url, nil)

start := time.Now().UnixNano()
app.Router.ServeHTTP(recorder, request)
dbElapsedTime := time.Now().UnixNano() - start

recorder = httptest.NewRecorder()
start = time.Now().UnixNano()
app.Router.ServeHTTP(recorder, request)
cacheElapsedTime := time.Now().UnixNano() - start

Expect(dbElapsedTime).To(BeNumerically(">", cacheElapsedTime))
})
})

Describe("PUT /offers/claim", func() {
Expand Down
2 changes: 1 addition & 1 deletion bench/helpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ import (
)

func getRoute(url string) string {
return fmt.Sprintf("http://localhost:8888%s", url)
return fmt.Sprintf("http://localhost:8889%s", url)
}

func createGames(db *runner.Connection, numberOfGames int) ([]*models.Game, error) {
Expand Down
60 changes: 39 additions & 21 deletions bench/offer_instance_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ func BenchmarkAvailableOffers(b *testing.B) {

b.ResetTimer()

for i := 0; i < b.N; i++ {
for i := 0; i < b.N/NumberOfOffersPerGame; i++ {
game := games[i%NumberOfGames]
playerID := fmt.Sprintf("player-%d", i)
route := getRoute(fmt.Sprintf("/available-offers?game-id=%s&player-id=%s", game.ID, playerID))
Expand Down Expand Up @@ -68,9 +68,15 @@ func BenchmarkClaimOffer(b *testing.B) {
}
}

var offerInstances []*models.OfferToReturn
type OfferHelper struct {
GameID *string
PlayerID *string
OfferInstanceID *string
}

var offerHelpers []*OfferHelper

for i := 0; i < b.N; i++ {
for i := 0; i < b.N/NumberOfOffersPerGame; i++ {
game := games[i%NumberOfGames]
playerID := fmt.Sprintf("player-%d", i)
route := getRoute(fmt.Sprintf("/available-offers?game-id=%s&player-id=%s", game.ID, playerID))
Expand All @@ -86,25 +92,28 @@ func BenchmarkClaimOffer(b *testing.B) {
}

for _, offers := range offersPerPlacement {
offerInstances = append(offerInstances, offers...)
for _, offer := range offers {
offerHelpers = append(offerHelpers, &OfferHelper{
GameID: &game.ID,
PlayerID: &playerID,
OfferInstanceID: &offer.ID,
})
}
}

res.Body.Close()
}

b.ResetTimer()

for i, offerInstance := range offerInstances {
gamePosition := i / NumberOfOffersPerGame
game := games[gamePosition%NumberOfGames]
playerID := fmt.Sprintf("player-%d", i)
for _, offer := range offerHelpers {
body := map[string]interface{}{
"gameId": game.ID,
"playerId": playerID,
"gameId": *offer.GameID,
"playerId": *offer.PlayerID,
"productId": "com.tfg.sample",
"timestamp": time.Now().Unix(),
"transactionId": uuid.NewV4().String(),
"id": offerInstance.ID,
"id": *offer.OfferInstanceID,
}
route := getRoute("/offers/claim")
res, err := putTo(route, body)
Expand Down Expand Up @@ -133,9 +142,15 @@ func BenchmarkImpressionOffer(b *testing.B) {
}
}

var offerInstances []*models.OfferToReturn
type OfferHelper struct {
GameID *string
PlayerID *string
OfferInstanceID *string
}

var offerHelpers []*OfferHelper

for i := 0; i < b.N; i++ {
for i := 0; i < b.N/NumberOfOffersPerGame; i++ {
game := games[i%NumberOfGames]
playerID := fmt.Sprintf("player-%d", i)
route := getRoute(fmt.Sprintf("/available-offers?game-id=%s&player-id=%s", game.ID, playerID))
Expand All @@ -151,24 +166,27 @@ func BenchmarkImpressionOffer(b *testing.B) {
}

for _, offers := range offersPerPlacement {
offerInstances = append(offerInstances, offers...)
for _, offer := range offers {
offerHelpers = append(offerHelpers, &OfferHelper{
GameID: &game.ID,
PlayerID: &playerID,
OfferInstanceID: &offer.ID,
})
}
}

res.Body.Close()
}

b.ResetTimer()

for i, offerInstance := range offerInstances {
gamePosition := i / NumberOfOffersPerGame
game := games[gamePosition%NumberOfGames]
playerID := fmt.Sprintf("player-%d", i)
for _, offer := range offerHelpers {
body := map[string]interface{}{
"gameId": game.ID,
"playerId": playerID,
"gameId": *offer.GameID,
"playerId": *offer.PlayerID,
"impressionId": uuid.NewV4().String(),
}
route := getRoute(fmt.Sprintf("/offers/%s/impressions", offerInstance.ID))
route := getRoute(fmt.Sprintf("/offers/%s/impressions", *offer.OfferInstanceID))
res, err := putTo(route, body)
validateResp(res, err)
res.Body.Close()
Expand Down
3 changes: 3 additions & 0 deletions config/acc.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,6 @@ redis:
maxPoolSize: 20
cache:
maxAgeSeconds: 43200
offersCache:
maxAgeSeconds: 300
cleanupInterval: 30
3 changes: 3 additions & 0 deletions config/local.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@ redis:
maxPoolSize: 20
cache:
maxAgeSeconds: 43200
offersCache:
maxAgeSeconds: 300
cleanupInterval: 30
basicauth:
username: user
password: pass
3 changes: 3 additions & 0 deletions config/perf.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,6 @@ redis:
password: ""
db: 0
maxPoolSize: 20
offersCache:
maxAgeSeconds: 300
cleanupInterval: 30
3 changes: 3 additions & 0 deletions config/test.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,6 @@ redis:
maxPoolSize: 20
cache:
maxAgeSeconds: 43200
offersCache:
maxAgeSeconds: 300
cleanupInterval: 30
1 change: 1 addition & 0 deletions glide.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -26,3 +26,4 @@ import:
version: v2
- package: gopkg.in/redis.v5
version: ^5.2.9
- package: github.com/patrickmn/go-cache
2 changes: 2 additions & 0 deletions migrations/0002-CreateOffersTable.sql
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,5 @@ CREATE TABLE offers (
version integer NOT NULL DEFAULT 1,
created_at timestamp WITH TIME ZONE NOT NULL DEFAULT NOW()
);

CREATE INDEX offers_game ON offers (game_id);
4 changes: 2 additions & 2 deletions migrations/migrations.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions models/constants.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,3 +45,6 @@ const SegmentSet = "Redis/SET"

//SegmentSAdd represents a redis op
const SegmentSAdd = "Redis/SADD"

//SegmentRedis represents a redis op
const SegmentRedis = "Redis"
6 changes: 6 additions & 0 deletions models/models_suite_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,16 +11,19 @@ import (
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
runner "gopkg.in/mgutz/dat.v2/sqlx-runner"
"time"

"testing"

"github.com/pmylund/go-cache"
oTesting "github.com/topfreegames/offers/testing"
"github.com/topfreegames/offers/util"
)

var conn runner.Connection
var db *runner.Tx
var redisClient *util.RedisClient
var offersCache *cache.Cache

func TestApi(t *testing.T) {
RegisterFailHandler(Fail)
Expand All @@ -37,12 +40,15 @@ var _ = BeforeSuite(func() {

redisClient, err = oTesting.GetTestRedis()
Expect(err).NotTo(HaveOccurred())

offersCache = cache.New(300*time.Second, 30*time.Second)
})

var _ = BeforeEach(func() {
var err error
db, err = conn.Begin()
Expect(err).NotTo(HaveOccurred())
offersCache.Flush()
})

var _ = AfterEach(func() {
Expand Down
Loading

0 comments on commit eed36ab

Please sign in to comment.