import time from threading import Thread from django.core.management.base import BaseCommand from django.db import connection from django.utils import timezone from hc.api.models import Check def notify(check_id, stdout): check = Check.objects.get(id=check_id) tmpl = "\nSending alert, status=%s, code=%s\n" stdout.write(tmpl % (check.status, check.code)) errors = check.send_alert() for ch, error in errors: stdout.write("ERROR: %s %s %s\n" % (ch.kind, ch.value, error)) def notify_on_thread(check_id, stdout): t = Thread(target=notify, args=(check_id, stdout)) t.start() class Command(BaseCommand): help = 'Sends UP/DOWN email alerts' owned = Check.objects.filter(user__isnull=False) def add_arguments(self, parser): parser.add_argument( '--no-loop', action='store_false', dest='loop', default=True, help='Do not keep running indefinitely in a 2 second wait loop', ) def handle_one(self): """ Process a single check. """ now = timezone.now() # Look for checks that are going down q = self.owned.filter(alert_after__lt=now, status="up") check = q.first() # If none found, look for checks that are going up if not check: q = self.owned.filter(alert_after__gt=now, status="down") check = q.first() if check is None: return False q = Check.objects.filter(id=check.id, status=check.status) current_status = check.get_status() if check.status == current_status: # Stored status is already up-to-date. Update alert_after # as needed but don't send notifications q.update(alert_after=check.get_alert_after()) return True else: # Atomically update status to the opposite num_updated = q.update(status=current_status) if num_updated == 1: # Send notifications only if status update succeeded # (no other sendalerts process got there first) notify_on_thread(check.id, self.stdout) return True return False def handle(self, *args, **options): if not options["loop"]: x = 0 while self.handle_one(): # returns True when there are more alerts to send. x += 1 return "Sent %d alert(s)" % x self.stdout.write("sendalerts is now running") ticks = 0 while True: while self.handle_one(): ticks = 0 ticks += 1 time.sleep(2) if ticks % 60 == 0: formatted = timezone.now().isoformat() self.stdout.write("-- MARK %s --" % formatted) connection.close()