Skip to content

Commit

Permalink
chore: add labels to redis failure metric
Browse files Browse the repository at this point in the history
  • Loading branch information
gussf committed Jun 17, 2024
1 parent f1a7d5e commit 32c8405
Show file tree
Hide file tree
Showing 11 changed files with 22 additions and 21 deletions.
4 changes: 2 additions & 2 deletions config/default.yaml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
---
gracefulShutdownTimeout: 30
apns:
rateLimit.rpm: 100
rateLimit.rpm: 20
concurrentWorkers: 300
connectionPoolSize: 1
pushQueueSize: 100
Expand All @@ -15,7 +15,7 @@ apns:
teamID: "ABC123DEFG"
topic: "com.game.test"
gcm:
rateLimit.rpm: 100
rateLimit.rpm: 20
pingInterval: 30
pingTimeout: 10
maxPendingMessages: 100
Expand Down
2 changes: 1 addition & 1 deletion extensions/apns_message_handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -231,7 +231,7 @@ func (a *APNSMessageHandler) HandleMessages(ctx context.Context, message interfa
return
}

allowed := a.rateLimiter.Allow(ctx, notification.DeviceToken)
allowed := a.rateLimiter.Allow(ctx, notification.DeviceToken, a.appName, "apns")
if !allowed {
statsReporterNotificationRateLimitReached(a.StatsReporters, a.appName, "apns")
l.WithField("message", message).Warn("rate limit reached")
Expand Down
4 changes: 2 additions & 2 deletions extensions/common.go
Original file line number Diff line number Diff line change
Expand Up @@ -94,9 +94,9 @@ func statsReporterNotificationRateLimitReached(statsReporters []interfaces.Stats
}
}

