Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Health Check endpoint #392

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ RUN mkdir /opt/venv && \


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
# copy prod dependencies
COPY --from=prod-deps /opt/venv /opt/venv
Expand All @@ -51,4 +51,8 @@ ENV PATH /opt/venv/bin:$PATH
RUN ["chmod", "g+w", "."]
# Run bootstrap logic
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"]
36 changes: 36 additions & 0 deletions bookmarks/tests/test_health_view.py
Original file line number Diff line number Diff line change
@@ -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)
2 changes: 2 additions & 0 deletions bookmarks/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,4 +31,6 @@
# Feeds
path('feeds/<str:feed_key>/all', AllBookmarksFeed(), name='feeds.all'),
path('feeds/<str:feed_key>/unread', UnreadBookmarksFeed(), name='feeds.unread'),
# Health check
path('health', views.health, name='health')
]
1 change: 1 addition & 0 deletions bookmarks/views/__init__.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
from .bookmarks import *
from .settings import *
from .toasts import *
from .health import health
20 changes: 20 additions & 0 deletions bookmarks/views/health.py
Original file line number Diff line number Diff line change
@@ -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)