Skip to content

Commit 9762527

Browse files
committed
Add disk and memory usage checks
1 parent 8680d23 commit 9762527

File tree

5 files changed

+125
-3
lines changed

5 files changed

+125
-3
lines changed

.github/workflows/python-package.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ jobs:
3030
- name: Install dependencies
3131
run: |
3232
python -m pip install --upgrade pip
33-
pip install -e .
33+
pip install -e .[psutil]
3434
pip install "${{ matrix.django }}"
3535
- name: Test
3636
run: |

setup.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77

88
setup(
99
name='django-simple-health-check',
10-
version='0.2.0',
10+
version='0.3.0',
1111
description='Simple Django health check',
1212
long_description=open('README.md').read(),
1313
long_description_content_type='text/markdown',
@@ -21,6 +21,9 @@
2121
install_requires=[
2222
'Django>=3.1,<4.0',
2323
],
24+
extras_require={
25+
'psutil': ['psutil'],
26+
},
2427
python_requires='>=3.7.*, <4.0.*',
2528
license='MIT',
2629
zip_safe=False,

simple_health_check/checks/ps.py

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
import locale
2+
import socket
3+
4+
import psutil
5+
6+
from . import BaseHealthCheck
7+
from ..exceptions import HealthCheckError
8+
9+
10+
host = socket.gethostname()
11+
12+
13+
class DiskUsage(BaseHealthCheck):
14+
def __init__(self, max_usage_percent: int = 0):
15+
super().__init__()
16+
17+
self.max_usage_percent = max_usage_percent
18+
19+
def check(self):
20+
if not self.max_usage_percent:
21+
return
22+
23+
du = psutil.disk_usage('/')
24+
if du.percent >= self.max_usage_percent:
25+
raise HealthCheckError(f'{host} {du.percent}% disk usage exceeds {self.max_usage_percent}%')
26+
27+
28+
class MemoryUsage(BaseHealthCheck):
29+
MB_1 = 1024 * 1024
30+
31+
def __init__(self, min_memory_mb: int = 0):
32+
super().__init__()
33+
34+
self.min_memory_mb = min_memory_mb
35+
self._min_memory_mb = min_memory_mb * self.MB_1
36+
37+
def check(self):
38+
if not self.min_memory_mb:
39+
return
40+
41+
memory = psutil.virtual_memory()
42+
if memory.available < self._min_memory_mb:
43+
locale.setlocale(locale.LC_ALL, '')
44+
available = round(memory.available / self.MB_1, 2)
45+
raise HealthCheckError(f'{host} {available:n} MB available RAM below {self.min_memory_mb:d} MB')

simple_health_check/tests.py

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,3 +74,75 @@ def test_cache_no_rediness(self):
7474
response = self.client.get('/readiness/')
7575
self.assertTrue(response.status_code == 500)
7676
self.assertTrue(response.content == b'down')
77+
78+
@override_settings(
79+
SIMPLE_HEALTH_CHECKS={
80+
'simple_health_check.checks.ps.DiskUsage': None,
81+
},
82+
)
83+
def test_ps_disk_usage_no_value(self):
84+
apps.get_app_config('simple_health_check').register_checks()
85+
86+
response = self.client.get('/readiness/')
87+
self.assertTrue(response.status_code == 200)
88+
self.assertTrue(response.content == b'ok')
89+
90+
@override_settings(
91+
SIMPLE_HEALTH_CHECKS={
92+
'simple_health_check.checks.ps.DiskUsage': dict(max_usage_percent=99),
93+
},
94+
)
95+
def test_ps_disk_usage(self):
96+
apps.get_app_config('simple_health_check').register_checks()
97+
98+
response = self.client.get('/readiness/')
99+
self.assertTrue(response.status_code == 200)
100+
self.assertTrue(response.content == b'ok')
101+
102+
@override_settings(
103+
SIMPLE_HEALTH_CHECKS={
104+
'simple_health_check.checks.ps.DiskUsage': dict(max_usage_percent=0.001),
105+
},
106+
)
107+
def test_ps_disk_usage_no_rediness(self):
108+
apps.get_app_config('simple_health_check').register_checks()
109+
110+
response = self.client.get('/readiness/')
111+
self.assertTrue(response.status_code == 500)
112+
self.assertTrue(response.content == b'down')
113+
114+
@override_settings(
115+
SIMPLE_HEALTH_CHECKS={
116+
'simple_health_check.checks.ps.MemoryUsage': None,
117+
},
118+
)
119+
def test_ps_memory_usage_no_value(self):
120+
apps.get_app_config('simple_health_check').register_checks()
121+
122+
response = self.client.get('/readiness/')
123+
self.assertTrue(response.status_code == 200)
124+
self.assertTrue(response.content == b'ok')
125+
126+
@override_settings(
127+
SIMPLE_HEALTH_CHECKS={
128+
'simple_health_check.checks.ps.MemoryUsage': dict(min_memory_mb=10),
129+
},
130+
)
131+
def test_ps_memory_usage(self):
132+
apps.get_app_config('simple_health_check').register_checks()
133+
134+
response = self.client.get('/readiness/')
135+
self.assertTrue(response.status_code == 200)
136+
self.assertTrue(response.content == b'ok')
137+
138+
@override_settings(
139+
SIMPLE_HEALTH_CHECKS={
140+
'simple_health_check.checks.ps.MemoryUsage': dict(min_memory_mb=100_000),
141+
},
142+
)
143+
def test_ps_memory_usage_no_rediness(self):
144+
apps.get_app_config('simple_health_check').register_checks()
145+
146+
response = self.client.get('/readiness/')
147+
self.assertTrue(response.status_code == 500)
148+
self.assertTrue(response.content == b'down')

tox.ini

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,8 @@ skip_missing_interpreters = True
44
envlist = py{37,38,39,310}-django{31,32}
55

66
[testenv]
7-
commands = python manage.py test
7+
extras =
8+
psutil
89
deps =
910
django31: Django>=3.1,<3.2
1011
django32: Django>=3.2,<3.3
@@ -14,3 +15,4 @@ basepython =
1415
py38: {env:TOX_PYTHON_38}
1516
py39: {env:TOX_PYTHON_39}
1617
py310: {env:TOX_PYTHON_310}
18+
commands = python manage.py test

0 commit comments

Comments
 (0)