Skip to content

Commit de02a02

Browse files
authored
feat: Add endpoint which returns 500 if any critical errors in sendpost.py occur (#390)
* chore: allow print calls to show in docker log * feat: set up health check endpoint * fix: correct import
1 parent 9e3d41c commit de02a02

File tree

6 files changed

+70
-7
lines changed

6 files changed

+70
-7
lines changed

docker-compose.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ services:
1414
- redis
1515
volumes:
1616
- .:/meow
17+
environment:
18+
PYTHONUNBUFFERED: 1
1719
db:
1820
image: postgres:latest
1921
environment:

meow/meow/urls.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,5 +6,7 @@
66
urlpatterns = [
77
url(r'^admin/', admin.site.urls),
88
url(r'^api/v1/', include('urls.urls')),
9+
url(r'healthcheck/', views.healthcheck, name='healthcheck'),
10+
url(r'healthchecktest/', views.healthchecktest, name='healthchecktest'),
911
url(r'', views.base, name='base')
1012
]

meow/meow/views.py

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,31 @@
22
import re
33
from django.shortcuts import redirect, render, get_object_or_404
44
from django.template.loader import get_template
5+
from django.http import JsonResponse
6+
7+
# For health check
8+
from scheduler.management.healthcheck import HealthCheck
59

610
def base(request):
711
#print("BASE")
812
return render(request, 'base.html')
13+
14+
def healthcheck(request):
15+
(healthy, message) = HealthCheck.healthCheck()
16+
17+
# Set up JSON Response
18+
data = {
19+
'healthy': str(healthy),
20+
'message': message if message else ''
21+
}
22+
23+
return JsonResponse(data, status=(500 if not healthy else 200))
24+
25+
# Test only, sets program to unhealthy state
26+
def healthchecktest(request):
27+
msg = request.GET.get('msg', '')
28+
29+
print('Health Check Test: ' + msg, flush=True)
30+
31+
HealthCheck.setUnhealthy(msg if msg else None)
32+
return JsonResponse({'message': 'ok'})

meow/scheduler/management/commands/sendposts.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
import logging
1919

2020
from scheduler.models import MeowSetting, SMPost
21+
from scheduler.management.healthcheck import HealthCheck
2122

2223
logger = logging.getLogger('scheduler')
2324

@@ -125,6 +126,7 @@ def handle(self, *args, **options):
125126
except:
126127
logger.critical("Something is very wrong in sendpost.py ")
127128
logger.critical("Something is very wrong in sendpost.py " + str(traceback.format_exc()))
129+
HealthCheck.setUnhealthy("Something is very wrong in sendpost.py " + str(traceback.format_exc()))
128130
post.log(traceback.format_exc())
129131

130132
logger.info("sendpost.py: Post {}-{} failed to send because it would been late. ".format(post.slug, post.id))
@@ -190,5 +192,6 @@ def handle(self, *args, **options):
190192
post.save()
191193
except (Exception) as e:
192194
logger.critical("Something is very wrong" + traceback.format_exc())
195+
HealthCheck.setUnhealthy("Something is very wrong" + traceback.format_exc())
193196
post.log(traceback.format_exc())
194197
post.log_error(e, post.section, True)
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
from typing import Optional, Tuple, List
2+
3+
'''
4+
Utils class to check app health.
5+
Used for Kubernetes to automatically restart app when critical errors occur.
6+
7+
Process:
8+
1. A critical error occurs
9+
2. HealthCheck receives notification of this via setUnhealthy(msg: Optional[str]) method
10+
3. HealthCheck keeps changes program state to unhealthy, and keeps track of the message
11+
4. A routine call to the healthcheck API occurs
12+
a. API calls healthCheck() which returns current status
13+
b. If program not in healthy state, API returns 500 status code along with messages
14+
c. If program is healthy, API returns 200 OK
15+
'''
16+
class HealthCheck(object):
17+
# Static var
18+
_healthy = True
19+
_message: List[str] = []
20+
21+
# Used to set global healthiness, with optional message
22+
@staticmethod
23+
def setUnhealthy(message: Optional[str] = None) -> None:
24+
HealthCheck._healthy = False
25+
26+
if message:
27+
HealthCheck._message.append(message)
28+
29+
# Returns global healthiness
30+
@staticmethod
31+
def healthCheck() -> Tuple[bool, str]:
32+
return (HealthCheck._healthy, HealthCheck._message)

package-lock.json

Lines changed: 7 additions & 7 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)