mirror of
https://github.com/sissbruecker/linkding
synced 2024-11-10 06:04:15 +00:00
Add Health Check endpoint (#392)
* add simple health endpoint * add curl and healthcheck to dockerfile * convert to view * add simple test * Add unhealthy test * Cleanup * check for LD_SERVER_PORT env var in healthcheck def * Revert changes to middlewares.py Co-authored-by: Sascha Ißbrücker <sascha.issbruecker@gmail.com>
This commit is contained in:
parent
894625aa25
commit
da99b8b034
5 changed files with 64 additions and 1 deletions
|
@ -34,7 +34,7 @@ RUN mkdir /opt/venv && \
|
||||||
|
|
||||||
|
|
||||||
FROM python:3.10.6-slim-buster as final
|
FROM python:3.10.6-slim-buster as final
|
||||||
RUN apt-get update && apt-get -y install mime-support libpq-dev
|
RUN apt-get update && apt-get -y install mime-support libpq-dev curl
|
||||||
WORKDIR /etc/linkding
|
WORKDIR /etc/linkding
|
||||||
# copy prod dependencies
|
# copy prod dependencies
|
||||||
COPY --from=prod-deps /opt/venv /opt/venv
|
COPY --from=prod-deps /opt/venv /opt/venv
|
||||||
|
@ -51,4 +51,8 @@ ENV PATH /opt/venv/bin:$PATH
|
||||||
RUN ["chmod", "g+w", "."]
|
RUN ["chmod", "g+w", "."]
|
||||||
# Run bootstrap logic
|
# Run bootstrap logic
|
||||||
RUN ["chmod", "+x", "./bootstrap.sh"]
|
RUN ["chmod", "+x", "./bootstrap.sh"]
|
||||||
|
|
||||||
|
HEALTHCHECK --interval=30s --retries=3 --timeout=1s \
|
||||||
|
CMD curl -f http://localhost:${LD_SERVER_PORT:-9090}/health || exit 1
|
||||||
|
|
||||||
CMD ["./bootstrap.sh"]
|
CMD ["./bootstrap.sh"]
|
||||||
|
|
36
bookmarks/tests/test_health_view.py
Normal file
36
bookmarks/tests/test_health_view.py
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
from unittest.mock import patch
|
||||||
|
|
||||||
|
from django.db import connections
|
||||||
|
from django.test import TestCase
|
||||||
|
|
||||||
|
from bookmarks.views.settings import app_version
|
||||||
|
|
||||||
|
|
||||||
|
class HealthViewTestCase(TestCase):
|
||||||
|
|
||||||
|
def test_health_healthy(self):
|
||||||
|
response = self.client.get("/health")
|
||||||
|
|
||||||
|
self.assertEqual(response.status_code, 200)
|
||||||
|
|
||||||
|
response_body = response.json()
|
||||||
|
expected_body = {
|
||||||
|
'version': app_version,
|
||||||
|
'status': 'healthy'
|
||||||
|
}
|
||||||
|
self.assertDictEqual(response_body, expected_body)
|
||||||
|
|
||||||
|
def test_health_unhealhty(self):
|
||||||
|
with patch.object(connections['default'], 'ensure_connection') as mock_ensure_connection:
|
||||||
|
mock_ensure_connection.side_effect = Exception('Connection error')
|
||||||
|
|
||||||
|
response = self.client.get("/health")
|
||||||
|
|
||||||
|
self.assertEqual(response.status_code, 500)
|
||||||
|
|
||||||
|
response_body = response.json()
|
||||||
|
expected_body = {
|
||||||
|
'version': app_version,
|
||||||
|
'status': 'unhealthy'
|
||||||
|
}
|
||||||
|
self.assertDictEqual(response_body, expected_body)
|
|
@ -31,4 +31,6 @@ urlpatterns = [
|
||||||
# Feeds
|
# Feeds
|
||||||
path('feeds/<str:feed_key>/all', AllBookmarksFeed(), name='feeds.all'),
|
path('feeds/<str:feed_key>/all', AllBookmarksFeed(), name='feeds.all'),
|
||||||
path('feeds/<str:feed_key>/unread', UnreadBookmarksFeed(), name='feeds.unread'),
|
path('feeds/<str:feed_key>/unread', UnreadBookmarksFeed(), name='feeds.unread'),
|
||||||
|
# Health check
|
||||||
|
path('health', views.health, name='health')
|
||||||
]
|
]
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
from .bookmarks import *
|
from .bookmarks import *
|
||||||
from .settings import *
|
from .settings import *
|
||||||
from .toasts import *
|
from .toasts import *
|
||||||
|
from .health import health
|
||||||
|
|
20
bookmarks/views/health.py
Normal file
20
bookmarks/views/health.py
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
from django.db import connections
|
||||||
|
from django.http import JsonResponse
|
||||||
|
|
||||||
|
from bookmarks.views.settings import app_version
|
||||||
|
|
||||||
|
|
||||||
|
def health(request):
|
||||||
|
code = 200
|
||||||
|
response = {
|
||||||
|
'version': app_version,
|
||||||
|
'status': 'healthy'
|
||||||
|
}
|
||||||
|
|
||||||
|
try:
|
||||||
|
connections['default'].ensure_connection()
|
||||||
|
except Exception:
|
||||||
|
response['status'] = 'unhealthy'
|
||||||
|
code = 500
|
||||||
|
|
||||||
|
return JsonResponse(response, status=code)
|
Loading…
Reference in a new issue