From e7a5f0c83aae4f5a362160218ecc43c8f2bfcaea Mon Sep 17 00:00:00 2001 From: agodnic Date: Wed, 31 May 2023 16:25:16 -0300 Subject: [PATCH] Fix an infinite loop in redis cache client (#369) When initializing the notional cache, if there was more than one page of results, the client would run into an infinite loop. This issue was causing several services to stall on startup in the staging environment (API, analytics, etc). --- common/client/cache/notional/cache.go | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/common/client/cache/notional/cache.go b/common/client/cache/notional/cache.go index a83c99e2..0cc9fbde 100644 --- a/common/client/cache/notional/cache.go +++ b/common/client/cache/notional/cache.go @@ -71,6 +71,7 @@ func NewNotionalCache(ctx context.Context, redisClient *redis.Client, channel st // Init subscribe to notional pubsub and load the cache. func (c *NotionalCache) Init(ctx context.Context) error { + // load notional cache err := c.loadCache(ctx) if err != nil { @@ -85,13 +86,21 @@ func (c *NotionalCache) Init(ctx context.Context) error { // loadCache load notional cache from redis. func (c *NotionalCache) loadCache(ctx context.Context) error { - scanCom := c.client.Scan(ctx, 0, wormscanNotionalCacheKeyRegex, 100) + + var cursor uint64 + var err error for { - // Scan for notional keys - keys, cursor, err := scanCom.Result() + // Get a page of results from the cursor + var keys []string + scanCmd := c.client.Scan(ctx, cursor, wormscanNotionalCacheKeyRegex, 100) + if scanCmd.Err() != nil { + c.logger.Error("redis.ScanCmd has errors", zap.Error(err)) + return fmt.Errorf("redis.ScanCmd has errors: %w", err) + } + keys, cursor, err = scanCmd.Result() if err != nil { - c.logger.Error("loadCache", zap.Error(err)) - return err + c.logger.Error("call to redis.ScanCmd.Result() failed", zap.Error(err)) + return fmt.Errorf("call to redis.ScanCmd.Result() failed: %w", err) } // Get notional value from keys @@ -107,11 +116,11 @@ func (c *NotionalCache) loadCache(ctx context.Context) error { c.notionalMap.Store(key, field) } + // If we've reached the end of the cursor, return if cursor == 0 { - break + return nil } } - return nil } // Subscribe to a notional update channel and load new values for the notional cache.