forked from GithubBackups/healthchecks
Background worker to send notifications
This commit is contained in:
parent
7997879bd8
commit
aad4bd2ffb
@ -2,6 +2,7 @@ from django.contrib import admin
|
|||||||
|
|
||||||
from hc.api.models import Check
|
from hc.api.models import Check
|
||||||
|
|
||||||
|
|
||||||
@admin.register(Check)
|
@admin.register(Check)
|
||||||
class ChecksAdmin(admin.ModelAdmin):
|
class ChecksAdmin(admin.ModelAdmin):
|
||||||
list_display = ("id", "code", "user", "last_ping")
|
list_display = ("id", "code", "user", "last_ping")
|
||||||
|
27
hc/api/management/commands/ensuretriggers.py
Normal file
27
hc/api/management/commands/ensuretriggers.py
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
from django.core.management.base import BaseCommand
|
||||||
|
from django.db import connection
|
||||||
|
|
||||||
|
|
||||||
|
class Command(BaseCommand):
|
||||||
|
help = 'Ensures triggers exist in database'
|
||||||
|
|
||||||
|
def handle(self, *args, **options):
|
||||||
|
cursor = connection.cursor()
|
||||||
|
|
||||||
|
cursor.execute("""
|
||||||
|
CREATE OR REPLACE FUNCTION update_alert_after()
|
||||||
|
RETURNS trigger AS $update_alert_after$
|
||||||
|
BEGIN
|
||||||
|
IF NEW.last_ping IS NOT NULL THEN
|
||||||
|
NEW.alert_after := NEW.last_ping + NEW.timeout;
|
||||||
|
END IF;
|
||||||
|
RETURN NEW;
|
||||||
|
END;
|
||||||
|
$update_alert_after$ LANGUAGE plpgsql;
|
||||||
|
|
||||||
|
DROP TRIGGER IF EXISTS update_alert_after ON api_check;
|
||||||
|
|
||||||
|
CREATE TRIGGER update_alert_after
|
||||||
|
BEFORE INSERT OR UPDATE OF last_ping, timeout ON api_check
|
||||||
|
FOR EACH ROW EXECUTE PROCEDURE update_alert_after();
|
||||||
|
""")
|
45
hc/api/management/commands/sendalerts.py
Normal file
45
hc/api/management/commands/sendalerts.py
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
import sys
|
||||||
|
import time
|
||||||
|
|
||||||
|
from django.core.management.base import BaseCommand
|
||||||
|
from django.utils import timezone
|
||||||
|
|
||||||
|
from hc.api.models import Check
|
||||||
|
from hc.lib.emails import send_status_notification
|
||||||
|
|
||||||
|
|
||||||
|
def _log(message):
|
||||||
|
sys.stdout.write(message)
|
||||||
|
sys.stdout.flush()
|
||||||
|
|
||||||
|
|
||||||
|
class Command(BaseCommand):
|
||||||
|
help = 'Ensures triggers exist in database'
|
||||||
|
|
||||||
|
def handle(self, *args, **options):
|
||||||
|
|
||||||
|
while True:
|
||||||
|
# Gone down?
|
||||||
|
query = Check.objects
|
||||||
|
query = query.filter(alert_after__lt=timezone.now())
|
||||||
|
query = query.filter(enabled=True, status="up")
|
||||||
|
for check in query:
|
||||||
|
check.status = "down"
|
||||||
|
check.save()
|
||||||
|
|
||||||
|
_log("\nSending email about going down for %s\n" % check.code)
|
||||||
|
send_status_notification(check)
|
||||||
|
|
||||||
|
# Gone up?
|
||||||
|
query = Check.objects
|
||||||
|
query = query.filter(alert_after__gt=timezone.now())
|
||||||
|
query = query.filter(enabled=True, status="down")
|
||||||
|
for check in query:
|
||||||
|
check.status = "up"
|
||||||
|
check.save()
|
||||||
|
|
||||||
|
_log("\nSending email about going up for %s\n" % check.code)
|
||||||
|
send_status_notification(check)
|
||||||
|
|
||||||
|
time.sleep(1)
|
||||||
|
_log(".")
|
35
hc/api/migrations/0002_auto_20150616_0732.py
Normal file
35
hc/api/migrations/0002_auto_20150616_0732.py
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
from django.db import models, migrations
|
||||||
|
import datetime
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('api', '0001_initial'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='check',
|
||||||
|
name='alert_after',
|
||||||
|
field=models.DateTimeField(null=True, blank=True),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='check',
|
||||||
|
name='enabled',
|
||||||
|
field=models.BooleanField(default=True),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='check',
|
||||||
|
name='status',
|
||||||
|
field=models.CharField(max_length=6, choices=[('up', 'Up'), ('down', 'Down'), ('new', 'New')], default='new'),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='check',
|
||||||
|
name='timeout',
|
||||||
|
field=models.DurationField(choices=[(datetime.timedelta(0, 300), '5 minutes'), (datetime.timedelta(0, 600), '10 minutes'), (datetime.timedelta(0, 1800), '30 minutes'), (datetime.timedelta(0, 3600), '1 hour'), (datetime.timedelta(0, 7200), '2 hours'), (datetime.timedelta(0, 21600), '6 hours'), (datetime.timedelta(0, 43200), '12 hours'), (datetime.timedelta(1), '1 day'), (datetime.timedelta(2), '2 days'), (datetime.timedelta(7), '1 week'), (datetime.timedelta(14), '2 weeks')], default=datetime.timedelta(1)),
|
||||||
|
),
|
||||||
|
]
|
@ -1,10 +1,31 @@
|
|||||||
|
from datetime import timedelta as td
|
||||||
import uuid
|
import uuid
|
||||||
|
|
||||||
from django.contrib.auth.models import User
|
from django.contrib.auth.models import User
|
||||||
from django.db import models
|
from django.db import models
|
||||||
|
|
||||||
|
STATUSES = (("up", "Up"), ("down", "Down"), ("new", "New"))
|
||||||
|
ONEDAY = td(days=1)
|
||||||
|
DURATIONS = (
|
||||||
|
(td(minutes=5), "5 minutes"),
|
||||||
|
(td(minutes=10), "10 minutes"),
|
||||||
|
(td(minutes=30), "30 minutes"),
|
||||||
|
(td(hours=1), "1 hour"),
|
||||||
|
(td(hours=2), "2 hours"),
|
||||||
|
(td(hours=6), "6 hours"),
|
||||||
|
(td(hours=12), "12 hours"),
|
||||||
|
(ONEDAY, "1 day"),
|
||||||
|
(td(days=2), "2 days"),
|
||||||
|
(td(weeks=1), "1 week"),
|
||||||
|
(td(weeks=2), "2 weeks")
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class Check(models.Model):
|
class Check(models.Model):
|
||||||
code = models.UUIDField(default=uuid.uuid4, editable=False)
|
code = models.UUIDField(default=uuid.uuid4, editable=False)
|
||||||
user = models.ForeignKey(User)
|
user = models.ForeignKey(User)
|
||||||
|
enabled = models.BooleanField(default=True)
|
||||||
|
timeout = models.DurationField(default=ONEDAY)
|
||||||
last_ping = models.DateTimeField(null=True, blank=True)
|
last_ping = models.DateTimeField(null=True, blank=True)
|
||||||
|
alert_after = models.DateTimeField(null=True, blank=True, editable=False)
|
||||||
|
status = models.CharField(max_length=6, choices=STATUSES, default="new")
|
||||||
|
@ -11,6 +11,9 @@ def ping(request, code):
|
|||||||
return HttpResponseBadRequest()
|
return HttpResponseBadRequest()
|
||||||
|
|
||||||
check.last_ping = timezone.now()
|
check.last_ping = timezone.now()
|
||||||
|
if check.status == "new":
|
||||||
|
check.status = "up"
|
||||||
|
|
||||||
check.save()
|
check.save()
|
||||||
|
|
||||||
return HttpResponse()
|
return HttpResponse()
|
||||||
|
15
hc/lib/emails.py
Normal file
15
hc/lib/emails.py
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
from django.core.mail import send_mail
|
||||||
|
|
||||||
|
|
||||||
|
def send_status_notification(check):
|
||||||
|
if check.status == "down":
|
||||||
|
subject = "Alert DOWN"
|
||||||
|
body = "Hi, the check %s has gone down" % check.code
|
||||||
|
elif check.status == "up":
|
||||||
|
subject = "Alert UP"
|
||||||
|
body = "Hi, the check %s has gone up" % check.code
|
||||||
|
else:
|
||||||
|
raise NotImplemented("Unexpected status: %s" % check.status)
|
||||||
|
|
||||||
|
send_mail(subject, body, 'cuu508@gmail.com', [check.user.email],
|
||||||
|
fail_silently=False)
|
@ -85,7 +85,7 @@ DATABASES = {
|
|||||||
'NAME': 'hc',
|
'NAME': 'hc',
|
||||||
'USER': 'hc',
|
'USER': 'hc',
|
||||||
'PASSWORD': '',
|
'PASSWORD': '',
|
||||||
'HOST': '192.168.1.111',
|
'HOST': '192.168.1.112',
|
||||||
'PORT': 5432,
|
'PORT': 5432,
|
||||||
'TEST': {'CHARSET': 'UTF8'}
|
'TEST': {'CHARSET': 'UTF8'}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user