Skip to content

Commit

Permalink
Merge pull request #11 from castaneai/frontend-ticket-cache
Browse files Browse the repository at this point in the history
feat: ticket cache
  • Loading branch information
castaneai authored Dec 23, 2023
2 parents b9a73f9 + fd9050e commit 5d18e39
Show file tree
Hide file tree
Showing 7 changed files with 150 additions and 4 deletions.
2 changes: 2 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ require (
)

require (
github.com/Code-Hex/go-generics-cache v1.3.1 // indirect
github.com/alicebob/gopher-json v0.0.0-20230218143504-906a9b012302 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/go-logr/logr v1.3.0 // indirect
Expand All @@ -32,6 +33,7 @@ require (
go.opentelemetry.io/otel/trace v1.21.0 // indirect
go.uber.org/atomic v1.10.0 // indirect
go.uber.org/multierr v1.11.0 // indirect
golang.org/x/exp v0.0.0-20220328175248-053ad81199eb // indirect
golang.org/x/net v0.17.0 // indirect
golang.org/x/sys v0.14.0 // indirect
golang.org/x/text v0.13.0 // indirect
Expand Down
4 changes: 4 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
github.com/Code-Hex/go-generics-cache v1.3.1 h1:i8rLwyhoyhaerr7JpjtYjJZUcCbWOdiYO3fZXLiEC4g=
github.com/Code-Hex/go-generics-cache v1.3.1/go.mod h1:qxcC9kRVrct9rHeiYpFWSoW1vxyillCVzX13KZG8dl4=
github.com/DmitriyVTitov/size v1.5.0/go.mod h1:le6rNI4CoLQV1b9gzp1+3d7hMAD/uu2QcJ+aYbNgiU0=
github.com/alicebob/gopher-json v0.0.0-20200520072559-a9ecdc9d1d3a/go.mod h1:SGnFV6hVsYE877CKEZ6tDNTjaSXYUk6QqoIK6PrAtcc=
github.com/alicebob/gopher-json v0.0.0-20230218143504-906a9b012302 h1:uvdUDbHQHO85qeSydJtItA4T55Pw6BtAejd0APRJOCE=
Expand Down Expand Up @@ -72,6 +74,8 @@ go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
go.uber.org/zap v1.24.0 h1:FiJd5l1UOLj0wCgbSE0rwwXHzEdAZS6hiiSnxJN/D60=
go.uber.org/zap v1.24.0/go.mod h1:2kMP+WWQ8aoFoedH3T2sq6iJ2yDWpHbP0f6MQbS9Gkg=
golang.org/x/exp v0.0.0-20220328175248-053ad81199eb h1:pC9Okm6BVmxEw76PUu0XUbOTQ92JX11hfvqTjAV3qxM=
golang.org/x/exp v0.0.0-20220328175248-053ad81199eb/go.mod h1:lgLbSvA5ygNOMpwM/9anMpWVlVJ7Z+cHWq/eFuinpGE=
golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM=
golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE=
golang.org/x/sync v0.3.0 h1:ftCYgMx6zT/asHUrPw8BLLscYtGznsLAnjq5RH9P66E=
Expand Down
13 changes: 9 additions & 4 deletions loadtest/cmd/frontend/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"net/http"
"time"

cache "github.com/Code-Hex/go-generics-cache"
"github.com/kelseyhightower/envconfig"
"github.com/prometheus/client_golang/prometheus/promhttp"
"github.com/redis/rueidis"
Expand All @@ -27,9 +28,10 @@ const (
)

type config struct {
RedisAddr string `envconfig:"REDIS_ADDR" default:"127.0.0.1:6379"`
AssignmentRedisAddr string `envconfig:"REDIS_ADDR_ASSIGNMENT"`
Port string `envconfig:"PORT" default:"50504"`
RedisAddr string `envconfig:"REDIS_ADDR" default:"127.0.0.1:6379"`
AssignmentRedisAddr string `envconfig:"REDIS_ADDR_ASSIGNMENT"`
Port string `envconfig:"PORT" default:"50504"`
TicketCacheTTL time.Duration `envconfig:"TICKET_CACHE_TTL" default:"10s"`
}

func main() {
Expand All @@ -53,7 +55,10 @@ func main() {
}
opts = append(opts, statestore.WithSeparatedAssignmentRedis(asRedis))
}
store := statestore.NewRedisStore(redis, opts...)
ticketCache := cache.New[string, *pb.Ticket]()
store := statestore.NewStoreWithTicketCache(
statestore.NewRedisStore(redis, opts...), ticketCache,
statestore.WithTicketCacheTTL(conf.TicketCacheTTL))
sv := grpc.NewServer()
pb.RegisterFrontendServiceServer(sv, minimatch.NewFrontendService(store))

Expand Down
2 changes: 2 additions & 0 deletions loadtest/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ require (
)

require (
github.com/Code-Hex/go-generics-cache v1.3.1 // indirect
github.com/alicebob/gopher-json v0.0.0-20230218143504-906a9b012302 // indirect
github.com/alicebob/miniredis/v2 v2.31.0 // indirect
github.com/beorn7/perks v1.0.1 // indirect
Expand All @@ -39,6 +40,7 @@ require (
go.uber.org/atomic v1.10.0 // indirect
go.uber.org/multierr v1.11.0 // indirect
go.uber.org/zap v1.24.0 // indirect
golang.org/x/exp v0.0.0-20220328175248-053ad81199eb // indirect
golang.org/x/net v0.17.0 // indirect
golang.org/x/sync v0.4.0 // indirect
golang.org/x/sys v0.14.0 // indirect
Expand Down
4 changes: 4 additions & 0 deletions loadtest/go.sum
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
github.com/Code-Hex/go-generics-cache v1.3.1 h1:i8rLwyhoyhaerr7JpjtYjJZUcCbWOdiYO3fZXLiEC4g=
github.com/Code-Hex/go-generics-cache v1.3.1/go.mod h1:qxcC9kRVrct9rHeiYpFWSoW1vxyillCVzX13KZG8dl4=
github.com/DmitriyVTitov/size v1.5.0/go.mod h1:le6rNI4CoLQV1b9gzp1+3d7hMAD/uu2QcJ+aYbNgiU0=
github.com/alicebob/gopher-json v0.0.0-20200520072559-a9ecdc9d1d3a/go.mod h1:SGnFV6hVsYE877CKEZ6tDNTjaSXYUk6QqoIK6PrAtcc=
github.com/alicebob/gopher-json v0.0.0-20230218143504-906a9b012302 h1:uvdUDbHQHO85qeSydJtItA4T55Pw6BtAejd0APRJOCE=
Expand Down Expand Up @@ -83,6 +85,8 @@ go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
go.uber.org/zap v1.24.0 h1:FiJd5l1UOLj0wCgbSE0rwwXHzEdAZS6hiiSnxJN/D60=
go.uber.org/zap v1.24.0/go.mod h1:2kMP+WWQ8aoFoedH3T2sq6iJ2yDWpHbP0f6MQbS9Gkg=
golang.org/x/exp v0.0.0-20220328175248-053ad81199eb h1:pC9Okm6BVmxEw76PUu0XUbOTQ92JX11hfvqTjAV3qxM=
golang.org/x/exp v0.0.0-20220328175248-053ad81199eb/go.mod h1:lgLbSvA5ygNOMpwM/9anMpWVlVJ7Z+cHWq/eFuinpGE=
golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM=
golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE=
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
Expand Down
91 changes: 91 additions & 0 deletions pkg/statestore/ticketcache.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
package statestore

import (
"context"
"time"

cache "github.com/Code-Hex/go-generics-cache"
"open-match.dev/open-match/pkg/pb"
)

type ticketCacheOptions struct {
ttl time.Duration
}

func defaultTicketCacheOptions() *ticketCacheOptions {
return &ticketCacheOptions{
ttl: 10 * time.Second,
}
}

type TicketCacheOption interface {
apply(options *ticketCacheOptions)
}

type ticketCacheOptionFunc func(options *ticketCacheOptions)

func (f ticketCacheOptionFunc) apply(options *ticketCacheOptions) {
f(options)
}

func WithTicketCacheTTL(ttl time.Duration) TicketCacheOption {
return ticketCacheOptionFunc(func(options *ticketCacheOptions) {
options.ttl = ttl
})
}

// StoreWithTicketCache caches GetTicket results in-memory with TTL
type StoreWithTicketCache struct {
origin StateStore
ticketCache *cache.Cache[string, *pb.Ticket]
options *ticketCacheOptions
}

func NewStoreWithTicketCache(origin StateStore, ticketCache *cache.Cache[string, *pb.Ticket], opts ...TicketCacheOption) *StoreWithTicketCache {
options := defaultTicketCacheOptions()
for _, o := range opts {
o.apply(options)
}
return &StoreWithTicketCache{
origin: origin,
ticketCache: ticketCache,
options: options,
}
}

func (s *StoreWithTicketCache) CreateTicket(ctx context.Context, ticket *pb.Ticket) error {
return s.origin.CreateTicket(ctx, ticket)
}

func (s *StoreWithTicketCache) DeleteTicket(ctx context.Context, ticketID string) error {
s.ticketCache.Delete(ticketID)
return s.origin.DeleteTicket(ctx, ticketID)
}

func (s *StoreWithTicketCache) GetTicket(ctx context.Context, ticketID string) (*pb.Ticket, error) {
if ticket, hit := s.ticketCache.Get(ticketID); hit {
return ticket, nil
}
ticket, err := s.origin.GetTicket(ctx, ticketID)
if err != nil {
return nil, err
}
s.ticketCache.Set(ticketID, ticket, cache.WithExpiration(s.options.ttl))
return ticket, nil
}

func (s *StoreWithTicketCache) GetAssignment(ctx context.Context, ticketID string) (*pb.Assignment, error) {
return s.origin.GetAssignment(ctx, ticketID)
}

func (s *StoreWithTicketCache) GetActiveTickets(ctx context.Context, limit int64) ([]*pb.Ticket, error) {
return s.origin.GetActiveTickets(ctx, limit)
}

func (s *StoreWithTicketCache) ReleaseTickets(ctx context.Context, ticketIDs []string) error {
return s.origin.ReleaseTickets(ctx, ticketIDs)
}

func (s *StoreWithTicketCache) AssignTickets(ctx context.Context, asgs []*pb.AssignmentGroup) error {
return s.origin.AssignTickets(ctx, asgs)
}
38 changes: 38 additions & 0 deletions pkg/statestore/ticketcache_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package statestore

import (
"context"
"testing"
"time"

cache "github.com/Code-Hex/go-generics-cache"
"github.com/alicebob/miniredis/v2"
"github.com/stretchr/testify/require"
"open-match.dev/open-match/pkg/pb"
)

func TestTicketCache(t *testing.T) {
mr := miniredis.RunT(t)
ticketCache := cache.New[string, *pb.Ticket]()
ttl := 500 * time.Millisecond
redisStore := newTestRedisStore(t, mr.Addr())
store := NewStoreWithTicketCache(redisStore, ticketCache, WithTicketCacheTTL(ttl))
ctx := context.Background()

require.NoError(t, store.CreateTicket(ctx, &pb.Ticket{Id: "t1"}))
t1, err := store.GetTicket(ctx, "t1")
require.NoError(t, err)
require.Equal(t, "t1", t1.Id)

require.NoError(t, redisStore.DeleteTicket(ctx, "t1"))

// it can be retrieved from the cache even if deleted
t1, err = store.GetTicket(ctx, "t1")
require.NoError(t, err)
require.Equal(t, "t1", t1.Id)

time.Sleep(ttl + 10*time.Millisecond)

t1, err = store.GetTicket(ctx, "t1")
require.Error(t, err, ErrTicketNotFound)
}

0 comments on commit 5d18e39

Please sign in to comment.