Skip to content

Commit 92aebad

Browse files
Merge branch 'revsys:master' into feature/disable-atomic-requests-for-health-check
2 parents 57cb9ba + d8c700f commit 92aebad

5 files changed

Lines changed: 62 additions & 6 deletions

File tree

README.md

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,20 @@ To use Health Check Subsets, Specify a subset name and associate it with the rel
105105
}
106106
```
107107

108+
To add checks on a specific database, it's possible to parameterize `DatabaseBackend` to use a specific database:
109+
```python
110+
HEALTH_CHECK = {
111+
# .....
112+
"SUBSETS": {
113+
"database-probe": [
114+
"DatabaseBackend[default]", # This is equivalent to "DatabaseBackend"
115+
"DatabaseBackend[secondary]",
116+
],
117+
},
118+
# .....
119+
}
120+
```
121+
108122
To only execute specific subset of health check
109123
```shell
110124
curl -X GET -H "Accept: application/json" http://www.example.com/ht/startup-probe/

health_check/db/apps.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
from django.apps import AppConfig
2+
from django.conf import settings
23

34
from health_check.plugins import plugin_dir
45

@@ -11,3 +12,6 @@ def ready(self):
1112
from .backends import DatabaseBackend
1213

1314
plugin_dir.register(DatabaseBackend)
15+
16+
for database_name in settings.DATABASES.keys():
17+
plugin_dir.register(DatabaseBackend, database_name=database_name)

health_check/db/backends.py

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
from django.db import DatabaseError, IntegrityError
1+
from django.db import DatabaseError, IntegrityError, transaction
22

33
from health_check.backends import BaseHealthCheckBackend
44
from health_check.exceptions import ServiceReturnedUnexpectedResult, ServiceUnavailable
@@ -7,13 +7,26 @@
77

88

99
class DatabaseBackend(BaseHealthCheckBackend):
10+
database_name = ""
11+
12+
def __init__(self, database_name: str = "") -> None:
13+
super().__init__()
14+
self.database_name = database_name or None
15+
1016
def check_status(self):
1117
try:
12-
obj = TestModel.objects.create(title="test")
13-
obj.title = "newtest"
14-
obj.save()
15-
obj.delete()
18+
with transaction.atomic(using=self.database_name):
19+
obj = TestModel.objects.create(title="test")
20+
obj.title = "newtest"
21+
obj.save()
22+
obj.delete()
1623
except IntegrityError:
1724
raise ServiceReturnedUnexpectedResult("Integrity Error")
1825
except DatabaseError:
1926
raise ServiceUnavailable("Database error")
27+
28+
def identifier(self) -> str:
29+
if not self.database_name:
30+
return super().identifier()
31+
32+
return f"{self.__class__.__name__}[{self.database_name}]"

tests/test_autodiscover.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,9 @@ def test_autodiscover(self):
2020
]
2121

2222
# The number of installed apps excluding celery should equal to all plugins except celery
23-
assert len(non_celery_plugins) == len(health_check_plugins)
23+
assert len(non_celery_plugins) == len(health_check_plugins) + len(
24+
settings.DATABASES # Each database creates specific health_check attached to it
25+
)
2426

2527
def test_discover_celery_queues(self):
2628
celery_plugins = [x for x in plugin_dir._registry if issubclass(x[0], CeleryHealthCheck)]

tests/test_db.py

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
from django.test import TestCase
66

77
from health_check.db.backends import DatabaseBackend
8+
from health_check.mixins import CheckMixin
89

910

1011
class MockDBModel(Model):
@@ -78,3 +79,25 @@ def test_raise_exception(self):
7879
db_backend = DatabaseBackend()
7980
with self.assertRaises(Exception):
8081
db_backend.run_check()
82+
83+
84+
class MultipleDatabasesTests(TestCase):
85+
"""
86+
Tests database specific features.
87+
Ensures that all databases are registered as their own backend and each backend runs in its own database.
88+
"""
89+
90+
def test_all_databases_registered(self):
91+
check_mixin = CheckMixin()
92+
all_plugins = check_mixin.plugins
93+
94+
self.assertIn("DatabaseBackend[default]", all_plugins)
95+
self.assertIn("DatabaseBackend[other]", all_plugins)
96+
97+
@patch("django.db.transaction.atomic")
98+
def test_checks_on_database(self, mocked_atomic):
99+
db1_health_check = DatabaseBackend(database_name="other")
100+
101+
db1_health_check.run_check()
102+
103+
mocked_atomic.assert_called_with(using="other")

0 commit comments

Comments
 (0)