Skip to content

Commit

Permalink
Fallback on all Redis errors
Browse files Browse the repository at this point in the history
  • Loading branch information
VojtechVitek committed Aug 7, 2024
1 parent 487f95a commit 760fb8b
Showing 1 changed file with 16 additions and 23 deletions.
39 changes: 16 additions & 23 deletions httprateredis.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,7 @@ package httprateredis

import (
"context"
"errors"
"fmt"
"net"
"os"
"path/filepath"
"strconv"
Expand Down Expand Up @@ -107,13 +105,8 @@ func (c *redisCounter) IncrementBy(key string, currentWindow time.Time, amount i
return c.fallbackCounter.IncrementBy(key, currentWindow, amount)
}
defer func() {
if err != nil {
// On redis network error, fallback to local in-memory counter.
var netErr net.Error
if errors.As(err, &netErr) || errors.Is(err, redis.ErrClosed) {
c.fallback()
err = c.fallbackCounter.IncrementBy(key, currentWindow, amount)
}
if c.shouldFallback(err) {
err = c.fallbackCounter.IncrementBy(key, currentWindow, amount)
}
}()
}
Expand Down Expand Up @@ -147,13 +140,8 @@ func (c *redisCounter) Get(key string, currentWindow, previousWindow time.Time)
return c.fallbackCounter.Get(key, currentWindow, previousWindow)
}
defer func() {
if err != nil {
// On redis network error, fallback to local in-memory counter.
var netErr net.Error
if errors.As(err, &netErr) || errors.Is(err, redis.ErrClosed) {
c.fallback()
curr, prev, err = c.fallbackCounter.Get(key, currentWindow, previousWindow)
}
if c.shouldFallback(err) {
curr, prev, err = c.fallbackCounter.Get(key, currentWindow, previousWindow)
}
}()
}
Expand Down Expand Up @@ -189,25 +177,30 @@ func (c *redisCounter) IsFallbackActivated() bool {
return c.fallbackActivated.Load()
}

func (c *redisCounter) fallback() {
// Activate the in-memory counter fallback, unless activated by some other goroutine.
fallbackAlreadyActivated := c.fallbackActivated.Swap(true)
if fallbackAlreadyActivated {
return
func (c *redisCounter) shouldFallback(err error) bool {
if err == nil {
return false
}

go c.reconnect()
// Activate the local in-memory counter fallback, unless activated by some other goroutine.
alreadyActivated := c.fallbackActivated.Swap(true)
if !alreadyActivated {
go c.reconnect()
}

return true
}

func (c *redisCounter) reconnect() {
// Try to re-connect to redis every 200ms.
for {
time.Sleep(200 * time.Millisecond)

err := c.client.Ping(context.Background()).Err()
if err == nil {
c.fallbackActivated.Store(false)
return
}
time.Sleep(200 * time.Millisecond)
}
}

Expand Down

0 comments on commit 760fb8b

Please sign in to comment.