mirror of
https://github.com/inventree/InvenTree.git
synced 2026-01-10 05:08:09 +00:00
feat(backend): Add dedicated health endpoint (#11104)
* feat(backend): Add dedicated health endpoint * bump api version * add test for new endpoint * fix check
This commit is contained in:
@@ -1,13 +1,16 @@
|
|||||||
"""InvenTree API version information."""
|
"""InvenTree API version information."""
|
||||||
|
|
||||||
# InvenTree API version
|
# InvenTree API version
|
||||||
INVENTREE_API_VERSION = 437
|
INVENTREE_API_VERSION = 438
|
||||||
"""Increment this API version number whenever there is a significant change to the API that any clients need to know about."""
|
"""Increment this API version number whenever there is a significant change to the API that any clients need to know about."""
|
||||||
|
|
||||||
INVENTREE_API_TEXT = """
|
INVENTREE_API_TEXT = """
|
||||||
|
|
||||||
|
v438 -> 2026-01-09 : https://github.com/inventree/InvenTree/pull/11104
|
||||||
|
- Adds a simpler / faster health check endpoint at /api/system/health/
|
||||||
|
|
||||||
v437 -> 2026-01-07 : https://github.com/inventree/InvenTree/pull/11084
|
v437 -> 2026-01-07 : https://github.com/inventree/InvenTree/pull/11084
|
||||||
- Add generic parameter support for the StockLocation model
|
- Adds generic parameter support for the StockLocation model
|
||||||
|
|
||||||
v436 -> 2026-01-06 : https://github.com/inventree/InvenTree/pull/11035
|
v436 -> 2026-01-06 : https://github.com/inventree/InvenTree/pull/11035
|
||||||
- Removes model-specific metadata endpoints and replaces them with redirects
|
- Removes model-specific metadata endpoints and replaces them with redirects
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ from django.conf import settings
|
|||||||
from django.contrib.contenttypes.models import ContentType
|
from django.contrib.contenttypes.models import ContentType
|
||||||
from django.core.exceptions import ValidationError
|
from django.core.exceptions import ValidationError
|
||||||
from django.db.models import Q
|
from django.db.models import Q
|
||||||
|
from django.http import JsonResponse
|
||||||
from django.http.response import HttpResponse
|
from django.http.response import HttpResponse
|
||||||
from django.urls import include, path, re_path
|
from django.urls import include, path, re_path
|
||||||
from django.utils.decorators import method_decorator
|
from django.utils.decorators import method_decorator
|
||||||
@@ -33,6 +34,7 @@ import common.filters
|
|||||||
import common.models
|
import common.models
|
||||||
import common.serializers
|
import common.serializers
|
||||||
import InvenTree.conversion
|
import InvenTree.conversion
|
||||||
|
import InvenTree.ready
|
||||||
from common.icons import get_icon_packs
|
from common.icons import get_icon_packs
|
||||||
from common.settings import get_global_setting
|
from common.settings import get_global_setting
|
||||||
from data_exporter.mixins import DataExportViewMixin
|
from data_exporter.mixins import DataExportViewMixin
|
||||||
@@ -1071,6 +1073,48 @@ class TestEmail(CreateAPI):
|
|||||||
) # pragma: no cover
|
) # pragma: no cover
|
||||||
|
|
||||||
|
|
||||||
|
class HealthCheckStatusSerializer(serializers.Serializer):
|
||||||
|
"""Status of the overall system health."""
|
||||||
|
|
||||||
|
status = serializers.ChoiceField(
|
||||||
|
help_text='Health status of the InvenTree server',
|
||||||
|
choices=['ok', 'loading'],
|
||||||
|
read_only=True,
|
||||||
|
default='ok',
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class HealthCheckView(APIView):
|
||||||
|
"""Simple JSON endpoint for InvenTree health check.
|
||||||
|
|
||||||
|
Intended to be used by external services to confirm that the InvenTree server is running.
|
||||||
|
"""
|
||||||
|
|
||||||
|
permission_classes = [AllowAnyOrReadScope]
|
||||||
|
|
||||||
|
@extend_schema(
|
||||||
|
responses={
|
||||||
|
200: OpenApiResponse(
|
||||||
|
response=HealthCheckStatusSerializer,
|
||||||
|
description='InvenTree server health status',
|
||||||
|
)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
def get(self, request, *args, **kwargs):
|
||||||
|
"""Simple health check endpoint for monitoring purposes.
|
||||||
|
|
||||||
|
Use the root API endpoint for more detailed information (using an authenticated request).
|
||||||
|
"""
|
||||||
|
status = (
|
||||||
|
InvenTree.ready.isPluginRegistryLoaded()
|
||||||
|
if settings.PLUGINS_ENABLED
|
||||||
|
else True
|
||||||
|
)
|
||||||
|
return JsonResponse(
|
||||||
|
{'status': 'ok' if status else 'loading'}, status=200 if status else 503
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
selection_urls = [
|
selection_urls = [
|
||||||
path(
|
path(
|
||||||
'<int:pk>/',
|
'<int:pk>/',
|
||||||
@@ -1346,6 +1390,11 @@ common_api_urls = [
|
|||||||
path('', DataOutputList.as_view(), name='api-data-output-list'),
|
path('', DataOutputList.as_view(), name='api-data-output-list'),
|
||||||
]),
|
]),
|
||||||
),
|
),
|
||||||
|
# System APIs (related to basic system functions)
|
||||||
|
path(
|
||||||
|
'system/',
|
||||||
|
include([path('health/', HealthCheckView.as_view(), name='api-system-health')]),
|
||||||
|
),
|
||||||
]
|
]
|
||||||
|
|
||||||
admin_api_urls = [
|
admin_api_urls = [
|
||||||
|
|||||||
@@ -1471,6 +1471,35 @@ class CommonTest(InvenTreeAPITestCase):
|
|||||||
self.user.is_superuser = False
|
self.user.is_superuser = False
|
||||||
self.user.save()
|
self.user.save()
|
||||||
|
|
||||||
|
def test_health_api(self):
|
||||||
|
"""Test health check URL."""
|
||||||
|
from plugin import registry
|
||||||
|
|
||||||
|
# Fully started system - ok
|
||||||
|
response_data = self.get(reverse('api-system-health'), expected_code=200).json()
|
||||||
|
self.assertIn('status', response_data)
|
||||||
|
self.assertEqual(response_data['status'], 'ok')
|
||||||
|
|
||||||
|
# Simulate plugin reloading - Not ready
|
||||||
|
try:
|
||||||
|
registry.plugins_loaded = False
|
||||||
|
response_data = self.get(
|
||||||
|
reverse('api-system-health'), expected_code=503
|
||||||
|
).json()
|
||||||
|
self.assertIn('status', response_data)
|
||||||
|
self.assertEqual(response_data['status'], 'loading')
|
||||||
|
finally:
|
||||||
|
registry.plugins_loaded = True
|
||||||
|
|
||||||
|
# No plugins enabled - still ok
|
||||||
|
with self.settings(PLUGINS_ENABLED=False):
|
||||||
|
self.assertEqual(
|
||||||
|
self.get(reverse('api-system-health'), expected_code=200).json()[
|
||||||
|
'status'
|
||||||
|
],
|
||||||
|
'ok',
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class CurrencyAPITests(InvenTreeAPITestCase):
|
class CurrencyAPITests(InvenTreeAPITestCase):
|
||||||
"""Unit tests for the currency exchange API endpoints."""
|
"""Unit tests for the currency exchange API endpoints."""
|
||||||
|
|||||||
Reference in New Issue
Block a user