-
Notifications
You must be signed in to change notification settings - Fork 194
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
c389ea2
commit 91dd5f0
Showing
9 changed files
with
149 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
default_app_config = 'health_check.contrib.redis.apps.HealthCheckConfig' |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
from django.apps import AppConfig | ||
|
||
from health_check.plugins import plugin_dir | ||
|
||
|
||
class HealthCheckConfig(AppConfig): | ||
name = "health_check.contrib.redis" | ||
|
||
def ready(self): | ||
from .backends import RedisHealthCheck | ||
|
||
plugin_dir.register(RedisHealthCheck) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
import logging | ||
|
||
from django.conf import settings | ||
from redis import exceptions, from_url | ||
|
||
from health_check.backends import BaseHealthCheckBackend | ||
from health_check.exceptions import ServiceUnavailable | ||
|
||
logger = logging.getLogger(__name__) | ||
|
||
|
||
class RedisHealthCheck(BaseHealthCheckBackend): | ||
"""Health check for Redis.""" | ||
|
||
redis_url = getattr(settings, "REDIS_URL", 'redis://localhost/1') | ||
|
||
def check_status(self): | ||
"""Check Redis service by pinging the redis instance with a redis connection.""" | ||
logger.debug("Got %s as the redis_url. Connecting to redis...", self.redis_url) | ||
|
||
logger.debug("Attempting to connect to redis...") | ||
try: | ||
# conn is used as a context to release opened resources later | ||
with from_url(self.redis_url) as conn: | ||
conn.ping() # exceptions may be raised upon ping | ||
except ConnectionRefusedError as e: | ||
self.add_error(ServiceUnavailable("Unable to connect to Redis: Connection was refused."), e) | ||
except exceptions.TimeoutError as e: | ||
self.add_error(ServiceUnavailable("Unable to connect to Redis: Timeout."), e) | ||
except exceptions.ConnectionError as e: | ||
self.add_error(ServiceUnavailable("Unable to connect to Redis: Connection Error"), e) | ||
except BaseException as e: | ||
self.add_error(ServiceUnavailable("Unknown error"), e) | ||
else: | ||
logger.debug("Connection established. Redis is healthy.") |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -9,3 +9,4 @@ pydocstyle | |
pep8-naming | ||
pytest<4 | ||
pytest-django | ||
redis==3.3.8 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,88 @@ | ||
import mock | ||
from redis.exceptions import ConnectionError, TimeoutError | ||
|
||
from health_check.contrib.redis.backends import RedisHealthCheck | ||
|
||
|
||
class TestRedisHealthCheck: | ||
"""Test Redis health check.""" | ||
|
||
@mock.patch("health_check.contrib.redis.backends.getattr") | ||
@mock.patch("health_check.contrib.redis.backends.from_url", autospec=True) | ||
def test_redis_refused_connection(self, mocked_connection, mocked_getattr): | ||
"""Test when the connection to Redis is refused.""" | ||
mocked_getattr.return_value = "redis_url" | ||
|
||
# mock returns | ||
mocked_connection.return_value = mock.MagicMock() | ||
mocked_connection.return_value.__enter__.side_effect = ConnectionRefusedError("Refused connection") | ||
|
||
# instantiates the class | ||
redis_healthchecker = RedisHealthCheck() | ||
|
||
# invokes the method check_status() | ||
redis_healthchecker.check_status() | ||
assert len(redis_healthchecker.errors), 1 | ||
|
||
# mock assertions | ||
mocked_connection.assert_called_once_with('redis://localhost/1') | ||
|
||
@mock.patch("health_check.contrib.redis.backends.getattr") | ||
@mock.patch("health_check.contrib.redis.backends.from_url") | ||
def test_redis_timeout_error(self, mocked_connection, mocked_getattr): | ||
"""Test Redis TimeoutError.""" | ||
mocked_getattr.return_value = "redis_url" | ||
|
||
# mock returns | ||
mocked_connection.return_value = mock.MagicMock() | ||
mocked_connection.return_value.__enter__.side_effect = TimeoutError("Timeout Error") | ||
|
||
# instantiates the class | ||
redis_healthchecker = RedisHealthCheck() | ||
|
||
# invokes the method check_status() | ||
redis_healthchecker.check_status() | ||
assert len(redis_healthchecker.errors), 1 | ||
|
||
# mock assertions | ||
mocked_connection.assert_called_once_with('redis://localhost/1') | ||
|
||
@mock.patch("health_check.contrib.redis.backends.getattr") | ||
@mock.patch("health_check.contrib.redis.backends.from_url") | ||
def test_redis_con_limit_exceeded(self, mocked_connection, mocked_getattr): | ||
"""Test Connection Limit Exceeded error.""" | ||
mocked_getattr.return_value = "redis_url" | ||
|
||
# mock returns | ||
mocked_connection.return_value = mock.MagicMock() | ||
mocked_connection.return_value.__enter__.side_effect = ConnectionError("Connection Error") | ||
|
||
# instantiates the class | ||
redis_healthchecker = RedisHealthCheck() | ||
|
||
# invokes the method check_status() | ||
redis_healthchecker.check_status() | ||
assert len(redis_healthchecker.errors), 1 | ||
|
||
# mock assertions | ||
mocked_connection.assert_called_once_with('redis://localhost/1') | ||
|
||
@mock.patch("health_check.contrib.redis.backends.getattr") | ||
@mock.patch("health_check.contrib.redis.backends.from_url") | ||
def test_redis_conn_ok(self, mocked_connection, mocked_getattr): | ||
"""Test everything is OK.""" | ||
mocked_getattr.return_value = "redis_url" | ||
|
||
# mock returns | ||
mocked_connection.return_value = mock.MagicMock() | ||
mocked_connection.return_value.__enter__.side_effect = True | ||
|
||
# instantiates the class | ||
redis_healthchecker = RedisHealthCheck() | ||
|
||
# invokes the method check_status() | ||
redis_healthchecker.check_status() | ||
assert len(redis_healthchecker.errors), 0 | ||
|
||
# mock assertions | ||
mocked_connection.assert_called_once_with('redis://localhost/1') |