From: Sipwise Development Team <support@sipwise.com>
Date: Wed, 12 May 2021 11:53:43 +0200
Subject: db_redis_graceful_scan

---
 src/modules/db_redis/redis_dbase.c | 19 +++++++++++++++----
 1 file changed, 15 insertions(+), 4 deletions(-)

diff --git a/src/modules/db_redis/redis_dbase.c b/src/modules/db_redis/redis_dbase.c
index 1b0c72e..d088b89 100644
--- a/src/modules/db_redis/redis_dbase.c
+++ b/src/modules/db_redis/redis_dbase.c
@@ -754,7 +754,7 @@ static int db_redis_scan_query_keys_pattern(km_redis_con_t *con, const str *matc
     int l;
 
 
-#undef USE_SCAN
+#define USE_SCAN
 
 #ifdef USE_SCAN
 
@@ -762,6 +762,8 @@ static int db_redis_scan_query_keys_pattern(km_redis_con_t *con, const str *matc
     unsigned long cursor = 0;
     unsigned int match_count = match_count_start_val;
     char match_count_str[16];
+    struct timeval start_tv, end_tv;
+    long tv_diff;
 
     do {
         snprintf(cursor_str, sizeof(cursor_str), "%lu", cursor);
@@ -796,7 +798,12 @@ static int db_redis_scan_query_keys_pattern(km_redis_con_t *con, const str *matc
             goto err;
         }
 
+        gettimeofday(&start_tv, NULL);
         reply = db_redis_command_argv(con, query_v);
+        gettimeofday(&end_tv, NULL);
+        tv_diff = ((long long) end_tv.tv_sec * 1000LL + end_tv.tv_usec / 1000L)
+                - ((long long) start_tv.tv_sec * 1000LL + start_tv.tv_usec / 1000L);
+
         db_redis_key_free(&query_v);
         db_redis_check_reply(con, reply, err);
         if (reply->type != REDIS_REPLY_ARRAY) {
@@ -870,11 +877,15 @@ static int db_redis_scan_query_keys_pattern(km_redis_con_t *con, const str *matc
         }
 
 #ifdef USE_SCAN
-        // exponential increase and falloff, hovering around 1000 results
-        if (keys_list->elements > 1300 && match_count > 500)
+        // exponential increase and falloff, not to exceed ~100 ms query run time
+        if (tv_diff > 50 && match_count > 10)
             match_count /= 2;
-        else if (keys_list->elements < 700 && match_count < 500000)
+        else if (tv_diff < 25 && match_count < 1000000)
             match_count *= 2;
+        if (cursor > 0) {
+            // give other queries some time to run
+            usleep(100000);
+        }
 #endif
 
         db_redis_free_reply(&reply);
