From 25b7b9a07b1511d8242fa98b10ffb172478e6f27 Mon Sep 17 00:00:00 2001 From: Dwight Hubbard Date: Tue, 26 Apr 2016 19:12:04 -0700 Subject: [PATCH 1/3] Deal with the server being busy when it is starting up. --- redislite/client.py | 27 +++++++++++++++++++++++++-- tests/test_client.py | 15 +++++++++++++++ 2 files changed, 40 insertions(+), 2 deletions(-) diff --git a/redislite/client.py b/redislite/client.py index e2d0568..d0085ed 100644 --- a/redislite/client.py +++ b/redislite/client.py @@ -122,7 +122,7 @@ def _connection_count(self): for client in self.client_list(): flags = client.get('flags', '') flags = flags.upper() - if 'U' in flags or 'N' in flags: + if 'U' in flags or 'N' in flags: # pragma: no cover active_connections += 1 return active_connections @@ -196,9 +196,32 @@ def _start_redis(self): raise RedisLiteException( 'Redis socket file %s is not present' % self.socket_file ) + self._save_setting_registry() self.running = True + def _wait_for_server_start(self): + """ + Wait until the server is not busy when receiving a request + + Raises + ------ + RedisLiteServerStartError - Server start timed out + """ + timeout = True + for i in range(0, self.start_timeout * 10): + try: + self.ping() + timeout = False + break + except redis.BusyLoadingError: + pass + time.sleep(.1) + if timeout: # pragma: no cover + raise RedisLiteServerStartError( + 'The redis-server process failed to start' + ) + def _is_redis_running(self): """ Determine if there is a config setting for a currently running redis @@ -339,7 +362,7 @@ def __init__(self, *args, **kwargs): super(RedisMixin, self).__init__(*args, **kwargs) # pragma: no cover logger.debug("Pinging the server to ensure we're connected") - self.ping() + self._wait_for_server_start() def __del__(self): self._cleanup() # pragma: no cover diff --git a/tests/test_client.py b/tests/test_client.py index 3bd4d80..9369b4c 100644 --- a/tests/test_client.py +++ b/tests/test_client.py @@ -279,6 +279,21 @@ def test_connection_fallthrough(self): with self.assertRaises(ConnectionError): redislite.Redis(port=1).keys() + def test_shutdown_race_condition(self): + """ + Test that there is no race condition when a shutdown is run after + a large data operation. + """ + if os.path.exists('bug.redis'): + os.remove('bug.redis') + db = redislite.StrictRedis('bug.redis') + for key in range(10000): + db.hset("h1", os.urandom(32), " " * 65536) + db.save() + db._cleanup() + del db + db = redislite.StrictRedis('bug.redis') + if __name__ == '__main__': logging.basicConfig(level=logging.DEBUG) From ae96999327b4393f502c97e54e911e8f77ceb931 Mon Sep 17 00:00:00 2001 From: Dwight Hubbard Date: Tue, 26 Apr 2016 19:16:22 -0700 Subject: [PATCH 2/3] Cleanup --- tests/test_client.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/test_client.py b/tests/test_client.py index 9369b4c..3753f0e 100644 --- a/tests/test_client.py +++ b/tests/test_client.py @@ -293,6 +293,8 @@ def test_shutdown_race_condition(self): db._cleanup() del db db = redislite.StrictRedis('bug.redis') + if os.path.exists('bug.redis'): + os.remove('bug.redis') if __name__ == '__main__': From 53afcd54ebe2c18a3f3cba942e2d6b896c50bfa9 Mon Sep 17 00:00:00 2001 From: Dwight Hubbard Date: Wed, 27 Apr 2016 13:01:55 -0700 Subject: [PATCH 3/3] Give a better exception message --- redislite/client.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/redislite/client.py b/redislite/client.py index d0085ed..a1aa676 100644 --- a/redislite/client.py +++ b/redislite/client.py @@ -219,7 +219,8 @@ def _wait_for_server_start(self): time.sleep(.1) if timeout: # pragma: no cover raise RedisLiteServerStartError( - 'The redis-server process failed to start' + 'The redis-server process failed to start; unreachable after ' + '{0} seconds'.format(self.start_timeout) ) def _is_redis_running(self):