You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

70 lines
2.1 KiB

  1. import logging
  2. import time
  3. from concurrent.futures import ThreadPoolExecutor
  4. from django.core.management.base import BaseCommand
  5. from django.db import connection
  6. from django.utils import timezone
  7. from hc.api.models import Check
  8. executor = ThreadPoolExecutor(max_workers=10)
  9. logger = logging.getLogger(__name__)
  10. class Command(BaseCommand):
  11. help = 'Sends UP/DOWN email alerts'
  12. def handle_many(self):
  13. """ Send alerts for many checks simultaneously. """
  14. query = Check.objects.filter(user__isnull=False).select_related("user")
  15. now = timezone.now()
  16. going_down = query.filter(alert_after__lt=now, status="up")
  17. going_up = query.filter(alert_after__gt=now, status="down")
  18. # Don't combine this in one query so Postgres can query using index:
  19. checks = list(going_down.iterator()) + list(going_up.iterator())
  20. if not checks:
  21. return False
  22. futures = [executor.submit(self.handle_one, check) for check in checks]
  23. for future in futures:
  24. future.result()
  25. return True
  26. def handle_one(self, check):
  27. """ Send an alert for a single check.
  28. Return True if an appropriate check was selected and processed.
  29. Return False if no checks need to be processed.
  30. """
  31. # Save the new status. If sendalerts crashes,
  32. # it won't process this check again.
  33. check.status = check.get_status()
  34. check.save()
  35. tmpl = "\nSending alert, status=%s, code=%s\n"
  36. self.stdout.write(tmpl % (check.status, check.code))
  37. errors = check.send_alert()
  38. for ch, error in errors:
  39. self.stdout.write("ERROR: %s %s %s\n" % (ch.kind, ch.value, error))
  40. connection.close()
  41. return True
  42. def handle(self, *args, **options):
  43. self.stdout.write("sendalerts starts up")
  44. ticks = 0
  45. while True:
  46. if self.handle_many():
  47. ticks = 0
  48. else:
  49. ticks += 1
  50. time.sleep(1)
  51. if ticks % 60 == 0:
  52. formatted = timezone.now().isoformat()
  53. self.stdout.write("-- MARK %s --" % formatted)