func statsReporterNotificationRateLimitFailed(statsReporters []interfaces.StatsReporter) {
func statsReporterNotificationRateLimitFailed(statsReporters []interfaces.StatsReporter, game string, platform string) {
for _, statsReporter := range statsReporters {
statsReporter.NotificationRateLimitFailed()
statsReporter.NotificationRateLimitFailed(game, platform)
}
}

Expand Down
4 changes: 2 additions & 2 deletions extensions/datadog_statsd.go
Original file line number Diff line number Diff line change
Expand Up @@ -121,10 +121,10 @@ func (s *StatsD) NotificationRateLimitReached(game string, platform string) {
}

// NotificationRateLimitFailed stores how many times rate limits failed to be calculated
func (s *StatsD) NotificationRateLimitFailed() {
func (s *StatsD) NotificationRateLimitFailed(game string, platform string) {
s.Client.Incr(
"rate_limit_failed",
[]string{},
[]string{fmt.Sprintf("platform:%s", platform), fmt.Sprintf("game:%s", game)},
1,
)
}
Expand Down
2 changes: 1 addition & 1 deletion extensions/gcm_message_handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -345,7 +345,7 @@ func (g *GCMMessageHandler) sendMessage(message interfaces.KafkaMessage) error {

l = l.WithField("message", km)

allowed := g.rateLimiter.Allow(context.Background(), km.To)
allowed := g.rateLimiter.Allow(context.Background(), km.To, message.Game, "gcm")
if !allowed {
statsReporterNotificationRateLimitReached(g.StatsReporters, message.Game, "gcm")
l.WithField("message", message).Warn("rate limit reached")
Expand Down
2 changes: 1 addition & 1 deletion extensions/handler/message_handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ func (h *messageHandler) HandleMessages(ctx context.Context, msg interfaces.Kafk
return
}

allowed := h.rateLimiter.Allow(ctx, km.To)
allowed := h.rateLimiter.Allow(ctx, km.To, msg.Game, "gcm")
if !allowed {
h.reportRateLimitReached(msg.Game)
l.WithField("message", msg).Warn("rate limit reached")
Expand Down
8 changes: 4 additions & 4 deletions extensions/rate_limiter.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ func NewRateLimiter(limit int, config *viper.Viper, statsReporters []interfaces.
// Allow checks Redis for the current rate a given device has in the current minute
// If the rate is lower than the limit, the message is allowed. Otherwise, it is not allowed.
// Reference: https://redis.io/glossary/rate-limiting/
func (r rateLimiter) Allow(ctx context.Context, device string) bool {
func (r rateLimiter) Allow(ctx context.Context, device string, game string, platform string) bool {
deviceKey := fmt.Sprintf("%s:%d", device, time.Now().Minute())
l := r.l.WithFields(logrus.Fields{
"deviceKey": deviceKey,
Expand All @@ -66,7 +66,7 @@ func (r rateLimiter) Allow(ctx context.Context, device string) bool {
if err != nil && !errors.Is(err, redis.Nil) {
// Something went wrong, return true to avoid blocking notifications.
l.WithError(err).Error("could not get current rate in redis")
statsReporterNotificationRateLimitFailed(r.statsReporters)
statsReporterNotificationRateLimitFailed(r.statsReporters, game, platform)
return true
}
if errors.Is(err, redis.Nil) {
Expand All @@ -78,7 +78,7 @@ func (r rateLimiter) Allow(ctx context.Context, device string) bool {
if err != nil {
// Something went wrong, return true to avoid blocking notifications.
l.WithError(err).Error("current rate is invalid")
statsReporterNotificationRateLimitFailed(r.statsReporters)
statsReporterNotificationRateLimitFailed(r.statsReporters, game, platform)
return true
}

Expand All @@ -94,7 +94,7 @@ func (r rateLimiter) Allow(ctx context.Context, device string) bool {
if err != nil {
// Allow the operation even if the transaction fails, to avoid blocking notifications.
l.WithError(err).Error("increment to current rate failed")
statsReporterNotificationRateLimitFailed(r.statsReporters)
statsReporterNotificationRateLimitFailed(r.statsReporters, game, platform)
}

l.WithField("currentRate", current).Debug("current rate allows message")
Expand Down
11 changes: 6 additions & 5 deletions extensions/rate_limiter_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,19 +27,20 @@ var _ = FDescribe("Rate Limiter", func() {
config, err := util.NewViperWithConfigFile(configFile)
Expect(err).NotTo(HaveOccurred())
hook.Reset()

game := "test"
platform := "test"
statsClients := []interfaces.StatsReporter{}

Describe("Rate limiting", func() {
It("should return not-allowed when rate limit is reached", func() {
rl := NewRateLimiter(1, config, statsClients, logger)
ctx := context.Background()
device := uuid.NewString()
allowed := rl.Allow(ctx, device)
allowed := rl.Allow(ctx, device, game, platform)
Expect(allowed).To(BeTrue())

// Should not allow due to reaching limit of 1
allowed = rl.Allow(ctx, device)
allowed = rl.Allow(ctx, device, game, platform)
Expect(allowed).To(BeFalse())
})

Expand All @@ -49,7 +50,7 @@ var _ = FDescribe("Rate Limiter", func() {
device := uuid.NewString()
currMin := time.Now().Minute()

allowed := rl.Allow(ctx, device)
allowed := rl.Allow(ctx, device, game, platform)
Expect(allowed).To(BeTrue())

key := fmt.Sprintf("%s:%d", device, currMin)
Expand All @@ -66,7 +67,7 @@ var _ = FDescribe("Rate Limiter", func() {
ctx := context.Background()
device := uuid.NewString()

allowed := rl.Allow(ctx, device)
allowed := rl.Allow(ctx, device, game, platform)
Expect(allowed).To(BeTrue())
})

Expand Down
2 changes: 1 addition & 1 deletion interfaces/rate_limiter.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,5 +26,5 @@ import "context"

// RateLimiter interface for rate limiting notifications per device.
type RateLimiter interface {
Allow(ctx context.Context, device string) bool
Allow(ctx context.Context, device, game, platform string) bool
}
2 changes: 1 addition & 1 deletion interfaces/stats_reporter.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ type StatsReporter interface {
ReportMetricGauge(metric string, value float64, game string, platform string)
ReportMetricCount(metric string, value int64, game string, platform string)
NotificationRateLimitReached(game string, platform string)
NotificationRateLimitFailed()
NotificationRateLimitFailed(game string, platform string)
ReportSendNotificationLatency(latencyMs time.Duration, game string, platform string, labels ...string)
ReportFirebaseLatency(latencyMs time.Duration, game string, labels ...string)
}
2 changes: 1 addition & 1 deletion mocks/rate_limiter.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,6 @@ func NewRateLimiterMock() *rateLimiterMock {
return &rateLimiterMock{}
}

func (rl *rateLimiterMock) Allow(ctx context.Context, device string) bool {
func (rl *rateLimiterMock) Allow(ctx context.Context, device, game, platform string) bool {
return true
}

0 comments on commit 32c8405

Please sign in to comment.